Firefish is a fork of Misskey, which is a fork of Calckey, which is a fediverse microblogging app, similar to Mastodon. Since apparently I haven't learned my lesson, let's try self-hosting a firefish instance, and see how that goes (spoiler alert: predictably awful). Interacting with social media in any form is hazardous to your mental health. The Fediverse is not immune to the excesses of device-mediated groupthink, nor is it some mythical bastion of proper discourse. However, the current crop of fediverse microblogging platforms have their fair share of moderation tools, so if you gain experience from reading this post, you'll soon be making a hobby of pasting keywords-to-mute into your moderation forms.
Follow this path if you, like me, are an aspiring misanthrope who loves frustration.
The General Idea
We'll use a Raspberry Pi 5 single-board ARM computer, with 8gb of RAM. Four GB may be enough, depending on your use. I observed by rough average 1GB of RAM usage over the first few days. Depending on how many instances you're federated with, if you have relays connected, and how many followers you have on your instance, YMMV. Once we've procured our hardware, onto which we'll install Gentoo Linux and the downstream RPI kernel. We'll use Podman, because why use docker when you can use podman? In other words we're going to have a containerized single-instance app which should be enough for s's and g's, but might fail horribly down the line. But as my accountant always says "you should be so lucky to pay lots of taxes". If you find your puny little SBC getting pounded by overwhelming internet popularity, follow-on configurations using k8s and co. are searchable on GitHub.
OS Installation
Getting gentoo fully loaded onto a raspberry pi is beyond the scope of this blog post,but the gentoo wiki's installation guide is excellent. For the initiated, it can be helpful to start with the stage-3 systemd tarball, and make sure to compile in all the podman dependencies to the downstream kernel.
Since we want Podman 5 for improved health check support in systemd units, accept the arm64
keyword in /etc/make.conf
:
ACCEPT_KEYWORDS="~arm64"
Container Setup
That having been accomplished, we'll need to set up our firefish containers. Firefish comes with a compose file, which is quite handy, and at only 78 lines, it's not exceedingly complicated. The app has three services: a postgres database, a redis cache, and a nodejs web server. We'll set up a network for them to communicate, and some volumes to hold config and data. Note that this guide was written with respect to the firefish repo at tag v20240630.
We could just podman compose up
the compose file and call it a day, but y'know: systemd all the things. Gotta systemd-coffeed
, systemd-nailclipperd
, systemd-existentialdreadd
, etc. Less cynically, we'll use loginctl
to bring up our rootless firefish pod on each boot, which is handy. Again, this is something you can script without systemd, but the cult of Poettering demands obeisance, so quadlet it is. We'll use podlet, which is a program that can turn a compose file into systemd services.
Composefile mods
As it happens, quadlet complains about several aspects of our compose file:
❯ podlet compose Error: 0: error converting compose file 1: error converting compose file into Quadlet files 2: error adding dependency on `db` to service `firefish-web` 3: dependency condition `service_healthy` is not directly supported Location: /home/whomsoever/.cargo/registry/src/index.crates.io-6f17d22bba15001f/podlet-0.3.0/src/cli/unit.rs:156 Suggestion: try using `Notify=healthy` in the [Container] section of the dependency Backtrace omitted. Run with RUST_BACKTRACE=1 environment variable to display it. Run with RUST_BACKTRACE=full to include source snippets.
And who are we to argue? We'll have to make some modifications. Remove the service_healthy
condition and replace them with a list of container names
-web:
+firefish-web:
image: registry.firefish.dev/firefish/firefish:latest
- container_name: firefish_web
+ container_name: 'firefish-web'
restart: unless-stopped
depends_on:
+ - 'firefish-db'
+ - 'firefish-redis'
- db:
- condition: service_healthy
- redis:
- condition: service_healthy
Having modified upstream's compose file to suit podlet's tastes, let's run the command to generate our services:
podlet compose
Copy the outputs to files in ~/.config/containers/systemd/firebase-web.container
, etc, being sure to add the condition above to each unit
[Container]
Notify=healthy
Next we need to set up the postgres database, which requires an extention called (and, please I'm asking you to say this out loud right now) pgroonga
. In order to do this, we first have to start the service once so that it creates the container.
systemctl --user start firefish-db
podman exec -it firefish-db sh -c 'psql \
--user="$POSTGRES_USER" \
--dbname="$POSTGRES_DB" \
--command="CREATE EXTENSION pgroonga;"'
That step should really be baked into the pgroonga
image, if you ask me, but no matter. If you entered the CREATE
command interactively, ctrl-d out of the sql prompt, then we need to add some config.
Troubleshooting
At a certain point I had an issue with the DB container's health check command. Running the health check command manually worked:
podman exec -it firefish-db sh -c 'pg_isready \
--user="$POSTGRES_USER" \
--dbname="$POSTGRES_DB"'
So I started the service then inspected the container to read the health check's output
❯ podman inspect firefish-db | jq .[].State.Health.Log
[
{
"Start": "2024-07-08T00:40:20.74269814+03:00",
"End": "2024-07-08T00:40:20.842938674+03:00",
"ExitCode": 1,
"Output": "/bin/sh: syntax error: unterminated quoted string"
}
]
Seems like I needed to adjust the syntax in the HealthCmd
field.
App config
Create an env file and a firefish config yaml so we can configure our instance
mkdir -p ~/.config/firefish
touch ~/.config/firefish/env
touch ~/.config/firefish/default.yml
Copy in the configuration from the firefish repo (you want the docker_example.env
and example.yml
files) and modify them to suit your needs. Make sure to set permissions appropriately! Should look like this when you're done:
$ ls -ln ~/.config/firefish/
total 12
-rw------- 1 1000 1000 6050 Jul 9 06:13 default.yml
-rw------- 1 1000 1000 220 Jul 9 06:13 env
Be sure to modify the volume bindings appropriately as well, and set the EnvironmentFile
key to point to ~/.config/firefish/env
;
Giv'er
All we have to do now is start the service
systemctl --user start firefish-web
And as they say, "zehu!", we now have firefish running locally. Fill out the onboarding survey, create an account, and start recklessly opining! If you want to attach it to a domain name, use cloudflared, dyndns, or run a reverse proxy, etc, but that's out of scope of this tutorial.