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
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# $OpenBSD: doas.conf,v 1.1 2016/09/03 11:58:32 pirofti Exp $
# Configuration sample file for doas(1).
# See doas.conf(5) for syntax and examples.
# Non-exhaustive list of variables needed to build release(8) and ports(7)
#permit nopass setenv { \
# FTPMODE PKG_CACHE PKG_PATH SM_PATH SSH_AUTH_SOCK \
# DESTDIR DISTDIR FETCH_CMD FLAVOR GROUP MAKE MAKECONF \
# MULTI_PACKAGES NOMAN OKAY_FILES OWNER PKG_DBDIR \
# PKG_DESTDIR PKG_TMPDIR PORTSDIR RELEASEDIR SHARED_ONLY \
# SUBPACKAGE WRKOBJDIR SUDO_PORT_V1 } :wsrc
# Allow wheel by default
permit 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
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#
# $OpenBSD: acme-client.conf,v 1.4 2020/09/17 09:13:06 florian Exp $
#
authority letsencrypt {
api url "https://acme-v02.api.letsencrypt.org/directory"
account key "/etc/acme/letsencrypt-privkey.pem"
}
authority letsencrypt-staging {
api url "https://acme-staging-v02.api.letsencrypt.org/directory"
account key "/etc/acme/letsencrypt-staging-privkey.pem"
}
domain jkossen.nl {
alternative names { www.jkossen.nl }
domain key "/etc/ssl/private/jkossen.nl.key"
domain full chain certificate "/etc/ssl/jkossen.nl.fullchain.pem"
sign with letsencrypt
}
|
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
:
1
2
3
|
next_part "Refreshing Let's Encrypt certificates:"
acme-client jkossen.nl && rcctl reload relayd
|
Make a symlink to the certificate
TODO: There’s a good reason to do this, but I forgot …
1
2
|
$ cd /etc/ssl
$ doas ln -s jkossen.nl.fullchain.pem jkossen.nl.crt
|
httpd
/etc/httpd/httpd.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
# $OpenBSD: httpd.conf,v 1.22 2020/11/04 10:34:18 denis Exp $
#
# jkossen.nl
#
server "jkossen.nl" {
listen on 127.0.0.1 port 8080
root "/jkossen.nl/public"
log style forwarded
location "/.well-known/acme-challenge/*" {
root "/acme"
request strip 2
}
location match "/posts/(.*)" {
block return 301 "https://$HTTP_HOST/%1"
}
location "/*" {
directory auto index
}
}
server "jkossen.nl" {
alias "www.jkossen.nl"
listen on * port 80
location "/.well-known/acme-challenge/*" {
root "/acme"
request strip 2
}
location "/*" {
block return 301 "https://$HTTP_HOST$REQUEST_URI"
}
}
server "www.jkossen.nl" {
listen on 127.0.0.1 port 8080
log style forwarded
block return 301 "https://jkossen.nl$REQUEST_URI"
}
types {
include "/usr/share/misc/mime.types"
# by default httpd serves ascii, not utf-8
"application"/"rss+xml; charset=utf-8" rss
"text"/"html; charset=utf-8" html htm shtml
"text"/"plain; charset=utf-8" txt
"text"/"xml; charset=utf-8" xml
"text"/"markdown; charset=utf-8" md
}
|
relayd
/etc/relayd/relayd.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
ipv4="192.168.2.10"
ipv6="2a02:a442:243a:1:221:86ff:fe9e:c2c4"
table <local> { 127.0.0.1 }
http protocol https {
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"
tls keypair "jkossen.nl"
match request header append "X-Forwarded-For" value "$REMOTE_ADDR"
match request header append "X-Forwarded-Port" value "$REMOTE_PORT"
match response header set "Referrer-Policy" value "same-origin"
match response header set "X-Frame-Options" value "deny"
match response header set "X-XSS-Protection" value "1; mode=block"
match response header set "X-Content-Type-Options" value "nosniff"
match response header set "Strict-Transport-Security" value "max-age=31536000; includeSubDomains; preload"
match response header set "Content-Security-Policy" value "default-src 'self'"
match response header set "Permissions-Policy" value "accelerometer=()"
match response header set "Cache-Control" value "max-age=86400"
return error
pass
}
relay wwwtls {
listen on $ipv4 port 443 tls
protocol https
forward to <local> port 8080
}
relay www6tls {
listen on $ipv6 port 443 tls
protocol https
forward to <local> port 8080
}
|
E-mail
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
# $OpenBSD: smtpd.conf,v 1.14 2019/11/26 20:14:38 gilles Exp $
# This is the smtpd server system-wide configuration file.
# See smtpd.conf(5) for more information.
table aliases file:/etc/mail/aliases
table secrets file:/etc/mail/secrets
listen on socket
# To accept external mail, replace with: listen on all
#
listen on lo0
action "local_mail" mbox alias <aliases>
action "mailbox" relay host smtps://account1@smtp.mailbox.org auth <secrets>
#action "outbound" relay
# Uncomment the following to accept external mail for domain "example.org"
#
# match from any for domain "example.org" action "local_mail"
match from local for local action "local_mail"
#match mail-from "@jkossen.nl" for any action "mailbox"
match from local for any action "mailbox"
#match from local for any action "outbound"
|
/etc/mail/secrets
Create this file containing your mailbox.org credentials.
1
|
account1 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.
1
2
|
$ doas chown root:_smtpd /etc/mail/secrets
$ doas chmod 0640 /etc/mail/secrets
|