Install snac on OpenBSD (without relayd)

Author and for comments:
Last update: - CC0 1.0 Universal

Snac is a simple, minimalistic ActivityPub instance and runs as a daemon (proxied by a TLS-enabled real httpd server) and provides the basic services for a Fediverse / ActivityPub instance (sharing messages and stuff from/to other systems like Mastodon, Pleroma, Friendica, etc.).Read more about and download snac here: https://codeberg.org/grunfink/snac2

This guide guides the steps to install snac on OpenBSD in a chroot'd environment for extra security Apparently I have no idea how to chroot when running the service with rcctl start snac. If anyone knows how to do it, or if it is even necessary, please send me a comment @antics@mastodon.nu and without the need to setup relayd.

Contents

  1. Web server with tls encryption: httpd and acme-client
    • httpd
    • acme-client
  2. Configure httpd.conf to work with snac (FastCGI)
  3. Install and run snac in a chroot environment
    • Only run snac with the daemon user _snac
    • Download and install snac
    • Setup the chroot environment
    • Run snac in chroot /var/snac
  4. Enable and start the snac daemon service

Web server with tls encryption: httpd and acme-client

httpd

Copy the httpd.conf example config:

cp /etc/examples/httpd.conf /etc/httpd.conf

Edit /etc/httpd.conf and add an optional alias in the tls server section and an optional root to serve your documents and files.It is worth noting that httpd by default runs in chroot /var/www. So the root folder /htdocs/example.com to serve static content from would be in /var/www/htdocs/example.com.

server "example.com" {
        listen on * tls port 443
        alias "www.example.com"
        root "/htdocs/example.com"
        ...

Test the httpd.conf configuration and start the httpd server:

httpd -dvn
rcctl enable httpd
rcctl start httpd

acme-client

If all went (ok) with httpd you continue and copy the acme-client.conf example config:

cp /etc/examples/acme-client.conf /etc/acme-client.conf

Append your domain to /etc/acme-client.conf:

domain example.com {
        alternative names { www.example.com }
        domain key "/etc/ssl/private/example.com.key"
        domain certificate "/etc/ssl/example.com.crt"
        domain full chain certificate "/etc/ssl/example.com.fullchain.pem"
        sign with letsencrypt
}

Create directories:

mkdir -p -m 700 /etc/ssl/private
mkdir -p -m 755 /var/www/acme

Run acme-client to create your keys:

acme-client -v example.com

If all went well you should now have your certificates in /etc/ssl. The certificates needs to be renewed every 72 days. Add the following script to /etc/daily.local to automatically check for renewal:

acme-client example.com
if [ $? -eq 0 ]
then
        rcctl reload httpd
fi

Add an index.html file to /var/www/htdocs/example.com/ and visit example.com in your browser to test if your server are serving request correctly.

We have now set up a basic httpd server with tls encryption.

Configure httpd.conf to work with snac (FastCGI)

The following configuration locations are from the snac(8) man page. Add them to the end of the tls server section in /etc/httpd.conf:

...
	#
	# snac access points
	#
	location "/fedi/*" {
		fastcgi socket tcp "127.0.0.1" 8001
	}
	location "/.well-known/webfinger" {
		fastcgi socket tcp "127.0.0.1" 8001
	}
	location "/oauth/*" {
		fastcgi socket tcp "127.0.0.1" 8001
	}
	location "/api/v1/*" {
		fastcgi socket tcp "127.0.0.1" 8001
	}
	location "/api/v2/*" {
		fastcgi socket tcp "127.0.0.1" 8001
	}
	location "/.well-known/nodeinfo" {
		fastcgi socket tcp "127.0.0.1" 8001
	}
	location "/.well-known/host-meta" {
		fastcgi socket tcp "127.0.0.1" 8001
	}
...

Test the configuration and then reload httpd if all is (ok). Also, start the slowcgi service,

httpd -dvn
rcctl reload httpd
rcctl slowcgi enable
rcctl slowcgi start

Install and run snac in a chroot environment

Under OpenBSD, snac makes use of the enhanced security functions unveil(2) and pledge(2). However, I'm not a good programmer and would in all certainty not recognize a security hole or backdoor in its code. Also, snac is not popular enough to being audited by security folks. So, we cannot trust snac and need some precautions.

Only run snac with the daemon user _snac

Create user _snac with home directory /var/snac:

useradd -g =uid -c "Snac daemon user." -L daemon -s /sbin/nologin -d /var/snac _snac

Download and install snac

Install git. Git also installs curl which is the only dependency for snac. Then clone snac to $HOME/src and build and install snac:

pkg_add git
mkdir $HOME/src
cd $HOME/src
git clone https://codeberg.org/grunfink/snac2.git
cd snac2
make
make install

Setup the chroot environment

Or am I wrong? According to this presentation, chroot is not a security feature. But then if that is the case, why would httpd run in chroot /var/www? The point of this part is to make snac run as user _snac in chroot /var/snac. That means basically, where the user _snac is concerned, the root filesystem / is based in /var/snac. My rationale for that is the fact that we cannot trust sources from outside of the OpenBSD ecosystem and especially from sources that are not well audited.Even with well audited sources theres backdoors like the recent xc attack.

Move the snac binary to /var/snac/bin We will later create a script in place of /usr/local/bin/snac that change user and chroots every time we run the snac binary.

mkdir -p /var/snac/bin
mv /usr/local/bin/snac /var/snac/bin

Check which libraries snac is linked with:

ldd /var/snac/bin/snac
... Name
... /var/snac/bin/snac
... /usr/local/lib/libcurl.so.26.24
... /usr/lib/libcrypto.so.52.0
... /usr/lib/libpthread.so.27.1
... /usr/lib/libc.so.97.1
... /usr/local/lib/libnghttp3.so.2.0
... /usr/local/lib/libngtcp2_crypto_quictls.so.0.0
... /usr/local/lib/libngtcp2.so.3.0
... /usr/lib/libssl.so.55.0
... /usr/local/lib/libnghttp2.so.0.21
... /usr/lib/libz.so.7.0
... /usr/libexec/ld.so

Now, create the same directory structre in /var/snac like so:

mkdir -p /var/snac/usr/local/lib
mkdir -p /var/snac/usr/lib
mkdir -p /var/snac/usr/libexec

And then copy the 11 library files to the corresponding directory in /var/snac

cp /usr/local/lib/libcurl.so.26.2 /var/snac/usr/local/lib
...
cp /usr/libexec/ld.so /var/snac/usr/libexec

Lastly, copy the /var/ld.so.hints file to the chroot environment so that ld.so can find the linked files.

mkdir /var/snac/var/run
cp /var/run/ld.so.hints /var/snac/var/run/ld.so.hints

Optional: if for some reason the shared libraries in /usr/local/lib isn't found in /var/run/ld.so.hints (run ldconfig -r for a list) you can rescan the directories (ldconfig -R /usr/local/lib) and then copy the file as above.

Run snac in chroot /var/snac

First make sure that /var/snac is owned by _snac

chown -R _snac:_snac /var/snac

Execute the snac binary:

chroot -u _snac /var/snac/ /bin/snac
snac 2.51 - A simple, minimalistic ActivityPub instance
Copyright (c) 2022 - 2024 grunfink et al. / MIT license

Commands:

init [{basedir}]                    Initializes the data storage
...

Everything ok! Create a startup script in /usr/local/bin/snac containing the following:

#!/bin/sh

chroot -u _snac /var/snac snac $1 $2

Lets create your instance. The following command will create and populate a data directory for your instance in /var/snac/snac-data.Optionally you could also name it to be more domain specific, i.e. example.com, instead of snac-data. When asked for a prefix: enter /fedi.

snac init snac-data

Now edit /var/snac/snac-data/server.json and set fastcgi to true:

...
    "fastcgi": true,
...

Test run the snac httpd daemon!

snac httpd snac-data
23:19:17 warning: shm object error (No such file or directory)
23:19:17 httpd (FastCGI) start 127.0.0.1:8001 snac/2.51
23:19:17 available (rlimit) fds: 128 (cur) / 1024 (max)
23:19:17 using 4 threads
23:19:17 background thread started

Success! Read the docs and add a new user:

snac adduser snac-data

Enable and start the snac daemon service

Attention! This startup script will not start snac in a chrooted environment. I have yet to figure out how to do that. See here, here and here. However the following script works fine.

Create the rc.d startup script for snac in /etc/rc.d/snac with the following contents:

#!/bin/ksh

daemon_args="httpd snac-data"
daemon_logger="daemon.info"
daemon_execdir="/var/snac"
daemon_user="_snac"
daemon="bin/snac ${daemon_args}"

. /etc/rc.d/rc.subr

pexp="${daemon}.*"
rc_reload=NO
rc_bg=YES

rc_cmd $1

Enable and start the service:

rcctl enable snac
rcctl start snac

You should now have a running instance of snac on your OpenBSD box.