How to self-host Mastodon
Learn how to deploy your own Mastodon instance
In this guide, you will learn how to self-host your own Mastodon instance. If you’re interested in self-hosting Mastodon without getting into the technical details, you can check out the list of dedicated Mastodon hosting providers.
What is Mastodon?
Mastodon is an open-source, decentralized, federated social media platform based on the ActivityPub protocol. The protocol provides a client-to-server API for creating, updating, and deleting content and a federated server-to-server API for delivering notifications and content.
This way, you can have different Mastodon instances running on different servers, and they can all communicate with each other instead of having a single centralized social network. It doesn’t have to be a Mastodon instance; it can be any other ActivityPub-compliant server.
Architecture of a Mastodon instance
A Mastodon instance is a fullstack application that consists of the following components:
- Ruby on Rails server
- PostgreSQL database
- Sidekiq for handling background jobs
- Node.js streaming server
- Redis for caching and background jobs
- React frontend
- Elasticsearch for full-text search (optional)
- S3-compatible storage for user-uploaded photos and videos, such as AWS S3 (optional)
- SMTP server for sending emails (you can use an email provider like Mailgun or Postmark)
While this guide will attempt to cover everything in detail from a beginner developer’s standpoint, the following would be helpful:
- Basic knowledge of the command line
- Basic knowledge of Docker
To follow along with this guide, you will need to have the following tools installed on your machine:
- Git – version control system.
- Docker – to build and share containerized applications.
- flyctl – command-line utility that lets you work with the Fly.io platform. You will also need a fly.io account.
Cloning the starter repository
To get started, navigate into the directory of your choice and run the following command to clone the starter repository:
git clone https://github.com/neondatabase/mastodon-fly.git cd mastodon-fly
When you Navigate into the cloned repository, you will see the following directory structure:
mastodon/ ┣ Dockerfile ┣ README.md ┣ fly.setup.toml ┗ fly.toml
Dockerfilecontains the instructions for building the Docker image that Fly will use to deploy the Mastodon instance.
fly.setup.tomlis the configuration file used for setting up the database for the Mastodon instance to run.
fly.tomlis the configuration file used when deploying the Mastodon instance to Fly.
Create a new app using flyctl
fly.setup.toml files, update the
app variable with the name you would like to use for your app on Fly. This app name has to be unique across all Fly apps.
app = "<your-app-name>" # add this value in fly.toml and fly.setup.toml
Next, run the following command to create a new app on fly.io:
flyctl apps create --name <your-app-name> flyctl scale memory 512
If the name you chose is unavailable, you will get the following error:
Error Validation failed: Name has already been taken
Otherwise, you will see a success message similar to the following:
automatically selected personal organization: your-name New app created: <your-app-name> Scaled VM Memory size to 512 MB CPU Cores: 1 Memory: 512 MB
Choosing a domain for your app
fly.toml file, set the
LOCAL_DOMAIN variable to the following format:
<your-app-name>.fly.dev. This will be the domain of your Mastodon instance.
# fly.toml [env] LOCAL_DOMAIN = "<app-name>.fly.dev"
How do I use my domain instead of the one provided by Fly.io?
You can use a custom domain instead of the one provided by Fly. You must go to the domain registrar you used and add a new A record with the value of your app’s IP address. You will learn later how to assign an IP address to your app.
Generating app secrets
Mastodon has a set of secrets that you need to generate. You can do so by running the following commands:
SECRET_KEY_BASE=$(docker run --rm -it tootsuite/mastodon:latest bin/rake secret) OTP_SECRET=$(docker run --rm -it tootsuite/mastodon:latest bin/rake secret) flyctl secrets set OTP_SECRET=$OTP_SECRET SECRET_KEY_BASE=$SECRET_KEY_BASE docker run --rm -e OTP_SECRET=$OTP_SECRET -e SECRET_KEY_BASE=$SECRET_KEY_BASE -it tootsuite/mastodon:latest bin/rake mastodon:webpush:generate_vapid_key | flyctl secrets import
You are pulling the latest Mastodon Docker image and generating a set of secrets for your Mastodon instance. You are then storing those secrets using the fly secrets set command. If everything worked correctly, you will see the following message:
Secrets are staged for the first deployment
You should also be able to list all of your app’s secrets by running
fly secrets list.
➜ fly secrets list NAME DIGEST CREATED AT OTP_SECRET 34c76c7e73558354 3h19m ago SECRET_KEY_BASE c38aa6ba9d0d7674 3h19m ago VAPID_PRIVATE_KEY 45c7f3d3fb6d6faf 3h19m ago VAPID_PUBLIC_KEY 9b0042852df64493 3h19m ago
Provisioning a Postgres database using Neon
Although you can use a Postgres database from any Postgres provider, using Neon has a great advantage: scaling down to zero. Unlike traditional Postgres databases, where you have to pay a monthly minimum fee, with Neon, you will only pay for what you use.
To get started, go to the Neon console and create a new project by clicking on “Create a project”
Choose 15 as the Postgres version, and pick a region near where you will deploy your Mastodon instance.
You will be presented with a dialog that provides a password for your database. Save this password somewhere safe because you will need it later.
All Neon connection strings have the following format:
useris the database user.
passwordis the database user’s password.
endpoint_hostnameis the host.
portis the Neon port number. The default port number is 5432.
dbnameis the name of the database. “neondb” is the default database created with each Neon project.
Next, open the
fly.setup.toml file and update the environment variables with your Neon database credentials:
# fly.setup.toml # above unchanged DB_HOST='<project_id.cloud.neon.tech>' DB_USER='<your-user>' DB_NAME='main' DB_PASS='project=<project_id>;<password>' DB_PORT='5432'
DB_PASS variable has the
DB_PASS='project=<project_id>;password' string format because the underlying database client library in the Docker image does not support the SNI (Server Name Indication) mechanism in TLS. Check out the documentation to learn more about how Neon routes connections.
You can find the Project ID in your project’s settings.
Running the setup script
Next, run the following command to create the database tables:
flyctl deploy -c fly.setup.toml
You might get the following error when running
flyctl deploy -c fly.setup.toml:
Error failed to fetch an image or build from source: error connecting to docker: remote builder app unavailable.
If that happens, pass the
--local-only flag to the deploy command and rerun it while Docker runs in the background.
flyctl deploy -c fly.setup.toml --local-only
After the command runs, you will see newly created tables in the “Tables” tab in In Neon console.
Next, run the following command to upload your database credentials to Fly:
flyctl secrets set DB_USER='' DB_NAME='neondb' DB_PASS='project=<projectId>;<your-password>' DB_PORT=5432 DB_HOST=''
Provisioning a Redis database
The next step is to provision a Redis database. For this guide, we will use Upstash, but you can use any other Redis provider.
In the Upsatsh console, go to the “Redis” tab and click the “Create database” button.
Next, pick a name for your database and choose a region close to where you will deploy your Mastodon instance. It’s also a good idea to enable the TLS and Eviction options.
Finally, grab the endpoint, password, and port values. You will upload them to Fly shortly.
Next, run the following command to upload your Redis database credentials to Fly:
flyctl secrets set REDIS_HOST="eu2-equal-pony-18876.upstash.io" REDIS_PORT="31476" REDIS_PASSWORD="abcdefgh"
Using Postmark as your email provider
Mastodon relies on emails to send confirmation links and notifications. You can set up a third-party email provider, making sending emails much more reliable than building your own SMTP server. You can use one of the many available services, such as Mailgun, Postmark, Sendgrid, etc.
After creating an account, you will need to verify your email to be able to send emails. Next, in the “Servers” tab, choose the default server. (You can think of a server as a project)
Next, pick the “ default transactional stream” and go to the “Settings” tab.
Scroll down to the SMTP section, and grab the values for the port, server name, username, and password.
Finally, run the following command to upload these secrets to Fly:
flyctl secrets set SMTP_SERVER='smtp.postmarkapp.com' SMTP_PORT='587' SMTP_LOGIN='some-id' SMTP_PASSWORD='some-secret' SMTP_FROM_ADDRESS=''
Optional: Adding support for file uploads using AWS S3
You will need to set up an Object storage solution to enable file uploads from users who sign up for your Mastodon instance. The most common tool is AWS S3. Check out the documentation to learn how create your first S3 bucket. You will also need to create an IAM user to generate an access key ID and secret.
After setting up an S3 bucket, run the following command to upload the secrets to Fly:
flyctl secrets set S3_ENABLED=true S3_BUCKET="<bucket-name>" AWS_ACCESS_KEY_ID="<aws-access-key>" AWS_SECRET_ACCESS_KEY=""
Assigning an IP address to your app
The last thing you need to do is allocate an IP address for your deployed app. You can do that by running the following command:
flyctl ips allocate-v4
If you go to your Fly.io dashboard, you will see a newly added IP address. You will be able to visit your app in a few minutes.
Deploying your app
You can now deploy your app to Fly by running the following command:
If you did all of the previous steps correctly, you should have a deployed Mastodon instance running at the domain you specified in your
fly.toml file 🎉
You will be able to create an account and new posts after confirming your email.
Summary & Final thoughts
In this guide, you learned what Mastodon is and how to deploy an instance while leveraging various tools. If you want to customize it, you will need to clone the main repository and create your own Docker image.