Use Neon as your dev environment for AWS RDS: accelerate your workflow while reducing costs

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.

Post image

Architecture of a Mastodon instance

A Mastodon instance is a fullstack application that consists of the following components:


Assumed knowledge

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

Development environment

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 platform. You will also need a 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 
cd mastodon-fly

When you Navigate into the cloned repository, you will see the following directory structure:

  • Dockerfile contains the instructions for building the Docker image that Fly will use to deploy the Mastodon instance.
  • fly.setup.toml is the configuration file used for setting up the database for the Mastodon instance to run.
  • fly.toml is the configuration file used when deploying the Mastodon instance to Fly.

Create a new app using flyctl

In your fly.toml and 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

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

In your fly.toml file, set the LOCAL_DOMAIN variable to the following format:

<your-app-name> This will be the domain of your Mastodon instance.

# fly.toml
LOCAL_DOMAIN = "<app-name>" 

How do I use my domain instead of the one provided by

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)


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.

Post image

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.

Post image

All Neon connection strings have the following format:

  • user is the database user.
  • password is the database user’s password.
  • endpoint_hostname is the host.
  • port is the Neon port number. The default port number is 5432.
  • dbname is 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


The 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.

Post image

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.

Post image

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.

Post image

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. 

Post image

Finally, grab the endpoint, password, and port values. You will upload them to Fly shortly.

Post image

Next, run the following command to upload your Redis database credentials to Fly: 

flyctl secrets set REDIS_HOST="" 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)

Post image

Next, pick the “ default transactional stream” and go to the “Settings” tab.

Post image

Scroll down to the SMTP section, and grab the values for the port, server name, username, and password. 

Post image

Finally, run the following command to upload these secrets to Fly:

flyctl secrets set SMTP_SERVER='' 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 dashboard, you will see a newly added IP address. You will be able to visit your app in a few minutes.

Post image

Deploying your app

You can now deploy your app to Fly by running the following command:

flyctl deploy

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 ????

Post image

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.