Interested in using HAProxy instead of OpenBSD’s relayd? Then keep reading!
HAProxy requires your acme-generated CRT and KEY files to be combined into a single PEM.
First create the directory we will need to contain the files be plan to generate:
doas mkdir /etc/ssl/certs
doas chmod 644 /etc/ssl/certs
Then create a separate script (this will be helpful if you plan to host multiple sites on a single server). Name it something like renew_certs.sh
and save it under a local directory (ie. /home/username/scripts
):
#!/bin/sh
DOMAINS="httpd.rocks example1.com example2.com example3.com"
CERTS_OUTPUT_DIR="/etc/ssl/certs"
echo "Checking certificates for each domain..."
# Loop through each domain and run acme-client only if renewal is needed
for DOMAIN in $DOMAINS; do
if ! doas acme-client -n "$DOMAIN"; then
echo "Certificate for $DOMAIN needs renewal, running acme-client..."
doas acme-client "$DOMAIN" || exit 1
else
echo "Certificate for $DOMAIN is still valid, skipping renewal."
fi
done
# Combine .fullchain.pem and .key into a single .pem file in /etc/ssl/certs
echo "Combining .fullchain.pem and .key files for each domain..."
for DOMAIN in $DOMAINS; do
CERT="/etc/ssl/$DOMAIN.cert"
KEY="/etc/ssl/private/$DOMAIN.key"
COMBINED_PEM="$CERTS_OUTPUT_DIR/$DOMAIN.pem"
if [ -f "$CERT" ] && [ -f "$KEY" ]; then
doas sh -c "cat '$CERT' '$KEY' > '$COMBINED_PEM'"
doas chmod 644 "$COMBINED_PEM"
echo "Combined $CERT and $KEY into $COMBINED_PEM"
else
echo "Missing $CERT or $KEY for $DOMAIN, skipping."
fi
done
# Reload httpd after updating certificates
echo "Reloading httpd..."
doas rcctl reload httpd
echo "httpd reloaded successfully."
For reference I have included multiple domains if you decide to host several websites through one server. Remove these if you only plan to host a single domain.
Set executable permissions:
doas chmod +x /path/to/renew_certs.sh
Then setup the following cronjob
by running crontab -e
and entering in:
0 0 * * * doas -u <user> /path/to/renew_certs.sh
Replace <user>
with your username.
This will check if you need to renew certificates every day at midnight (server time). If new certs are needed, it will properly combine the generated crt
and key
files into a single <project-name>.pem
file under the shared directory /etc/ssl/certs
.
Since we haven’t run this script yet, we should execute it for building the initial pem
files required for HAProxy:
doas sh /path/to/renew_certs.sh
First, install the package:
doas pkg_add haproxy
Now configure the core /etc/haproxy/haproxy.cfg
(take note of the extension! OpenBSD uses cfg
rather than the standard conf
for HAProxy) and add the following to the existing file:
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend http_in
bind *:80
redirect scheme https if !{ ssl_fc }
default_backend main_backend
frontend https_in
bind *:443 ssl crt /etc/ssl/certs/
default_backend main_backend
# Backend to httpd with security headers, no TLS
backend main_backend
http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains"
http-response set-header X-Content-Type-Options "nosniff"
http-response set-header X-Frame-Options "DENY"
http-response set-header X-XSS-Protection "1; mode=block"
http-response set-header Content-Security-Policy "script-src 'self'"
http-response set-header Referrer-Policy "no-referrer"
http-response set-header Permissions-Policy "microphone=()"
server local_httpd 127.0.0.1:8080
The haproxy.cfg
in a nutshell:
frontend http_in
:main_backend
to set security headersfrontend https_in
:main_backend
to set security headersbackend main_backend
:Important: Take note of the line:
bind *:443 ssl crt /etc/ssl/certs/
This tells HAProxy to dynamically scan a directory containing our certificates. We set this up previously with our automated renew_certs.sh
script.
This is handy if you decide to host multiple sites on a single server. Otherwise, you would have to edit and reload your HAProxy config everytime you setup a new website.
Once that’s complete, test that everything is working, and if so, enable and start HAProxy:
doas haproxy -c -f /etc/haproxy/haproxy.cfg
doas rcctl enable haproxy
doas rcctl start haproxy
Return to the core /etc/httpd.conf
file and add the following redirect block to your www
server section:
server "www.httpd.rocks" {
listen on * port 80
root "/htdocs/httpd.rocks"
block return 301 "https://httpd.rocks$REQUEST_URI"
location "/.well-known/acme-challenge/*" {
root "/acme"
request strip 2
}
}
Restart your httpd server again:
rcctl restart httpd
Now check out your website! Everything should work as intended.
You should have valid TLS, your standard HTTP request should forward to HTTPS, all www
requests should forward to non-www
, and your security headers should score an A+.
That’s it!
I’m far from an OpenBSD expert! Please help improve this project!