Basic OpenHTTPd Configuration
OpenHTTPd is a light-weight web server developed by the OpenBSD dev team.
Overview
Pros:
Lean: Small, no plugins
Clean code
Secure: Strict validity checking, privilege separation, strong cryptography
Fast
Easy to configure with good manpage documentation
Docs and references
You'll want to consult the httpd and httpd.conf man pages. Httpd and Relayd Mastery also contains many helpful examples.
Configuring
NOTE: You must replace example.com with your own domain
Copy the example file in ##STARTCODEBLOCK##
/etc/examples/httpd.conf ##ENDCODEBLOCK##
:
$ doas cp /etc/examples/httpd.conf /etc/httpd.conf
Edit ##STARTCODEBLOCK##
/etc/httpd.conf ##ENDCODEBLOCK##
:
server "example.com" {
listen on * port 80
location "/.well-known/acme-challenge/*" {
root "/acme"
request strip 2
}
location * {
block return 302 "https://$HTTP_HOST$REQUEST_URI"
}
}
Replace example.com
to your actual hostname. On other web servers, this might be known as the virtual host.
listen on
tells the web server to listen on all IPs on port 80.
The first location
block in lines 3-6 responds to verification requests according to the ACME protocol. For any request that begins with http://example.com/.well-known/acme-challenge/
, httpd will look for the documents in the new root /acme
. Since openhttpd chroots to /var/www by default, the document root is actually /var/www/acme/
. The directive request strip 2
tells openhttpd to search in /var/www/acme/
and not /var/www/acme/.well-known/acme-challenge/
.
The second location
block in lines 7-9 tell the web server to respond with HTTP 302 for all other requests. An HTTP 302 response forwards the web browser to a new URL address. Any user that connects to your web server using port 80, except for ACME verification, will be forwarded to use TLS on port 443 instead.
This second location
block is suggested by the OpenBSD team, but for accessibility reasons, we recommend removing the second location block.
To allow plaintext requests on port 80, your conf file should now look like this:
server "example.com" {
listen on * port 80
location "/.well-known/acme-challenge/*" {
root "/acme"
request strip 2
}
}
Within the framework of a virtual host, you can also create folders for users of your system:
location match "/sites/([a-z|A-Z|-|_]+)/(.+)" {
request rewrite "/sites/%251/pub/%252"
}
Note: You must have a server block listening on port 80. Do not delete this block or else acme-client will not work. The web server needs the listener block on port 80 for ACME protocol verification.
The block for TLS on port 443 should be commented out until after you have requested TLS certs.
#server "example.com" {
# listen on * tls port 443
# tls {
# certificate "/etc/ssl/example.com.crt"
# key "/etc/ssl/private/example.com.key"
# }
# location "/pub/*" {
# directory auto index
# }
# location "/.well-known/acme-challenge/*" {
# root "/acme"
# request strip 2
# }
#}
Make sure to replace every instance of example.com
with your real hostname, then check that your configuration is valid:
$ doas httpd -n
Starting the server
$ doas rcctl enable httpd
$ doas rcctl start httpd
Testing
Let's test to see if the web server is working on port 80. This test should be run on some other computer besides your web server (your home PC or phone is fine). Let's use telnet:
$ telnet example.com 80
GET /index.html HTTP/1.1
Host: example.com
You should a response similar to the one below:
HTTP/1.0 302 Found
Date: Tue, 23 Feb 2021 14:01:28 GMT
OpenBSD httpd
Connection: close
Content-Type: text/html
Content-Length: 486
Location: https://example.com/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>302 Found</title>
<style type="text/css"><!--
body { background-color: white; color: black; font-family: 'Comic Sans MS', 'Chalkboard SE', 'Comic Neue', sans-serif; }
hr { border: 0; border-bottom: 1px dashed; }
@media (prefers-color-scheme: dark) {
body { background-color: #1E1F21; color: #EEEFF1; }
a { color: #BAD7FF; }
}
--></style>
</head>
<body>
<h1>302 Found</h1>
<hr>
<address>OpenBSD httpd</address>
</body>
</html>
Connection closed by foreign host.
Troubleshooting
If you were unable to establish the connection above, it may be because your firewall is blocking port 80.
You can ensure pf allows incoming http connections by putting this line into /etc/pf.conf:
pass in quick proto tcp to port {http https}
Then, reload the pf rulesets:
$ doas pfctl -f /etc/pf.conf
Adding TLS
Next, you'll want to request an SSL cert using acme-client. Then, you'll want to add TLS to openhttpd.