Hosting My Own Fediverse Instance

Date: August 31 2018


This article uses the term "Fediverse" to refer to a decentralized social network made up of servers speaking the ActivityPub protocol. The term "instance" refers to one or more servers and their associated domain name and web presence. One instance acts as a single logical server in the network although it may be backed by more than one server. This article outlines my attempts to set up a server that is a part of this network.


The most popular Fediverse server software (as of this writing) is Mastodon. The first step to turning a server into an instance is therefore to deploy Mastodon to it. Mastodon is packaged up as a series of containers which should make the deployment process easy. My first attempt at deploying these containers was using Azure Container Instances. That failed miserably. The containers still need to be configured and it is hard to figure out how to do that for a container group. This did not deter me. My attempt was to run the containers inside of a cloud VM.

Mastodon has a lot of moving parts, each of which runs in its own container:

I am not sure why Mastodon needs both a relational database and a simple key-value store but it does. The background jobs are things like sending messages to other instances and follow-related activity. I was able to get this up inside a VM.

Unfortunately, the VM did not like running all these things very much. It struggled under the load. I needed to find some other server software. Surely, in a truly federated system, there would be at least one other competing implementation. I looked for a Python implementation but the projects which I did find looked like they had been abandoned. I say projects, but it may have been one project that a few different maintainers picked up and abandoned in turn.


It turns out that the second most popular Fediverse server software (as of this writing) is Pleroma. Pleroma is implemented in Elixir which means that it runs on the Erlang VM. It was easier than I expected to install elixir, erlang, and the related packages that Pleroma needs. Pleroma needs a database so I installed PostgreSQL too. Mix is Elixir's build tool. It makes gathering dependencies, generating the config, setting up the database, and running the code very easy.

Now, I am hosting my instance at social.​xqz.​ca but I wanted my handle to match my email at my domain. Mastodon has this custom domain feature but Pleroma does not. It seemed like something that should have bene an easy enough feature to implement. That turned out to be the case! I know both Erlang and Ruby so it was very easy to pick up Elixir and start hacking away at the project.

For this feature to work, four things were required:

  1. Webfinger requests responded to my desired handle
  2. Webfinger requests responded to username @ the web domain
  3. Both Webfinger responses had the same content
  4. The Subject in those responses was the desired handle

Nothing beats testing in production so that is what I did for my patch. After running it for a while, I discovered that I had modified the Subject in JSON responses but not in XML responses. The feature worked reliably once I fixed that last piece.

I sent a pull request to the project and fixed up the patch to make it suitable for general consumption. The pull request was rejected outright. If you want the patch, I cloned the repo with the patch applied and put it on GitHub.


It is one thing to run the service and test it out but it is another to run it in a way that is reliable and secure. Either Apache2 or nginx will work as a front end web server to proxy requests. Any kind of social media platform should be served over HTTPS. Let's encrypt is fairly straightforward to set up. The simple way to let certbot do its thing is to have it temporarily stop the front end web server and let it take over the necessary web port. Pleroma itself should be run as a system service. It may be tempting to run it in a tmux or GNU screen session but it is better as a service.

If you are running Pleroma inside of a cloud VM, the important things to consider are: the code, the config, uploads, and the database. The code is kept in a git repository so backing that up elsewhere should be as easy as cloning or pushing the repo. You don't need to push to GitHub. A file share mounted on the server or a physical machine that you control can work just as well. Ideally, you would check the config into version control and back that up along side your code backups. Media uploads should be sent to cloud storage. Azure Files can be mounted as a file share so specifying a local path backed by that should work well. Alternatively, they can be sent as blobs to AWS S3 or Azure Blob storage. Daily database backups are always a good idea. Store them the same place that you would for uploads.