self-hosting mastodon with docker-compose
mastodon is the premier app of the fediverse - the ecosystem of decentralized web applications bound together by the activitypub protocol. there are many public instances of mastodon available for people to join, but savvy users may be interested in hosting their own. the reasons for this are multifold - examples include using your own domain name, resisting censorship, and having full agency over your online presence.
the project's official documentation includes instructions for running mastodon directly on a host machine. the source repository, however, includes a docker-compose file that is configured for a production deployment. this greatly streamlines the process of standing up a new instance, but there are a few extra steps involved to go from zero to running a functional instance.
I will make a few assumptions here: that the reader has 1) access to a virtual or physical machine with a modern linux distribution, 2) familiarity with docker and docker-compose, 3) knowledge of how to set up a reverse proxy with security certs, and 4) an understanding of how to safely expose an application to the open internet. to that last point, the mastodon project has a quick and dirty guide on configuring ssh, fail2ban, and iptables.
first, let's clone the repo and checkout the most recent stable tag. at the time of writing, it's v4.4.5:
$ git clone git@github.com:mastodon/mastodon.git && cd mastodon
$ git checkout v4.4.5
note that it's not strictly necessary to clone the repo - you can just copy the docker-compose yaml directly from github - but it's nice to have version control around this file for updates. you also have the option of building the application image from source. (the compose file points at prebuilt images for your convenience.)
perhaps like me, your first instinct is to just start every service in daemon mode and hit the ground running. if you do, you'll quickly find that the database needs to be set up. to do so, we'll start only the postgres container and get a psql shell, from which we can create the database:
$ docker compose up db -d
$ docker ps # grab the container id from this
$ docker exec -it <CONTAINER ID> psql -U postgres
postgres=# CREATE USER mastodon WITH PASSWORD '<YOUR STRONG PASSWORD HERE>' CREATEDB;
postgres=# \q
with the database created, we can now run the rake task that will do pretty much everything else. we should also create the .env.production
file that for our environment variables - the rake task is about to generate some!
$ touch .env.production
$ docker compose run --rm web bundle exec rake mastodon:setup
this launches a setup wizard that guides you through the basic configuration. one item of note is that mastodon requires an smtp server to send emails - something you may not have. mailgun has a free tier that is limited to 100 emails a day, which is fine if you're running an instance just for yourself. once the setup wizard finishes, it will print a set of environment variables that you should copy into your .env.production
file.
now we can start all of the containers! and then immediately stop them:
$ docker compose up -d
$ docker compose down
this is for another non-obvious reason: we need to update the permissions on the directories that are created for the container volumes, or else we'll encounter baffling errors from the application:
# chown -R 70:70 postgres14/
# chown -R 991:991 public/
these are the UIDs and GIDs of the postgres and mastodon users for the db and web images, respectively.
at this point, it is safe to start all of the services and start configuring nginx or caddy or whatever you're using to direct inbound traffic to the web container. happy posting!