TLS for OpenHTTPd
This guide shows you how to enable TLS? for OpenHTTPd. It assumes you have already set up plaintext OpenHTTPd listening on port 80, and you have successfully requested TLS certs using acme-client.
Docs and references
Consult httpd, httpd.conf, acme-client, and acme-client.conf man pages. Httpd and Relayd Mastery also contains many helpful examples.
Configuring
In the previous guide, we used /etc/examples/httpd.conf as a template for /etc/httpd.conf:
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" } } 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 } }
NOTE: You must replace example.com with your own domain
We commented out the second block in the basic OpenHTTPd guide because we did not yet request TLS certs yet. Now that we have certs from acme-client, we uncomment the second block.
TLS Block Explained
Here is a line-by-line description of the TLS block:
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 } }
Lines 2-6 tells the web server to listen on all IPs on port 443. As a result, we need a tls block to specify which SSL certs to use. Again, it is necessary to replace example.com
with your actual hostname.
Lines 7-9 say that, for any request beginning with https://example.com/pub/, the web server should automatically show a directory listing. Normally this is not a good idea for security reasons, but for a public folder, it should be fine.
In a normal production server, if OpenHTTPd is already running, reloading is best to avoid downtime:
$ doas rcctl reload httpd
For your first test however, you will want to stop OpenHTTPd?:
$ doas rcctl stop httpd
Then, check that your configuration is valid:
$ doas httpd -n
Once you are certain it has been configured properly, you can start the server:
$ doas rcctl start httpd
Testing
To test if your web server has a working SSL cert, use openssl:
$ openssl s_client -connect example.com:443
NOTE: You must replace example.com
with your actual hostname.
You should see the correct SSL subject and issuer:
$ openssl s_client -connect example.org:443 CONNECTED(00000003) depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3 verify return:1 depth=1 C = US, O = Let's Encrypt, CN = R3 verify return:1 depth=0 CN = example.com verify return:1 depth=0 CN = example.com verify return:1 write W BLOCK --- Certificate chain 0 s:/CN=example.com i:/C=US/O=Let's Encrypt/CN=R3 1 s:/C=US/O=Let's Encrypt/CN=R3 i:/O=Digital Signature Trust Co./CN=DST Root CA X3 --- Server certificate -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- subject=/CN=example.com issuer=/C=US/O=Let's Encrypt/CN=R3 --- No client certificate CA names sent Server Temp Key: ECDH, X25519, 253 bits --- SSL handshake has read 3730 bytes and written 367 bytes --- New, TLSv1/SSLv3, Cipher is AEAD-AES256-GCM-SHA384 Server public key is 4096 bit Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated SSL-Session: Protocol : TLSv1.3 Cipher : AEAD-AES256-GCM-SHA384 Session-ID: Session-ID-ctx: Master-Key: Start Time: 1614233943 Timeout : 7200 (sec) Verify return code: 0 (ok) ---
You can also visit the website using your web browser. Open your web browser to https://example.com
. If you see an error such as 403 Forbidden, it may mean you have not set up a website.
Look for the SSL padlock in the address bar (which indicates your site is secure), then view more information about the certificate:
Attach:ssl-cert.png
Automation
Let's Encrypt TLS certs expire after 90 days. As a result, you are highly encouraged to automate the renewal of TLS certs. Otherwise, once a cert expires, your users may no longer be able to visit your site.
We can automate the request process using crontab.
$ doas crontab -e
Add this line at the bottom:
~ ~ * * * acme-client example.com >> /var/log/acme-client.log 2>&1 && sleep 300 && rcctl reload httpd
This cronjob will check the certificate once each day at a random time to see if it needs to be renewed. If it does, it will renew the cert, wait 300 seconds, then reload openhttpd to use it.
Troubleshooting
If you were unable to establish the connection above, it may be because your firewall is blocking port 443.
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