Your own Fediverse instance
When toot.community announced that it would shut down, I had to make a decision: either lose the posts I had written over the years, or rescue them myself.
I already wrote about the why in my previous blog post. This one is about the how - and about a small, surprisingly elegant piece of software called snac2. So if you are in a similar situation or for whatever reason want to run your own small Fediverse instance, this is for you.
When I asked AI which options exist for a self-hosted Fediverse instance that is meant for just a single or a handful of people but is still fully part of the Fediverse, it kept coming back to almost only two serious answers:
- GoToSocial, written in Go, and
- Snac2, written in portable C.
I decided to go with snac2, because it is very lightweight, resource-efficient and quite easy to set up.
Why Snac2 is just right»
Snac2 was created by Grunfink and is a lightweight ActivityPub server written in portable C. It is designed to be simple, efficient and easy to set up, which makes it a great fit for small instances or personal use.
The name stands for “Social Networks Are Crap” - which, honestly, fits the whole story rather well. What I found especially good is how lean it is:
- No database, all data is stored as plain files on disk
- No JavaScript, no cookies, no tracking in the web interface
- Exactly two external dependencies: OpenSSL and libcurl
- Roughly 33,000 lines of C in total
So there’s no stack of complexity and the whole codebase is small enough to actually be read and understand by AI to make meaningful changes, which I’ll come back to in a moment. But much more important was to me, that it can be handled by my small VPS very well.
Snac2 Installation»
I use a standard debian linux server on my VPS. The installation is quite straightforward, but you need to be familiar with the command line and basic linux commands. It is no binary package but instead you need to compile it from source. The following commands did the job for me. You might need to adjust some paths and names to your needs.
Update your system and install the necessary dependencies
apt update apt upgrade -y apt install -y git build-essentialClone the Snac2 repository and compile it
cd /opt git clone https://codeberg.org/grunfink/snac2.git cd snac2 make clean make LDFLAGS="-lrt" # first run and see version information /opt/snac2/snac | head -2Create a dedicated user with home directory for Snac2
useradd --system --home /home/snac --shell /usr/sbin/nologin snac # make sure a valid home directory exists for the user getent passwd snac mkdir -p /home/snac usermod -d /home/snac snacInitialize Snac2
# initialize the Snac2 instance /opt/snac2/snac initIn this step, you will be prompted to enter some configuration details for your Snac2 instance. Here are example settings.
Base directory: /home/snac/data Network address or full path to unix socket [127.0.0.1]: /home/snac/socket Host name: social.your-domain.io URL prefix: [empty] Admin email address (optional): your-email@gmail.comYou might notice that I use
/home/snac/dataas the default data directory and/home/snac/socketas the Unix socket. You can change these paths, but adjust the permissions accordingly.Your reverse proxy must forward requests to the Snac2 socket or network address. I use a Unix socket in the Snac user’s home directory with group permissions for web, making it accessible to the web server/reverse proxy. Nginx is a common choice, but any web server that supports reverse proxying and SSL termination will work.
I use a simple Node.js script with greenlock for reverse proxying and Let’s Encrypt certificate renewal, but you can use any setup you prefer. Make sure your social domain is configured for certificate generation and renewal as well.
Set the correct permissions and run the Snac2 server
chown -R snac:snac /home/snac chown snac:web /home/snac/socket # quit with Ctrl-C /opt/snac2/snac httpd /home/snac/data
Snac2 as a service»
You successfully installed Snac2 and can run it manually, but it is better to run it as a service. Create a systemd service file for Snac2 eg. using vim /etc/systemd/system/snac.
[Unit]
Description=Snac ActivityPub server
After=network.target
[Service]
Type=simple
User=snac
Group=snac
WorkingDirectory=/home/snac/data
Environment=HOME=/home/snac/data
ExecStart=/opt/snac2/snac httpd /home/snac/data
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target Then you can enable and start the service with the following commands:
systemctl daemon-reload
systemctl enable --now snac
systemctl start snac In case you want to check the logs of the service, you can use the following command:
systemctl status snac
journalctl -u snac -n 50 --no-pager Add your Snac2 user and import your data»
Now that you host your own Fediverse instance it is time to add at least your own account to it. If you had an account somewhere else and want to move you data, you are welcome to follow my steps.
/opt/snac2/snac adduser /home/snac/data [USERNAME] Now you can check if your user was created successfully and the instance is running by resolving your account via WebFinger (optional):
curl https://social.dittgen.name/.well-known/webfinger?resource=acct:[USERNAME]@social.dittgen.name
/opt/snac2/snac webfinger /home/snac/data @[USERNAME]@social.dittgen.name To move you content from another instance, as in my case a Mastodon instance, export the different files. You can find a detailed description where to find the download option over at the [Mastodon documentation].
To rescue your follows, lists and bookmarks, place the relevant CSV files from your archive into the import directory of your new user and make sure Snac2 can read them, then run the import_csv command:
/home/snac/data/user/[USERNAME]/import/
├── following_accounts.csv
├── blocked_accounts.csv
├── bookmarks.csv
├── lists.csv
└── archive.zip (posts, boosts, likes) chown -R snac:snac /home/snac
chmod 750 /home/snac
chmod 750 /home/snac/import
chmod 640 /home/snac/import/*.csv
/opt/snac2/snac import_csv /home/snac/data [USERNAME] Importing the archive of posts and boosts»
Importing my follows and lists worked out of the box, because snac2 already ships an import_csv command. But importing the actual posts and boosts from a standard Mastodon archive is not supported by default.
That was the moment I realised something nice about Snac2:
Because the codebase is small and clean, it fits comfortably into the context window of a typical AI assistant. So I simply asked the AI to create this piece of software on demand, if you will. The demand is a feature with a small livespan, something to just use once to import my archived posts.
And here comes the irony I mentioned earlier: Snac2’s author Grunfink explicitly does not accept contributions that involve generative AI, his CONTRIBUTING file bans AI-generated material outright. So this feature will never be merged into the main branch, which is perfectly fine:
The result is a small patch of roughly 450 lines that adds an import_archive command for Mastodon ActivityPub archives. Because this is a very specific use case and by no means production code, I can easily trust the generated code and verify that it is working just by looking at my imported posts.
You can find this importer in the feat/import-mastodon-activitypub-archive branch of my Snac2 fork.
If you want to try it yourself, download the branch and compile it as described above, then import your archive:
cd /opt
git clone git@github.com:matths/snac2.git snac2-ext
git checkout feat/import-mastodon-activitypub-archive
cd snac2-ext
make clean
make LDFLAGS="-lrt"
/opt/snac2-ext/snac | head -2
# use the customized snac2 binary to import the archive
/opt/snac2-ext/snac import_archive /home/snac/data [USERNAME] After the import, a few bookkeeping steps are needed so that the imported posts are correctly attributed to my account:
# check if the import was successful
/opt/snac2/snac state /home/snac/data
# tell Snac2 that the latter is an alias/alternate ActivityPub identity
# for first one - the local account:
/opt/snac2/snac alias /home/snac/data [USERNAME] @[USERNAME]@social.dittgen.name
# displays the current state/statistics of the Snac instance
/opt/snac2/snac state /home/snac/data A good experience, with one small caveat»
Overall, running my own Fediverse instance has been a really good experience so far. The setup was quick, the resource usage is minimal, and the only thing I really had to adapt was the custom CSS stylesheet to make the web interface look the way I want.
The only issues I encountered are related to my reverse proxy in some situations. For example, forwarding the callback URLs of an app-specific protocol to the instance can be tricky at times triggered by some iOS ActivityPub client. But apart from those edge cases, everything works like a charm.
My posts are safe again - this time on infrastructure that I control.
If this post was helpful for you feel free to get in contact using the Fediverse. ;)