Hosting a HUGO website with OpenBSD
acme-clienthttpdhugoletsencryptopenbsdopenbsd.amsterdampfrelayd
1231 words - estimated time to read 5 Minutes, 35 Seconds
2024-11-20 17:09 +0100
Intended Audience
This guide is intended for anyone who wants to setup a HUGO website runing on OpenBSD using httpd and relayd.
Document Scope
It is assumed that you have some basic UNIX administration skills and that you have already setup an OpenBSD server to your liking. General setup and administration is outside the scope of this document. Instead, we will focus on setting up OpenBSD’s httpd server, relayd, SSL certificates, and so on.
OpenBSD.Amsterdam - A short plug for my hosting provider
This server is hosted on OpenBSD.Amsterdam. They have really been a pleasure to work with, and they give back to The OpenBSD Foundation and at under 6 euros per month it’s a great value.
OpenBSD Amsterdam - https://openbsd.amsterdam
The OpenBSD Foundation - https://www.openbsdfoundation.org
acme-client, httpd, and relayd
The OpenBSD project has some beautifully designed software and tools. The httpd webserver is intentionally lightweight and doesn’t have too many features. For this reason we will need to use relayd to handle http headers and it is indeed the star of the show.
For now let’s have a look at the official documentation:
httpd manpage - https://man.openbsd.org/httpd.8
httpd.conf manpage - https://man.openbsd.org/httpd.conf.5
relayd manpage - https://man.openbsd.org/relayd.8
relayd.conf manpage - https://man.openbsd.org/relayd.conf.5
acme-client manpage - https://man.openbsd.org/acme-client.1
acme-client.conf manpage - https://man.openbsd.org/acme-client.conf.5
Steps
- Ensure prerequisites have been managed
- OpenBSD installed / configured
- DNS under your control
- CAA records setup
- PF setup for TCP ports 80 and 443
- Install required software ( HUGO )
- Setup httpd, relayd, acme-client
- Generate SSL certificates
- Enable and Start Services
- Create scripts, and cronjob
- Setup HUGO ( NOT COVERED IN THIS DOCUMENT )
Prerequisites - NOT COVERED IN THIS DOCUMENT
Will not be covering setting up DNS in this guide. Please double-check to make sure that you have proper CAA records setup for your domain. These CAA records allow your domain SSL certs to be managed by Let’s Encrypt.
This is what they look like:
example.org. 300 IN CAA 0 issue "letsencrypt.org"
You may check your domain as follows:
# /usr/bin/dig CAA example.org @9.9.9.9
; <<>> dig 9.10.8-P1 <<>> CAA example.org @9.9.9.9
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42490
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;example.org. IN CAA
;; ANSWER SECTION:
example.org. 3600 IN CAA 0 issue "letsencrypt.org"
;; Query time: 12 msec
;; SERVER: 9.9.9.9#53(9.9.9.9)
;; WHEN: Mon Nov 11 11:11:11 CEST 2024
;; MSG SIZE rcvd: 81
#
pf.conf
Also ensure that you have opened up ports on the firewall to your web services. Be mindful of the required order: options, queueing, translation and filtering.
Example entries in the /etc/pf.conf
file:
NET="em0"
### TCP Flags ###
MOD_STATE="flags S/SA modulate state"
pass in log on $NET inet proto tcp from any to $NET_IP port 80 $MOD_STATE
pass in log on $NET inet proto tcp from any to $NET_IP port 443 $MOD_STATE
Required Software
All of the required software is in base except HUGO. Software in OpenBSD’s base is considered highly secure.
hugo–extended
Install HUGO:
/usr/sbin/pkg_add -vi hugo--extended
httpd
Fire up your favorite editor and edit the /etc/httpd.conf
file. Adjust to suit your specific requirements.
types { include "/usr/share/misc/mime.types" }
server "example.org" {
listen on 127.0.0.1 port 8080
location "/.well-known/acme-challenge/*" {
root "/acme"
request strip 2
}
root "/htdocs/example.org/public"
directory auto index
}
### http -> https ###
server "example.org" {
listen on 127.0.0.1 port 8181
block return 301 "https://$HTTP_HOST$REQUEST_URI"
}
### www -> raw domain ###
server "www.example.org" {
listen on 127.0.0.1 port 8080
block drop
}
Save your config.
the httpd daemon is chrooted to /var/www
by default. It is there where we will need to create the document root directory structure.
mkdir -p /var/www/htdocs/example.org
Let’s check our configs to make sure they are sane.
httpd -n
You should see something like: configuration OK
The httpd daemon can be enabled and started as follows:
rcctl enable httpd
rcctl start httpd
relayd
Fire up your favorite editor again and edit the /etc/relayd.conf
file. Adjust to meet your requirements.
EXT4 = "xx.xx.xx.xx" ### <-- INET4 INTERFACE IP GOES HERE
table <LOCAL> { 127.0.0.1 }
log state changes
log connection
http protocol "HTTP_FILTER" {
### DEBUG ###
# Uncomment during testing to return HTTP 403 Forbidden when request is blocked.
# Comment out and relayd will close connection with TCP FIN ( for scanners and crap )
#return error
http headerlen 4096
tls edh
tls keypair "example.org"
tls { no tlsv1.0, no tlsv1.1, ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256" }
match request header set "X-Forwarded-For" value "$REMOTE_ADDR"
match request header set "X-Forwarded-SPort" value "$REMOTE_PORT"
match request header set "X-Forwarded-DPort" value "$SERVER_PORT"
match response header remove "Server" value "*"
match header log "Host"
match header log "X-Forwarded-For"
match header log "User-Agent"
match header log "X-Req-Status"
match url log
match response header set "Referrer-Policy" value "same-origin"
match response header set "Referrer-Policy" value "no-referrer"
match response header set "X-Frame-Options" value "deny"
match response header set "X-XSS-Protection" value "1; mode=block"
match response header set "Content-Security-Policy" value "default-src 'none'; style-src 'self'; img-src 'self'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'"
match response header set "Permissions-Policy: microphone=(), camera=()"
match response header set "Strict-Transport-Security" value "max-age=31536000; includeSubDomains; preload"
match response header set "X-Content-Type-Options" value "nosniff"
match response header set "Cache-Control" value "max-age=86400"
match request tag "BAD_METHOD"
match request method GET tag "OK_METH"
match request method HEAD tag "OK_METH"
block request quick tagged "BAD_METHOD"
match request header "Host" value "example.org" tag "OK_REQ"
match request header "Host" value "www.example.org" tag "OK_REQ"
block request quick tagged "OK_METH" tag "BAD_HH"
#block request quick path "*.php" tag "NO_PHP"
#block request quick path "*.cgi" tag "NO_CGI"
#block request quick path "*.js" tag "NO_JS"
#block request quick path "*.asp" tag "NO_ASP"
block tag "BAD_REQ"
pass request tagged "OK_REQ"
}
relay "IPV4_WEB_HTTPS" {
listen on $EXT4 port 443 tls
protocol "HTTP_FILTER"
forward to <LOCAL> port 8080
}
relay "IPV4_WEB_HTTP" {
listen on $EXT4 port 80
protocol "HTTP_FILTER"
forward to <LOCAL> port 8181
}
The relayd daemon can be enabled and started as follows:
rcctl enable relayd
rcctl start relayd
acme-client
SSL certificates will be managed using OpenBSD’s acme-client
.
Open up the /etc/acme-client.conf
file with your favorite editor and add something like this:
authority letsencrypt {
api url "https://acme-v02.api.letsencrypt.org/directory"
account key "/etc/acme/letsencrypt-privkey.pem"
contact "mailto:your.email@example.org"
}
domain example.org {
domain key "/etc/ssl/private/example.org.key"
domain full chain certificate "/etc/ssl/example.org.fullchain.pem"
sign with letsencrypt
}
Create the directory structure:
mkdir -p -m 700 /etc/ssl/private
mkdir -p -m 755 /var/www/acme
Check the configuration and restart httpd:
# httpd -n
configuration ok
# rcctl restart httpd
httpd(ok)
httpd(ok)
#
Restart relayd as well:
# rcctl restart relayd
relayd(ok)
relayd(ok)
#
Run the acme-client ( this should setup our SSL certificates ):
# acme-client -v example.org
...
acme-client: /etc/ssl/www.example.crt: created
acme-client: /etc/ssl/www.example.pem: created
To renew the certificates automagically create a script /usr/local/sbin/acme.sh
with the following contents:
#!/bin/sh
/usr/sbin/acme-client example.org >/dev/null 2>&1 && /usr/sbin/rcctl reload httpd >/dev/null 2>&1 && /usr/sbin/rcctl reload relayd
Make sure the permissions are correct.
# /bin/chmod 750 /usr/local/sbin/acme.sh
# ls -l /usr/local/sbin/acme.sh
-rwxr-x--- 1 root wheel 116 Jan 1 07:11 acme.sh
#
Add it a cronjob to always keep the SSL certs up-to-date:
###############################################################################
#minute hour mday month wday [flags] command #
###############################################################################
### Keep SSL Certs Up-To-Date ###
0 0 * * * /usr/local/sbin/acme.sh
HUGO
Follow the instructions for the HUGO theme of your choosing.