« home

How to run your own social network (with Snac)

18 December 2024

If you already know why permacomputing and little projects like Snac are so important for the fediverse, feel free to jump to the install instructions.
This guide is also available in Italian.

The Fediverse is a federated system of communities that looks somewhat like a big social network but without any central authority and without the algorithmic control of people beliefs and behaviours that fluel "surveillance capitalism".

The Fediverse connects different applications that communicate over a few protocols (with ActivityPub being the most supported one), providing different services to different communities.

An (pretty partial) overview of the applications coonnected to the Fediverse.

Given its hackish heritance and its focus on interconnected communities, the fediverse mood is quite peculiar compared to the one you can experience in commercial social networks.

Contents are distributed to users in a strictly temporal order, so it's pretty unusual for a content to become "viral" in the way it would on platforms like X, Facebook or TikTok, because the platform does not boost its visibility to the most vulnerable people to reinforce their addiction or to pilot their opinions and choices.

In the Fediverse you mostly find people minding their own business, talking with real-world friends, sharing their own contents and occasionally joining interesting conversations with strangers.

In other words, the Fediverse is proudly weird.

Big fish eat little fish all

Since the early days of identi.ca, the Fediverse grew and evolved with thousands different communities running their own node (commonly called "instance") of their favourite applications.

Millions of people already belongs to such communities and daily exchange their opinions, contents and mood over the system. Many of such communities are also open to new members that share some specific interest or value, or maybe just want to partecipate to the public discourse outside of US billionaires' properties.

Over the years, a few generalist instances grew so much that they became a bit of a problem for the autonomy of whole ecosystem. A problem exacerbated when Meta (owner of Facebook, Instagram and WhatsApp) half-joined the Fediverse with their new Threads app, in the usual BigTech tactics "embrance, extend and extinguish".

"Meta proposing Threads to the Fediverse" by David Revoy.

The cybernetic problems that large instances with millions (or billions) of users pose to smaller communities are both technical (raise in server-load and costs) and socio-political (harassments, spam, algorithmic exploitation of people...) but their analysis would take too much space in this (already long) political introduction to the solution.

It suffices to say that many large Fediverse nodes have been keen to let such threats in after Rocho's introduction.

"Don't roll out the red carpet for them" by David Revoy.

Faux-decentralization

A different and more subtle threat is "faux-decentralization".

The most transparent example is BlueSky, a corporate social network cosplaying decentralization, while turning "Bluesky Social, PBC" into a gatekeeper able to decide what people can read.

A more subtle form of "faux-decentralization" is caused by large managed hosting providers such as masto.host or toot.io: it's nice to see professional providers of fediverse applications, but their use by instances with hundreds or even thousands of users effectively reduce the resilience of the system and the autonomy of smaller communities.
And if you complain too much about the risks such companies pose to users, you will soon be censored by admins who lack the skills to manage their own server.

Mastodon instances pretending to be free and decentralized... while being managed by the same company.

The worst form of faux-decentralization is deploying the applications on BigTech's cloud services (AWS, Azure and so on), that expose users to both corporate exploitation and US surveillance under the renewed and reinforced FISA 702.

If you lend your users' data to BigTech, you betray their trust.


A barely competent fediverse admin... lured by the cloud provider he evoked.

Whatever the threats, they exploit a single underlying vulnerability: self-hosting most of applications is somewhat complex and expensive.

In general, self-hosting an Internet-facing server requires pretty good technical skills as a system administrator.

Notably, self-hosting a Mastodon server requires resources (mostly storage and bandwidth) that grow with the number of active users, their followers and the number of people they follow from other servers.
If you can't host the server on your own bare-metal, a trustworthy European VPS for a small but active community will cost you more than 500€ each year.

Not the most expensive hobby out there, but both requirements (competence and money) becomes barrier to entry that discourage most communities from building their own autonomous space in the Fediverse.

Permacomputing to the rescue!

Among the weirdest groups you can find on the Fediverse, a few hackers all over the world are building a sustainable and free post-capitalist infrastructure inspired by permaculture.

I was exposed to permacomputing years ago by Bob Mottram, a great hacker who created LibreServer and the great epicyon fediverse server that pursuit the exact same goals we have here, but in a different socio-technical way (building systems suitable for self-hosting on low power systems).

However, applications of permacomputing principles can be found in many simple and carefully crafted software that even predate their conceptualization, such as the Oberon Operating System and the Fossil Software Configuration Management System.

Fossil in particular inspired the development of my doh.cgi, a DNS-over-HTTPS sinkhole you can run as a CGI on any cheap web hosting plan.

Simply put, the political goal of doh.cgi is to leverage a technology designed to centralize most DNS resolutions in the hands of few large cloud providers while pretending to protect users' privacy, to actually protect users' privacy.

Using the decade old (but still widely supported) CGI framework, people can build their own DNS-over-HTTPS sinkhole for few bucks a year, often within the few megabytes of web hosting that provider attach to domain registration for free.

It works so well that I finally realized how the good old CGI framework could be used to counter the centralization forces that plague the Fediverse, simply because there are way more webmasters than competent sysadmins out there.

According to the permacomputing principles, before starting to hack yet another fediverse application (under my usual Hacking License) I looked around for existing solutions to reuse.

The first notable software I've found is #Seppo, a awesome OCaml CGI granting users a personal presence in the fediverse.

#Seppo is a labour of love by Marcus Rohrmoser with an underlying philosophy I love and several design decisions I like, but it's a bit too much "hacker-friendly" for most of communities out there. So while I love basically everything of it, it wouldn't help much with the political issue I'm trying to address.

SNAC: Social Networks Are Crap!

Then I met Grunfink's Snac, a simple minimalistic ActivityPub instance written in portable C but still powerful enough to interact with Mastodon front-ends such as Tusky, Fedilab or Tootle.

While less known than other fediverse servers (Mastodon, Pleroma, Friendica, Lemmy...), Snac is already quite used out there.

However, just like those servers, it's usually self-hosted on commodity hardware at home, or run in a VPS in the cloud (hopefully not from BigTech).

As a C nerd myself, I was surprised by the peculiar quality and originality of its codebase (and by with its bold lack of tests 😱). So I tried for a few nights to hack it so that it could be run as a CGI and I even managed to get it up and running... but.

To run on a commodity web hosting, you can't rely on a specific version of glibc being available, so you have to resort to static linking. As you always should, actually. :-)

However Snac depends on OpenSSL and curl, that together makes the final stripped binary larger then 5MiB: at least 3 page faults with the usual 2MiB page size on Linux x86_64.

These numbers might look negligible compared with the usual software bloat that plague our times, but they aren't because of how a webserver interacts with a CGI program, starting a new process for each HTTP request received.

I tried to explore alternative solutions to this issue, but they basically required a deep fork of snac as the changes were sparse and not easy to manage with a few #ifdef. However I didn't want to fork Snac because of the great work Grunfink is doing.

Finally I realized that since Snac already support the good old FastCGI execution environment, I could write a small CGI to start Snac (if not already running) and to proxy the requests received through a unix domain socket.

And guess what?
Reading the source code of the original FastCGI reference implementation, I learnt that such tool already exists! :-)

Since it took a couple of nights to understand how to build and configure snac and cgi-fcgi to work together (mostly because few use these technologies these days and search engines hide older doc), I wrote this article to help people get up and running.

I'm trying to assume a basic familiarity with GNU/Linux systems, with the ability to execute simple commands. Obviously, your mileage may vary.

Build Snac

What follows (finally! :-D) are the detailed instructions to build a statically linked Snac and a statically linked cgi-fcgi and deploy them on a cheap shared hosting running Apache on GNU/Linux to create your brand new fediverse node.

These instructions has been tested on a Debian GNU/Linux but they should work on any system running the required software, even if you are still dependent on spyware like Windows (with WSL) or MacOS.

So let's install wget, tar, git, make, sshfs and musl-gcc:

        sudo apt-get install wget tar git make sshfs musl-gcc
      

I'm going to use sshfs because it's easier to use and document in a command line, but you can easily adapt these instructions to a GUI like FileZilla: just execute the commands locally and then upload everything to you website.

Setup the work environment:

mkdir deploy
cd deploy
export DEPLOY_TARGET=$PWD
cd ..
mkdir build
cd build
export BUILD_TARGET=$PWD
export CC="musl-gcc"
      

Download and build the required libraries, zlib, openssl, and curl:

echo download and build zlib
wget https://zlib.net/current/zlib.tar.gz
tar xvf zlib.tar.gz
cd zlib-1.3.1/
./configure --prefix=$BUILD_TARGET --static
make
make install
cd ..

echo download and build openssl
wget https://github.com/openssl/openssl/releases/download/openssl-3.4.0/openssl-3.4.0.tar.gz
tar xvf openssl-3.4.0.tar.gz
cd openssl-3.4.0
CC="musl-gcc -fPIE -pie -static -idirafter /usr/include/ -idirafter /usr/include/x86_64-linux-gnu/" \
   ./Configure no-shared no-async --prefix=$BUILD_TARGET --openssldir=$BUILD_TARGET/ssl linux-x86_64
make depend
make
make install
cd ..

echo download and build curl
wget https://curl.se/download/curl-8.11.1.tar.gz
tar xvf curl-8.11.1.tar.gz
cd curl-8.11.1
./configure --disable-shared --enable-static --disable-silent-rules \
            --disable-debug --disable-warnings --disable-werror \
            --disable-curldebug --disable-symbol-hiding --disable-ares \
            --disable-rt --disable-ech --disable-dependency-tracking \
            --disable-libtool-lock --enable-http --disable-ftp \
            --disable-file --disable-ldap --disable-ldaps \
            --disable-rtsp --disable-proxy --disable-dict \
            --disable-telnet --disable-tftp --disable-pop3 \
            --disable-imap --disable-smb --disable-smtp --disable-gopher \
            --disable-mqtt --disable-manual --disable-libcurl-option --disable-ipv6 \
            --disable-openssl-auto-load-config --disable-versioned-symbols \
            --disable-verbose --disable-sspi --disable-crypto-auth \
            --disable-ntlm --disable-ntlm-wb --disable-tls-srp \
            --disable-unix-sockets --disable-cookies --disable-socketpair \
            --disable-http-auth --disable-doh --disable-mime --disable-dateparse \
            --disable-netrc --disable-progress-meter --disable-dnsshuffle \
            --disable-get-easy-options --disable-alt-svc --disable-websockets \
            --without-brotli --without-zstd --without-libpsl --without-libgsasl \
            --without-librtmp --without-winidn --disable-threaded-resolver  \
            --with-openssl=$BUILD_TARGET/ --with-zlib=$BUILD_TARGET/ \
            --prefix=$BUILD_TARGET/
make
make install
cd ..
      

NOTE that I'm not providing a script to run for the same reason I'm not releasing a couple of executables ready to run: each of these dependencies evolves and breaks, and it's up to you to preserve your users' security by properly updating them as new security issues get fixed.

Finally we can build a statically linked version of Snac:

git clone https://codeberg.org/grunfink/snac2.git
cd snac2
make CFLAGS="-g -Wall -Wextra -pedantic -static -DWITHOUT_SHM" \
     LDFLAGS="-L$BUILD_TARGET/lib64 -lcurl -lssl -lcrypto -lz" \
     PREFIX=$BUILD_TARGET 
make install PREFIX=$BUILD_TARGET
(cd $BUILD_TARGET; strip bin/snac)
cd ..
      

Build CGI-FCGI

The second tool we have to build is a statically linked version of the venerable CGI-FCGI tool:

git clone https://github.com/FastCGI-Archives/fcgi2.git
cd fcgi2
./autogen.sh
./configure --prefix=$BUILD_TARGET
make AM_LDFLAGS=-all-static
make AM_LDFLAGS=-all-static install
(cd $BUILD_TARGET; strip bin/cgi-fcgi)
cd ..
      

Initialization

Now that we have the software we need, it's time to read the Snac documentation and in particular the Administrator manual.

Indeed, we are going to initialize our fediverse instance.

First we connect to our web hosting server, where we already initialized a new empty web site with a SSL certificate (these days most shared hosting providers give you a free SSL certificate from Let's Encrypt).
Obviously you need to replace "username", "ftpserver", and "/your/new/website/folder" with the correct values.

sshfs username@ftpserver:/your/new/website/folder $DEPLOY_TARGET
      

Now we can see our webserver filesystem in the $DEPLOY_TARGET directory.

export PATH="$BUILD_TARGET/bin:$PATH"
cd $DEPLOY_TARGET
mkdir -p cgi-bin
cp $BUILD_TARGET/bin/snac cgi-bin
cp $BUILD_TARGET/bin/cgi-fcgi cgi-bin
snac init .snac-files
mkdir .snac-files/log
      

Now in the .snac-files folder you find the "database" of your node. Indeed Snac does not use a RDMS or something, just files and hardlink among them (that must be supported by the underlying filesystem).

NOTE that for security reasons, it would be very wise to keep binaries, sockets and the Snac basedir outside the of the virtual host root (the directory served to visitor of the web site), but this might or might not be possible depending on the hosting plan you are using.
Here I'm assuming you cannot, to simplify the explaination.

You now need to customize the .snac-files/server.json according to your needs. In particular, you need to set the "host" to the domain name of your service, "fastcgi" to "true", and "address" to the full path of a unix domain socket that will be created to communicate with the web server through cgi-fcgi.

For example, if your new domain name point to /your/new/website/folder you might set "address" to "/your/new/website/folder/snac.socket".

At this point we can add our users:

snac adduser .snac-files alice
snac adduser .snac-files bob
...
      

For each user you need to collect the initial password, that you should send them over an end-to-end encrypted channel. Teach users to change password at the first login (and to use an offline password manager, such as KeePassXC or KeePassDX).

Now we need a way for cgi-fcgi to start our Snac server:

cat << EOF > cgi-bin/snac-wrap.sh
#!/usr/bin/sh
WEBSITE_ROOT=/your/new/website/folder
exec -c $WEBSITE_ROOT/cgi-bin/snac httpd $WEBSITE_ROOT/.snac-files >> /dev/null 2>&1
EOF
chmod u+x cgi-bin/snac-wrap.sh
      

Obviously, if your hosting provider does not let you execute a shell, you have to replace this script with an equivalent alternative, such as a python or php script or even a little C program.

The snac-wrap.sh script will be used by cgi-fcgi to start Snac when it's not running:

cat << EOF > cgi-bin/snac.cgi
#!/home/tesioic/tools/cgi/cgi-fcgi -f
-connect /your/new/website/folder/snac.socket /your/new/website/folder/cgi-bin/snac-wrap.sh 1
EOF
chmod u+x cgi-bin/snac.cgi
      

Finally we are going to inform Apache how to invoke snac.cgi:

cat << EOF > .htaccess
# On index requests, run cgi-bin/snac.cgi
Options -Indexes
DirectoryIndex cgi-bin/snac.cgi

# Get rid of crawlers' DoS and protect user privacy
Header set X-Robots-Tag "noindex, nofollow"
Header set Referrer-Policy "no-referrer"

RewriteBase /

# Hide private files
RewriteCond %{REQUEST_FILENAME} .*snac-files.*
RewriteRule ^ - [R=404,L]
RewriteCond %{REQUEST_FILENAME} .*snac.socket
RewriteRule ^ - [R=404,L]

# Whenever a requested file or folder does not exists, exec cgi-bin/snac.cgi
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule "^(.*)$" cgi-bin/snac.cgi [NC,PT,L]
EOF

cat << EOF > cgi-bin/.htaccess
CGIPassAuth on
Options +ExecCGI
SetHandler cgi-script
EOF
      

Done!

Your brand new social network is up and running.

The Snac's user interface is pretty minimalist, but you can use it with any client compatible with Mastodon API.

Also you can customize your instance with a custom favicon.ico, a custom greeting.html, funny emojis or a cool style you like.

Now relax: this Christmas you have the most original present ready for your friends.

You should really follow @grunfink@comam.es for updates, but if you have any question about the process I described here, feel free to write me over the fediverse at @giacomo@snac.tesio.it.