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
- Alpine Linux
- All binaries if possible, as I wanted to avoid overhead that systems like docker bring with
- yarr for rss, readeck for the read later service, agate as a gemini server, snac2 for some activitpub fun (say mastodon), and caddy to act as a reverse proxy that enables easy tls handling
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:
- Finish Alpine setup
- SSH into the Pi
- Activate the community repositories
- Install nano and caddy
ssh root@local.ip.address
setup-alpine
[...]
reboot
ssh user@local.ip.address
setup-apkrepos -c
apk add caddy nanoFor 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).
- Install Readeck, the read later service
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- Installe Agate, the gemini server
- The gemtext files live under
/srv/agate/data
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- Install yarr, the rss reader with Fever API
- I choose an easy rss server without capabilities for different users. We just have to share the feeds we read, which is cool I guess.
mkdir -p /srv/yarr/data
apk add yarr- I had to start yarr once and then copy the database
- Also created an auth file with a user:password pair
- Then changed ownership to yarr:yarr since the yarr service config uses it’s own user and group (should maybe do for readeck and agate as well)
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/- Installed snac2, an awesome ActivityPub server
- Again, had to change owner and group of the data folder
apk add snac
mkdir -p /srv/snac
cd /srv/snac
snac init data
[...]
chown snac:snac -R data/Don’t forget to setup fediverse users
After that I had to fiddle a bit with some config for caddy and readeck
Create (where necessary) and activate the services so the applications run automatic when booting the Pi
Start said services and/or reboot
Config Files
- The caddy config file lives under
/etc/caddy/Caddyfileand looks like this
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
}This config essentially allows to be aware of incoming requests and route them to the correct application. agate doesn’t need to be handled by caddy since it runs on port 1965 and brings its own tls certificate.
The Readeck config is at
/srv/readeck/config.tomland had to be slightly adjusted to run on another port and is aware under which URL it is running.
[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"- snac2 creates it’s own config stuff when running
init, but I choose to run it under port 8084
Create and Activate Services
These are in place to start the different applications when the Pi boots.
- caddy, just add the application to the default thing
rc-update add caddy default- readeck needs a service entry to be created, after which we can add it to the default service startup as well
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"- agate works like readeck
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"- yarr already has a service entry. I only had to add the
command_args, in order to use my own data folder.
rc-update add yarr default
nano /etc/init.d/yarr- Just add it after the
commands=...entry
[...]
command_args="-auth-file /srv/yarr/auth.txt -db /srv/yarr/data/storage.db -addr 127.0.0.1:8083"
[...]- snac2 is similar to yarr, and I just changed the data folder
rc-update add snac default
nano /etc/init.d/snac[...]
: ${SNAC_DATA:="/srv/snac/data"}
[...]