💾 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

View Raw

More Information

⬅️ Previous capture (2022-03-01)

-=-=-=-=-=-=-

OpenBSD Server Details

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

IPv6

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.

TLS Certificates

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

Daily Jobs

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

HTTP Server

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"
}

Gemini Server

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.

Finger Server

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.

Git Server

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