Running OpenBSD's native web server: arranging /etc/httpd.conf, creating virtual hosts, securing with TLS via acme-client, integrating PHP through FastCGI, and using httpd as a reverse proxy to backend applications.

In episode 8 you built an OpenBSD network and learned that this machine can become a router and firewall. Now it's time to run your first public service: a web server. Not nginx, not Apache — OpenBSD has httpd, a lightweight, secure native web server designed specifically in the OpenBSD style.
httpd is a minimalist web server designed for a clear set of tasks: serving static files, TLS termination, FastCGI, and reverse proxying. It's not a replacement for nginx for complex needs — but for most needs, it's more than enough, with a small attack surface.
Like all OpenBSD services, httpd is managed with rcctl:
rcctl enable httpd
rcctl start httpd
rcctl set httpd flags "-n"rcctl enable httpd makes it boot automatically.rcctl start httpd runs it now.rcctl set httpd flags "-n" tests the configuration without actually starting (dry-run) — the same validation habit as pfctl -n.All httpd configuration lives in one file: /etc/httpd.conf. A basic example:
server "default" {
listen on * port 80
root "/htdocs/example.com"
}The server "default" block catches requests that don't match any other server. root sets the document directory, and listen sets the address and port.
Warning
httpd runs as the www user with minimal privileges. Make sure the root directory and the files inside it are readable by that user, for example with chown -R www:www /var/www/htdocs/example.com or by keeping the correct default permissions.
To serve several domains on one server, define multiple server blocks:
server "example.com" {
listen on * port 80
root "/htdocs/example.com"
}
server "blog.example.com" {
listen on * port 80
root "/htdocs/blog.example.com"
}Each block can have its own root, locations, and rules. This is the basic pattern for hosting multiple sites.
For HTTPS, httpd integrates closely with acme-client (details in episode 10). A common configuration pattern:
server "example.com" {
listen on * port 80
location "/.well-known/acme-challenge/*" {
root "/acme"
}
location * {
block return 301 "https://example.com$REQUEST_URI"
}
}
server "example.com" {
listen on * tls port 443
tls {
certificate "/etc/ssl/example.com.crt"
key "/etc/ssl/private/example.com.key"
}
root "/htdocs/example.com"
}The port 80 block directs the acme challenge to the /acme directory, then redirects other requests to HTTPS. The port 443 block loads the certificate and key. You'll produce that certificate in episode 10.
httpd doesn't execute PHP itself; it talks to PHP via FastCGI (for example php-fpm). First, install PHP and enable fpm:
pkg_add php
rcctl enable php_fpm
rcctl start php_fpmThen configure httpd to forward .php requests to fpm:
server "example.com" {
listen on * port 80
root "/htdocs/example.com"
location "/index.php" {
fastcgi socket "/run/php-fpm.sock"
}
}Requests to PHP files are forwarded through a Unix socket to php-fpm, and httpd serves the result. This approach keeps things secure: PHP doesn't run inside httpd, so a bug on one side doesn't automatically expose the other.
httpd can also be a reverse proxy — forwarding requests to backend applications like a Node or Python app:
server "app.example.com" {
listen on * port 80
location "/" {
proxy {
pass to "tcp://127.0.0.1:8080"
}
}
}All requests to app.example.com are forwarded to 127.0.0.1:8080. The reverse proxy + TLS combination makes httpd a secure front door for any application — a pattern you'll reinforce with relayd in episode 16.
Info
If you need httpd features that aren't available — for example complex rewrites or many modules — that's when to consider nginx or relayd. Start with httpd: simple, secure, and often good enough.
Before restarting, always validate the configuration:
httpd -n
rcctl restart httpd
tail -f /var/log/httpd.error.logThe error log is at /var/log/httpd.error.log. The httpd -n + log combination is your main debugging tool. If a request fails, check directory permissions and the rcctl status httpd state.
In episode 9 you ran httpd, OpenBSD's native web server: enabling it with rcctl, arranging /etc/httpd.conf, creating virtual hosts, securing with TLS via acme-client, integrating PHP through FastCGI, and turning it into a reverse proxy.
Key takeaways:
/etc/httpd.conf.server blocks with their own listen, root, and rules.httpd -n before restarting.In the next episode, episode 10, we'll break down TLS and certificates — getting to know LibreSSL as an OpenSSL fork, using the openssl CLI, automating Let's Encrypt certificates with acme-client, and doing TLS termination for httpd and relayd.