Micro Selfhosting

I had a little bit of time and motivation on my hands and a Raspberry Pi 4B dormant and unused. So I tried to see how much I can host on it and it’s going surprisingly well. I wanted to have some applications that make kind of sense to be online, that I would use myself, and that I could eventually offer to some of my folks around here. Those services include rss feeds, something to read later, lightweight content hosting, and chatting. After some research and reading I decided on the following setup

Basic Setup

I used the official Raspberry Pi Imager to burn Alpine to a micro sd card. I have a 32GB card that came with the Raspberry Pi. Next I followed the steps outlined here to have a headless setup, but I didn’t do the memory optimization things yet. Next:

ssh root@local.ip.address
setup-alpine
[...]
reboot
ssh user@local.ip.address
setup-apkrepos -c
apk add caddy nano

For the moment I ommit information on how to setup the domain, the dns records, the port forwarding, but that’s all part of the setup as well if you want to access the locally running Pi from the outside. I also chose to the applications running under /srv/* together with their data and configs. That makes it easier for me to create propoer backups later, I hope (but I have to set that up yet).

mkdir -p /srv/readeck
cd /srv/readeck
wget -O readeck https://codeberg.org/readeck/readeck/releases/download/0.21.5/readeck-0.21.5-linux-arm64
chmod a+x readeck
mkdir -p /srv/agate/data
cd /srv/agate
wget https://github.com/mbrubeck/agate/releases/download/v3.3.20/agate.aarch64-unknown-linux-gnu.gz
gunzip agate.aarch64-unknown-linux-gnu.gz
mv agate.aarch64-unknown-linux-gnu agate
chmod +x agate
mkdir -p /srv/yarr/data
apk add yarr
yarr
cd /srv/yarr
cp /root/.config/yarr/storage.db data/storage.db
"user:password" > auth.txt
chmod 600 auth.txt
chown yarr:yarr auth.txt
chown yarr:yarr -R data/
apk add snac
mkdir -p /srv/snac
cd /srv/snac
snac init data
[...]
chown snac:snac -R data/

Config Files

keep.grandmarais.ch {
    reverse_proxy localhost:8081
}

feed.grandmarais.ch {
    reverse_proxy localhost:8083
}

post.grandmarais.ch {
    reverse_proxy / localhost:8084
    reverse_proxy /* localhost:8084
    reverse_proxy /.well-known/webfinger localhost:8084
    reverse_proxy /api/v1/* localhost:8084
    reverse_proxy /api/v2/* localhost:8084
    reverse_proxy /oauth/* localhost:8084
    reverse_proxy /.well-known/nodeinfo localhost:8084
    reverse_proxy /.well-known/host-meta localhost:8084
    reverse_proxy /share localhost:8084
    reverse_proxy /authorize_interaction localhost:8084
}
[main]
log_level = "INFO"
secret_key = "{YOUR-SECRET-KEY}"
data_directory = "data"

[server]
host = "127.0.0.1"
port = 8081
allowed_hosts = ["keep.grandmarais.ch"]
trusted_proxies = ["127.0.0.1"]

[database]
source = "sqlite3:data/db.sqlite3"

Create and Activate Services

These are in place to start the different applications when the Pi boots.

rc-update add caddy default
touch /etc/init.d/readeck
chmod +x /etc/init.d/readeck
rc-update add readeck default
nano /etc/init.d/readeck
#!/sbin/openrc-run
name="Readeck"
description="Read-it-later service"
directory="/srv/readeck"
command="/srv/readeck/readeck"
command_args="serve -config /srv/readeck/config.toml"
command_background=true
pidfile="/run/readeck.pid"
touch /etc/init.d/agate
chmod +x /etc/init.d/agate
rc-update add agate default
nano /etc/init.d/agate
#!/sbin/openrc-run
name="agate"
description="agate gemini server"
directory="/srv/agate"
command="/srv/agate/agate"
command_args="--content data/ --addr [::]:1965 --addr 0.0.0.0:1965 --hostname gems.grandmarais.ch --lang en-US"
command_background=true
pidfile="/run/agate.pid"
rc-update add yarr default
nano /etc/init.d/yarr
[...]
command_args="-auth-file /srv/yarr/auth.txt -db /srv/yarr/data/storage.db -addr 127.0.0.1:8083"
[...]
rc-update add snac default
nano /etc/init.d/snac
[...]
: ${SNAC_DATA:="/srv/snac/data"}
[...]