I signed up for OpenBSD.amsterdam this weekend. They give you OpenBSD VMs hosted on OpenBSD (how cool is that! I never see the point of having FreeBSD or OpenBSD hosted on KVM running on Linux… might as well just use Linux then!).
I had tried it last year but gave up as the latency was bad (I was in Dubai, and OpenBSD virtualization has packet drops etc). Fast-forward a year and I am in a different country and 2 OpenBSD releases have happened since then… so I figured why not give it a shot again.
I am an OpenBSD fan boy even though I am no expert in it. Back during my Uni days I spent a lot of time on the BSDs and OpenBSD was the one I liked working a lot with. Maybe I am feeding into the hype of it being secure and preferrring security over performance etc., but something about the fact that here is an OS that stands for something and is not afraid to compromise other aspects for it appeals to me. There’s a reason why I started with Linux as opposed to Windows years ago – I liked the philosophy of GNU, open source, and the decentralization that Linux stands for – and from there it was a short step to discovering the BSDs and liking what they stand for. Even on Linux I actively dislike Ubuntu; I can’t put a finger on why, but I just find it not to represent why I started using Linux. I like Debian and Arch Linux (and Manjaro) because I feel like they stand for something and I have similar feeling towards OpenBSD. There’s a simplicity and philosophy about it that appeals to me and even though something like vmd
might not be as performant as KVM or bhyve nor have similar features, I’d still want to use it. You can see it when playing with OpenBSD software like PF
or httpd
or relayd
etc. Even the rc.d
system is opinionated.
Anyways, enough digressing!
I signed up for OpenBSD.amsterdam this weekend, setup FDE on it, and next I wanted to setup Gitea. You’ll recall my mentioning Gitea in a recent post on Gogs and there is a Gitea package on OpenBSD so I went with that.
Install & Configure Gitea
Installing Gitea is straightforward:
1 |
doas pkg_add gitea |
As part of installing it tells you the following:
1 2 3 4 5 6 7 8 9 10 11 |
Install notice: If you are upgrading from gitea-<1.7.1, please note the following changes: * Configuration file location has changed from /etc/gitea/conf/app.ini to /etc/gitea/app.ini * GITEA_CUSTOM directory location has changed from /etc/gitea to /var/gitea/custom * Default ROOT_PATH for logs has changed from /var/gitea/log to /var/log/gitea |
To configure Gitea edit /etc/gitea/app.ini
(as root or doas
). The config cheat sheet has info on what the options mean. I made the following changes in the [Server]
section:
1 2 3 4 5 6 7 8 9 10 11 |
[server] ; The protocol the server listens on. One of 'http', 'https', 'unix' or 'fcgi'. PROTOCOL = fcgi DOMAIN = git.example.com ROOT_URL = https://git.example.com/ ; when STATIC_URL_PREFIX is empty it will follow ROOT_URL STATIC_URL_PREFIX = ; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket. HTTP_ADDR = 127.0.0.1 ; The port to listen on. Leave empty when using a unix socket. HTTP_PORT = 3000 |
This defines your Gitea URLs etc and what protocol it should listen to, what ports & IP address etc. NOTE: Change the URLs to match you configuration.
Gitea has its own web server and you can use that if you want (either directly or put it behind relayd
). I don’t want to, so I set the protocol to be fcgi
to have it listening via the FastCGI protocol on 127.0.0.1:3000 and I will have the web server pass on requests to this IP:port
.
Aside
Actually, when I setup Gitea the first time I didn’t take the route above. I was impatient and just wanted it up and running so I could quickly do the initial config. So what I did is set the protocol to http
instead of fcgi
:
1 2 3 4 5 6 7 8 9 10 11 |
[server] ; The protocol the server listens on. One of 'http', 'https', 'unix' or 'fcgi'. PROTOCOL = http DOMAIN = git.example.com ROOT_URL = https://git.example.com/ ; when STATIC_URL_PREFIX is empty it will follow ROOT_URL STATIC_URL_PREFIX = ; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket. HTTP_ADDR = 127.0.0.1 ; The port to listen on. Leave empty when using a unix socket. HTTP_PORT = 3000 |
The I did the following from my home machine:
1 |
ssh -L 127.0.0.1:3000:127.0.0.1:3000 -N <my openbsd vm> |
This opens and SSH session to the OpenBSD VM, does not open a console (-N
), and forwards 127.0.0.1:3000
on the local machine to 127.0.0.1:3000
on the OpenBSD VM. Thus I could then go to http://127.0.0.1:3000
on my home machine and quickly configure Gitea and play around with it (e.g. create my initial user, disable new registrations etc).
After this I setup httpd
as I detail below and changed the Gitea config to use fcgi
instead.
Setting up the web server and SSL
Now that Gitea is installed and configured and listening on 127.0.0.1:3000
over the FastCGI protocol I want to setup OpenBSD’s web server httpd
to forward requests to this. I also want to setup SSL certs from Let’s Encrypt.
OpenBSD comes with its own ACME client so one doesn’t need something like certbot
(although it too is packaged if the default ACME client isn’t enough; the package name is certbot
). I created /etc/acme-client.conf
with the following:
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 |
# # $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" } authority buypass { api url "https://api.buypass.com/acme/directory" account key "/etc/acme/buypass-privkey.pem" contact "mailto:me@example.com" } authority buypass-test { api url "https://api.test4.buypass.no/acme/directory" account key "/etc/acme/buypass-test-privkey.pem" contact "mailto:me@example.com" } domain git.example.com { alternative names { gitea.example.com } domain key "/etc/ssl/private/git.example.com.key" domain full chain certificate "/etc/ssl/git.example.com.fullchain.pem" sign with letsencrypt |
This is a copy of the example configuration at /etc/examples/acme-client.conf
with the domain
block being what I modified from the default to suit my needs. This file defines the letsencrypt URLs etc. and what the domain
bit defines is how my domain (git.example.com in this case, with an alternate name of gitea.example.com) is to be configured. This section defines which letsencrypt service to use (the production one or the staging one) and where to store the keys etc. We’ll refer to this key locations later.
If you already have httpd
configured you can request for a certificate now. Since I was doing a fresh install I had to configure httpd
first.
To do that I created /etc/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 |
# $OpenBSD: httpd.conf,v 1.20 2018/06/13 15:08:24 reyk Exp $ # default http server to redirect the request scheme "http" to "https" server "git.example.com" { listen on * port 80 # Enable the TCP NODELAY option for this connection. This is recommended to avoid delays in the data stream. tcp nodelay log style forwarded # ACME challenge location "/.well-known/acme-challenge/*" { root "/acme" request strip 2 } location * { block return 302 "https://$HTTP_HOST$REQUEST_URI" } } # default https server server "git.example.com" { listen on * tls port 443 # Signal to the receiving user agent that this host and all sub domains of the host's domain should be considered HSTS hosts. hsts subdomains # Enable the TCP NODELAY option for this connection. This is recommended to avoid delays in the data stream. tcp nodelay log style forwarded # ACME challenge over TLS location "/.well-known/acme-challenge/*" { root "/acme" request strip 2 } tls { certificate "/etc/ssl/git.example.com.fullchain.pem" key "/etc/ssl/private/git.eample.com.key" } location "/*" { fastcgi socket tcp 127.0.0.1 3000 } } |
If you are not starting fresh like me you probably don’t need all of this as you’d have an httpd.conf
file already with existing config. I didn’t, so I copied from /etc/examples/httpd.conf
and modified a bit.
The config file defines a web server listening on port 80 that forwards to port 443. It defines a URL /.well-known/acme-challenge/
which is a well known URL used for ACME challenges. It also sets up some logging options.
The config file also defines a web server listening on port 443 with TLS. This one is similar to the port 80 config but the bits of interest (or addition to your existing config) are these:
1 2 3 4 5 6 7 8 |
tls { certificate "/etc/ssl/git.example.com.fullchain.pem" key "/etc/ssl/private/git.eample.com.key" } location "/*" { fastcgi socket tcp 127.0.0.1 3000 } |
The first block defines the TLS keys and certificate chain – notice the path matches what we defined in acme-client.conf
earlier. And the second block sends all requests to the root path to 127.0.0.1:3000
over FastCGI.
After this restart httpd
if it is already running (or else do doas rcctl -f start httpd
if you are starting it for the first time (the -f
is to force a start as by default /etc/rc.conf
has httpd
disabled) and assuming all went well you now have OpenBSD’s web server up and running.
Don’t go to git.example.com
yet though as it won’t work. The port 80 website will redirect you to the TLS version but we don’t have certs yet.
So request for a certificate (line 1 is the command):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ doas acme-client -v git.example.com acme-client: https://acme-v02.api.letsencrypt.org/directory: directories acme-client: acme-v02.api.letsencrypt.org: DNS: 172.65.32.248 acme-client: dochngreq: https://acme-v02.api.letsencrypt.org/acme/authz-v3/8311450110 acme-client: challenge, token: 3FNcXFGJA9o8Abhz7oG-dbxJqn9fFlXBju9uEzgpTMI, uri: https://acme-v02.api.letsencrypt.org/acme/chall-v3/8311450110/EHMT3A, status: 2 acme-client: dochngreq: https://acme-v02.api.letsencrypt.org/acme/authz-v3/8311552003 acme-client: challenge, token: RAK5HCRkjN6_L5xmt_a9sEdTkZOLB04ZMuoL3vRgJiE, uri: https://acme-v02.api.letsencrypt.org/acme/chall-v3/8311552003/09IovQ, status: 0 acme-client: /var/www/acme/RAK5HCRkjN6_L5xmt_a9sEdTkZOLB04ZMuoL3vRgJiE: created acme-client: https://acme-v02.api.letsencrypt.org/acme/chall-v3/8311552003/09IovQ: challenge acme-client: order.status 1 acme-client: https://acme-v02.api.letsencrypt.org/acme/finalize/101093471/6000021232: certificate acme-client: order.status 3 acme-client: https://acme-v02.api.letsencrypt.org/acme/cert/03612fca44640b5b4429c5710a8b9b274cc8: certificate acme-client: /etc/ssl/git.example.com.fullchain.pem: created |
Assuming you had no errors and the certs were created like above, we are good to go.
Now doas rcctl reload httpd
and browsing to https://git.example.com
should show you the Gitea page.
Final Touches
Assuming all went fine so far, enable httpd so it launches automatically going forward:
1 |
doas rcctl enable httpd |
Also do crontab -e
as root and add the following line:
1 |
~ * * * * acme-client git.example.com && rcctl reload httpd |
This will renew the certificate whenever it is about to expire and reload httpd
.
That’s all, now you can start playing with Gitea.