Web server setup with OpenBSD
As a hobby, I host my website on my own server. It’s currently running the OpenBSD operating system. OpenBSD comes with batteries included. Among other things, it comes with a web (http / https) server, a transparent proxy and load balancer, a mail (SMTP) server, the OpenSSH shell server and a packet filter (“firewall”). Everything you need to host your website yourself. All nicely integrated. All for free.
OpenBSD is very consistent, lightweight and probably the most secure functional operating system available. Maintenance is a breeze, so it’s great for serving purposes.
Want to setup your own OpenBSD box? Then it can be helpful to see how other people have configured their machines.
Below you can find most of my configuration files.
By the way, I owe credit to Derek Sivers. While setting up OpenBSD and searching information about it I came across his website. He has quite some sensible things to say that rhyme with things I want to accomplish.
You might want to read his Tech Independence tutorial on how to set up your own server.
Doas
Doas is a replacement for sudo
developed by the OpenBSD
developers. It allows you to execute commands as another user. I’ve set
it up to allow users in the wheel
group to execute any
command as root.
/etc/doas.conf
1# $OpenBSD: doas.conf,v 1.1 2016/09/03 11:58:32 pirofti Exp $
2# Configuration sample file for doas(1).
3# See doas.conf(5) for syntax and examples.
4
5# Non-exhaustive list of variables needed to build release(8) and ports(7)
6#permit nopass setenv { \
7# FTPMODE PKG_CACHE PKG_PATH SM_PATH SSH_AUTH_SOCK \
8# DESTDIR DISTDIR FETCH_CMD FLAVOR GROUP MAKE MAKECONF \
9# MULTI_PACKAGES NOMAN OKAY_FILES OWNER PKG_DBDIR \
10# PKG_DESTDIR PKG_TMPDIR PORTSDIR RELEASEDIR SHARED_ONLY \
11# SUBPACKAGE WRKOBJDIR SUDO_PORT_V1 } :wsrc
12
13# Allow wheel by default
14permit persist keepenv :wheel
Web
OpenBSD includes acme-client
which I use to create and
manage my SSL certificates from Let’s Encrypt. ACME stands for “Automatic Certificate Management
Environment”.
For the Web server I use OpenBSD’s included httpd. It works fine for serving plain html. For more complex needs it supports the FastCGI protocol.
I also use relayd
as a proxy server. It allows me to
(among other things) add CSP (Content Security Policy).
acme-client
Certificate configuration
/etc/acme-client.conf
:
1#
2# $OpenBSD: acme-client.conf,v 1.4 2020/09/17 09:13:06 florian Exp $
3#
4authority letsencrypt {
5 api url "https://acme-v02.api.letsencrypt.org/directory"
6 account key "/etc/acme/letsencrypt-privkey.pem"
7}
8
9authority letsencrypt-staging {
10 api url "https://acme-staging-v02.api.letsencrypt.org/directory"
11 account key "/etc/acme/letsencrypt-staging-privkey.pem"
12}
13
14domain jkossen.nl {
15 alternative names { www.jkossen.nl }
16 domain key "/etc/ssl/private/jkossen.nl.key"
17 domain full chain certificate "/etc/ssl/jkossen.nl.fullchain.pem"
18 sign with letsencrypt
19}
To request your certificate, first set up httpd
and
relayd
as below since it serves the acme challenge, then
execute:
1$ doas acme-client -v jkossen.nl
Check certificates daily
/etc/daily.local
:
1next_part "Refreshing Let's Encrypt certificates:"
2
3acme-client jkossen.nl && rcctl reload relayd
Make a symlink to the certificate
TODO: There’s a good reason to do this, but I forgot …
httpd
/etc/httpd/httpd.conf
1# $OpenBSD: httpd.conf,v 1.22 2020/11/04 10:34:18 denis Exp $
2
3#
4# jkossen.nl
5#
6server "jkossen.nl" {
7 listen on 127.0.0.1 port 8080
8 root "/jkossen.nl/public"
9 log style forwarded
10 location "/.well-known/acme-challenge/*" {
11 root "/acme"
12 request strip 2
13 }
14 location match "/posts/(.*)" {
15 block return 301 "https://$HTTP_HOST/%1"
16 }
17 location "/*" {
18 directory auto index
19 }
20}
21
22server "jkossen.nl" {
23 alias "www.jkossen.nl"
24 listen on * port 80
25 location "/.well-known/acme-challenge/*" {
26 root "/acme"
27 request strip 2
28 }
29 location "/*" {
30 block return 301 "https://$HTTP_HOST$REQUEST_URI"
31 }
32}
33
34server "www.jkossen.nl" {
35 listen on 127.0.0.1 port 8080
36 log style forwarded
37 block return 301 "https://jkossen.nl$REQUEST_URI"
38}
39
40types {
41 include "/usr/share/misc/mime.types"
42
43 # by default httpd serves ascii, not utf-8
44 "application"/"rss+xml; charset=utf-8" rss
45 "text"/"html; charset=utf-8" html htm shtml
46 "text"/"plain; charset=utf-8" txt
47 "text"/"xml; charset=utf-8" xml
48 "text"/"markdown; charset=utf-8" md
49}
relayd
/etc/relayd/relayd.conf
1ipv4="192.168.2.10"
2ipv6="2a02:a442:243a:1:221:86ff:fe9e:c2c4"
3
4table <local> { 127.0.0.1 }
5
6http protocol https {
7 tls ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"
8
9 tls keypair "jkossen.nl"
10
11 match request header append "X-Forwarded-For" value "$REMOTE_ADDR"
12 match request header append "X-Forwarded-Port" value "$REMOTE_PORT"
13
14 match response header set "Referrer-Policy" value "same-origin"
15 match response header set "X-Frame-Options" value "deny"
16 match response header set "X-XSS-Protection" value "1; mode=block"
17 match response header set "X-Content-Type-Options" value "nosniff"
18 match response header set "Strict-Transport-Security" value "max-age=31536000; includeSubDomains; preload"
19 match response header set "Content-Security-Policy" value "default-src 'self'"
20 match response header set "Permissions-Policy" value "accelerometer=()"
21 match response header set "Cache-Control" value "max-age=86400"
22
23 return error
24 pass
25}
26
27relay wwwtls {
28 listen on $ipv4 port 443 tls
29 protocol https
30 forward to <local> port 8080
31}
32
33relay www6tls {
34 listen on $ipv6 port 443 tls
35 protocol https
36 forward to <local> port 8080
37}
I use mailbox.org for my e-mail needs, and have OpenBSD set up to relay mail through them.
You don’t need to install packages. OpenBSD comes with OpenSMTPD installed.
/etc/mail/smtpd.conf
1# $OpenBSD: smtpd.conf,v 1.14 2019/11/26 20:14:38 gilles Exp $
2
3# This is the smtpd server system-wide configuration file.
4# See smtpd.conf(5) for more information.
5
6table aliases file:/etc/mail/aliases
7table secrets file:/etc/mail/secrets
8
9listen on socket
10
11# To accept external mail, replace with: listen on all
12#
13listen on lo0
14
15action "local_mail" mbox alias <aliases>
16action "mailbox" relay host smtps://account1@smtp.mailbox.org auth <secrets>
17#action "outbound" relay
18
19# Uncomment the following to accept external mail for domain "example.org"
20#
21# match from any for domain "example.org" action "local_mail"
22match from local for local action "local_mail"
23#match mail-from "@jkossen.nl" for any action "mailbox"
24match from local for any action "mailbox"
25#match from local for any action "outbound"
/etc/mail/secrets
Create this file containing your mailbox.org credentials.
1account1 me@mydomain.com:myPa$$w0rd
Replace me@mydomain.com
with your mailbox.org user name
(which should be your full e-mail address). Replace
myPa$$w0rd
with your password.
NOTE: account1
in
smtps://account1@smtp.mailbox.org
in
smtpd.conf
refers to account1
in
/etc/mail/secrets
.
If you change it, change both.
Set permissions
Make sure only root and smtpd can read your account information and password.