Dave's OpenBSD Blog #8: OpenBSD httpd (Rewrites/Redirects, PHP)

Page created: 2024-11-16
Updated: 2025-05-24

Go back to my OpenBSD page for more entries.

Well, this entry started off with more advanced httpd.conf exploration, but that grew to the point where I realized it would be better as a stand-alone reference page. So here’s that:

OpenBSD httpd Rewrite and Redirects with Examples

Moving on, after some soul-searching, I decided to trust my gut and just go ahead and use PHP for my project. I’ll defend PHP, especially after version 8, to anyone. It may not be pretty, but it’s extremely productive and versatile. It’s plenty performant for all but the most extreme uses. And it has so much useful Web functionality built right in. On top of that, it doesn’t need a template language add-on because it is a template language.

Well, enough justifying my choice. Here’s me installing PHP and setting it up on OpenBSD 7.6:

Installing PHP 8.3

The php package contains the FastCGI implementation PHP-FPM:

$ pkg_info php
...
This main package includes the most common SAPIs: cli (the stand-alone
binary which can be used for command-line scripts) and fpm (the "FastCGI
process manager" which manages a pool of separate processes that accept
web-server requests over the FastCGI protocol).
...

So this should install PHP ready to go with the httpd server:

OpenBSD 7.6 (GENERIC) #332: Mon Sep 30 08:45:17 MDT 2024
...
willard2$ doas pkg_add php
quirks-7.50 signed on 2024-11-22T16:48:05Z
https://cdn.openbsd.org/pub/OpenBSD/7.6/packages-stable/amd64/php-8.1.30.tgz: Retrying https://cdn.openbsd.org/pub/OpenBSD/7.6/packages-stable/amd64/php-8.1.30.tgz
Ambiguous: choose package for php
a	0: <None>
	1: php-8.1.31
	2: php-8.2.26
	3: php-8.3.14
Your choice: 3
php-8.3.14:argon2-20190702p0: ok
php-8.3.14:xz-5.6.2: ok
php-8.3.14:libxml-2.13.3p0: ok
php-8.3.14:oniguruma-6.9.9: ok
php-8.3.14:bzip2-1.0.8p0: ok
php-8.3.14:pcre2-10.37p2: ok
php-8.3.14:femail-1.0p1: ok
php-8.3.14:femail-chroot-1.0p3: ok
php-8.3.14:capstone-5.0: ok
php-8.3.14: ok
Running tags: ok
The following new rcscripts were installed: /etc/rc.d/php83_fpm
See rcctl(8) for details.
New and changed readme(s):
	/usr/local/share/doc/pkg-readmes/femail-chroot
	/usr/local/share/doc/pkg-readmes/php-8.3

Oh, and I also want php-pdo_sqlite, which also installs dependency sqlite3 because that’s the database I plan on using for my specific project. I don’t need this right away, but will soon:

willard2$ php-pdo_sqlite
php-pdo_sqlite-8.3.14:sqlite3-3.44.2: ok
php-pdo_sqlite-8.3.14: ok

For the rest, I found this guide handy:

Enable and start php-fpm:

willard2$ doas rcctl enable php83_fpm
willard2$ doas rcctl start php83_fpm
php83_fpm(ok)

And when a .php file is requested, we’ll run the request through the PHP FastCGI socket:

server "*.ratfactor.com" {
        listen on * port 80

        # shell glob-style match filename:
        location "*.php" {
                fastcgi socket "/run/php-fpm.sock"
        }
}

And then a simple test PHP file:

willard2$ cat /var/www/htdocs/test.php
<html>
<body>
	<?php
	echo 6 + 6;
	?>
</body>
</html>

Does it work? I go to willard.ratfactor.com/test.php and…​

12

Yay!!!

SQLite3 + PHP + PDO

I want my database to be stored outside of the htdocs/ directory so someone can’t just download the whole thing by name.

Here’s my new directory:

willard2$ cd /var/www/
willard2$ doas mkdir var
willard2$ doas chown www:www var
willard2$ doas chmod g+w var

The idea is that since httpd runs chrooted into /var/www, this will appear as /var to my PHP code.

Note that previously I made myself a member of the www group so I can write my website content as my regular user.

I’ll make a little test db:

willard2$ sqlite3 foo.db
SQLite version 3.44.2 2023-11-24 11:41:44
Enter ".help" for usage hints.
sqlite> create table foo(key, value);
sqlite> insert into foo values ('author','JRR Tolkien');

And have my test page attempt to query the database:

willard2$ cat htdocs/test.php
<html>
<body>
<?php

$db = new PDO('sqlite:/var/foo.db');
$result = $db->query('select * from foo');

foreach($result as $row){
	echo "{$row[0]}: {$row[1]}<br>";
}

?>
</body>
</html>

Alas, the page came up blank and an error was logged:

willard2$ tail /var/www/logs/error.log
PHP message: PHP Fatal error:  Uncaught Error: Call to undefined function php_info() in /htdocs/test.php:4
Stack trace:
#0 {main}
  thrown in /htdocs/test.php on line 4
PHP message: PHP Fatal error:  Uncaught PDOException: could not find driver in /htdocs/test.php:5
Stack trace:
#0 /htdocs/test.php(5): PDO->__construct()
#1 {main}
  thrown in /htdocs/test.php on line 5

Okay, so I’m pretty sure I need to enable the SQLite PDO driver.

Here’s the PHP-related configuration in /etc:

/etc
|-- php-8.3/
|-- php-8.3.ini
|-- php-8.3.sample/
|   |-- opcache.ini
|   `-- pdo_sqlite.ini
|-- php-fpm.conf
|-- php-fpm.d

And the sample pdo_sqlite.ini file contains a single line:

extension=pdo_sqlite.so

Evidently, the intended way to add extensions is to copy the sample into the non-sample directory. Then I restart PHP-FPM to allow the PHP processes to pick up the changes:

willard2$ cd /etc
willard2$ doas cp php-8.3.sample/pdo_sqlite.ini php-8.3/
willard2$ doas rcctl restart php83_fpm
php83_fpm(ok)
php83_fpm(ok)

And refresh the page in the browser…​

 author: JRR Tolkien

Yes!

PHP File Upload Size Limits

There are three settings:

The first two are /etc/php-8.3.ini (where 8.3 might be a newer version when you’re reading this.):

...
post_max_size = 8M
...
upload_max_filesize = 8M

Then restart php-fpm with:

willard2$ doas rcctl restart php83_fpm
php83_fpm(ok)

By the way, the easiest way to check these settings (and make sure your changes were made correctly by refreshing after reloading php-fpm) is to temporarily make a PHP page containing just this line:

<?php phpinfo();

The third setting is the OpenBSD httpd server maximum request body in /etc/httpd.conf. This is a roughly 8Mb limit in a location block:

server "foo.ratfactor.com" {
    ...
    connection max request body 8388608
    ...
}

Note that the quantity of the max request body is in bytes! The man page for httpd.conf explains that the default is a limit of 1Mb, so if your uploads are mysteriously failing with the server simply disconnecting, this is probably the reason.

And, of course, don’t forget to reload httpd to take those changes too!