💾 Archived View for paritybit.ca › sysadmin › openbsd-server-details.gmi captured on 2022-07-16 at 13:41:59. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2022-03-01)
-=-=-=-=-=-=-
This article gives a detailed look at the configuration of the services I run. An overview and rationale is available in the following article:
/sysadmin/openbsd-server-overview.gmi
Hetzner supports IPv6, but seemingly only through DHCPv6 or manual configuration. OpenBSD supports IPv6, but only using SLAAC or manual configuration. Therefore, some manual configuration in hostname.vio0 was needed to get IPv6 to work:
dhcp inet6 alias 2a01:4ff:f0:f61::1 64 !route add -inet6 default fe80::1%vio0
Note that Hetzner routes all IPv6 traffic for their cloud instances through fe80::1.
OpenBSD's acme-client is used to request certificates. This is the configuration:
authority letsencrypt { api url "https://acme-v02.api.letsencrypt.org/directory" account key "/etc/acme/letsencrypt-privkey.pem" } domain paritybit.ca { alternative names { www.paritybit.ca, ftp.paritybit.ca, git.paritybit.ca, jbauer.ca } domain key "/etc/ssl/private/paritybit.ca.key" domain full chain certificate "/etc/ssl/paritybit.ca.fullchain.pem" sign with letsencrypt }
Renewing the certificates is handled by /etc/monthly.local, which is run by cron once a month. The output is sent to me in an email.
next_part "Renewing TLS certificate(s):" acme-client -v -F paritybit.ca rcctl reload relayd httpd
A series of jobs are run daily to provide a daily report of basic server status. This is configured in /etc/daily.local:
next_part "Checking for updates:" pkg_add -un 2>&1 next_part "Checking for available system patches:" syspatch -c next_part "Disk usage report:" df -h
All of the domains are served by the following httpd configuration. It also handles the file server since that is done over http.
types { include "/usr/share/misc/mime.types" } # For certificate renewal server "paritybit.ca" { alias "jbauer.ca" alias "ftp.paritybit.ca" alias "git.paritybit.ca" listen on * port 80 location "/.well-known/acme-challenge/*" { root "/acme" request strip 2 } location * { block return 301 "https://$HTTP_HOST$REQUEST_URI" } } # Redirect to WWW server "paritybit.ca" { listen on * tls port 443 tls { certificate "/etc/ssl/paritybit.ca.fullchain.pem" key "/etc/ssl/private/paritybit.ca.key" } hsts { max-age 31536000 preload subdomains } location * { block return 301 "https://www.paritybit.ca$REQUEST_URI" } } server "www.paritybit.ca" { listen on * tls port 443 tls { certificate "/etc/ssl/paritybit.ca.fullchain.pem" key "/etc/ssl/private/paritybit.ca.key" } hsts { max-age 31536000 preload } root "paritybit.ca" location match "/([^%.]+)$" { request rewrite "/%1.html" } } server "jbauer.ca" { listen on * tls port 443 tls { certificate "/etc/ssl/paritybit.ca.fullchain.pem" key "/etc/ssl/private/paritybit.ca.key" } hsts { max-age 31536000 preload subdomains } root "jbauer.ca" } server "ftp.paritybit.ca" { listen on * tls port 443 tls { certificate "/etc/ssl/paritybit.ca.fullchain.pem" key "/etc/ssl/private/paritybit.ca.key" } hsts { max-age 31536000 preload } root "ftp.paritybit.ca" directory auto index location "/paste/" { directory no index } } server "git.paritybit.ca" { listen on * tls port 443 tls { certificate "/etc/ssl/paritybit.ca.fullchain.pem" key "/etc/ssl/private/paritybit.ca.key" } hsts { max-age 31536000 preload } root "git.paritybit.ca" }
vger configuration is extremely simple since it just uses inetd and relayd:
This is the inetd configuration:
127.0.0.1:11965 stream tcp nowait _vger /usr/local/bin/vger vger
And this is the relayd configuration:
log connection tcp protocol "gemini" { tls keypair paritybit.ca } relay "gemini" { listen on egress port 1965 tls protocol "gemini" forward to 127.0.0.1 port 11965 }
/etc/ssl/paritybit.ca.fullchain.pem is symlinked to /etc/ssl/paritybit.ca.crt for relayd.
The content of the gemini server is a git repository that lives in /var/gemini. When updates to the wiki are made, I can simply SSH into the server and run `git pull` to update the content. The _vger group has the ability to read the contents of /var/gemini but only root has permissions for the .git folder so the gemini server can't serve it.
The configuration in inetd for fingerd is:
finger stream tcp nowait _fingerd /usr/libexec/fingerd fingerd -lsmu finger stream tcp6 nowait _fingerd /usr/libexec/fingerd fingerd -lsmu
A user (jbauer) was created with ~/.plan and ~/.project files which are displayed by fingerd.
The static pages generated by stagit are served using the configuration in httpd.conf. Git repositories live in /var/git and updates are pushed there using SSH. The git daemon for cloning using the git:// protocol is invoked using inetd with the following configuration:
git stream tcp nowait _gitdaemon /usr/local/bin/git git daemon --inetd --verbose --base-path=/var/git --export-all /var/git/ git stream tcp6 nowait _gitdaemon /usr/local/bin/git git daemon --inetd --verbose --base-path=/var/git --export-all /var/git/
The following script is run as an hourly cronjob to update the static pages and incorporate recently pushed changes. I may switch to using a post-receive hook instead of a cronjob if this doesn't end up fitting my needs.
#!/bin/sh # Update all individual repos for repo in /var/git/*; do cd /var/www/git.paritybit.ca/"$(basename "$repo" .git)" /usr/local/bin/stagit "$repo" done # Re-generate the index page cd /var/www/git.paritybit.ca /usr/local/bin/stagit-index /var/git/* > index.html
The following script is used to make adding a new repository quicker and easier:
#!/bin/sh printf "Project Name: " read name printf "Project Description: " read desc #printf "Project URL: " #read url url="https://git.sr.ht/~jbauer/$name" #printf "Project Owner: " #read owner owner="Jake Bauer" cd /var/www/git.paritybit.ca mkdir "$name" && cd "$name" ln -s ../favicon.png . ln -s ../logo.png . ln -s ../style.css . cd /var/git git clone --bare "$url" echo "$desc" > "$name".git/description echo "$owner" > "$name".git/owner echo "$url" > "$name".git/url