Mastodon

How to Install Mastodon on Debian and Ubuntu (Step-by-Step Guide)

Step-by-step guide to installing Mastodon on Debian and Ubuntu. Start your own decentralized social network today!

7 min read
How to Install Mastodon on Debian and Ubuntu (Step-by-Step Guide)
AI image generated by ChatGPT 4o

I contributed to the official Mastodon installation guide back in 2022, but it has since become outdated. In this updated guide, I’ll walk you through the latest step-by-step process to install and configure a Mastodon instance on your own server.


1.What is Mastodon?


Mastodon is a free, open-source, decentralized social networking platform that offers a Twitter-like experience without being controlled by a single company.

Instead of everyone joining one central site, users can create or join independently operated servers (called "instances") that communicate with each other across the wider "Fediverse" (federated universe).

Running your own Mastodon instance gives you full control over your community, data, and content policies.

Mastodon - Decentralized social media
Learn more about Mastodon, the radically different, free and open-source decentralized social media platform.

Mastodon Official Website


2.Prerequisites

You will need to prepare the following:

  • A public domain name (either free or paid) with DNS A/AAAA records pointed to your server's IP address. In this tutorial, we will use example.com as an example.

  • A Linux server with Debian Stable or Ubuntu LTS installed and root access.

  • An email delivery service such as Mailgun or Amazon Simple Email Service.

First, log in to your server as the root user, or switch to root using sudo -i or su root and update system:

apt update
apt upgrade -y
apt full-upgrade -y

Upgrade system

Then, install the required software and dependencies:

apt install curl vim wget gnupg dpkg apt-transport-https lsb-release ca-certificates -y

Install system packages


3.Add repositories

Nginx

curl -sS https://n.wtf/public.key | gpg --dearmor > /usr/share/keyrings/n.wtf.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/n.wtf.gpg] https://mirror-cdn.xtom.com/sb/nginx/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/n.wtf.list

Nginx by N.WTF

Node.js

curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/nodesource.gpg

echo "deb [signed-by=//usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list

Node.js 22.x

PostgreSQL

curl -sSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor > /usr/share/keyrings/postgresql.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/postgresql.list

Latest PostgreSQL

Redis

curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg

echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list

Latest Redis

Elasticsearch 7

curl -sS https://artifacts.elastic.co/GPG-KEY-elasticsearch | gpg --dearmor > /usr/share/keyrings/elasticsearch.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/elasticsearch.gpg] https://artifacts.elastic.co/packages/7.x/apt stable main" > /etc/apt/sources.list.d/elasticsearch.list

Elasticsearch 7 (optional)

Then update system

apt update

Update system

And enable Yarn

corepack enable

Enable Yarn


4.Install System Packages

Now, let's install the system packages required for Mastodon:

apt install -y \
  imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev file git-core \
  g++ libprotobuf-dev protobuf-compiler pkg-config nodejs gcc autoconf \
  bison build-essential libssl-dev libyaml-dev libreadline6-dev \
  zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev \
  redis-server redis-tools postgresql postgresql-contrib \
  libidn11-dev libicu-dev libjemalloc-dev libvips nginx-extras

Install system packages

Then, enable the redis-server service:

systemctl enable --now redis-server

Enable Redis


5.Create Masoton User

We should create a user called mastodon:

sudo adduser --disabled-password --gecos "" --home /home/mastodon mastodon

Add Mastodon user

Then, grant the appropriate permissions for the /home/mastodon directory:

chmod 0755 /home/mastodon

Grant permission


6.Setting Up PostgreSQL

Mastodon uses PostgreSQL as its database. Let's create a user named mastodon and grant it permission to create a database for Mastodon:

sudo -u postgres psql
CREATE USER mastodon CREATEDB;
\q

Create PostgreSQL user

You can use PGTune to optimize your PostgreSQL configuration and performance settings.

PGTune automatically generates recommended PostgreSQL configuration settings based on your server's resources, such as memory and CPU, to improve database performance.


7.Install Mastodon

Now, let's use the mastodon user to install Mastodon. First, switch to the mastodon user and navigate to the /home/mastodon directory:

su - mastodon
cd ~

Switch to Mastodon user

Next, install rbenv, a version management tool for the Ruby programming language:

git clone https://github.com/rbenv/rbenv.git ~/.rbenv
cd ~/.rbenv && src/configure && make -C src
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
sourcec ~/.bashrc
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build

Install rbenv

Then, clone the Mastodon Git repository and switch to the latest released version:

cd ~
git clone https://github.com/mastodon/mastodon.git live && cd live
git checkout $(git tag -l | grep '^v[0-9.]*$' | sort -V | tail -n 1)

Fetch Mastodon source code

Once this is done, we can install the correct version of Ruby:

RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install

Install Ruby

Now, let's install the Ruby and JavaScript dependencies:

bundle config deployment 'true'
bundle config without 'development test'
bundle install -j$(getconf _NPROCESSORS_ONLN)
yarn install

Install Ruby and NodeJS dependencies

Wait until the installation is complete. Next, we will proceed with the Mastodon configuration.


6.Generate the Mastodon configuration file

Run the interactive setup wizard:

RAILS_ENV=production bin/rails mastodon:setup

Setup Mastodon

This process will:

  • Create a configuration file
  • Run asset precompilation
  • Create the database schema

The configuration file is saved as .env.production. You can review and edit it as needed. For detailed options, refer to the official documentation.

You’re done working with the mastodon user for now, so switch back to the root user:

exit

Exit to root


7.Configuring Nginx and SSL Certicates

We use acme.sh to obtain free SSL certificates from Let's Encrypt:

cd ~
git clone https://github.com/acmesh-official/acme.sh.git
cd ./acme.sh
./acme.sh --install -m [email protected]
source ~/.bashrc
acme.sh --upgrade --auto-upgrade
acme.sh --set-default-ca --server letsencrypt

Install acme.sh

Make sure to replace [email protected] with your actual email address; otherwise, you may encounter an error like this:

[Mon Apr 28 06:28:13 PM UTC 2025] Registering account: https://acme-v02.api.letsencrypt.org/directory
[Mon Apr 28 06:28:14 PM UTC 2025] Account registration error: {
  "type": "urn:ietf:params:acme:error:invalidContact",
  "detail": "Error creating new account :: contact email has forbidden domain \"example.com\"",
  "status": 400
}

Error if you use @example.com

Now, let's create a directory for Let's Encrypt verification using the HTTP-01 challenge, along with a directory to store the SSL certificates:

mkdir -p /var/www/letsencrypt/.well-known/{acme-challenge,pki-validation}
chown www-data:www-data /var/www/letsencrypt -R
mkdir -p /etc/nginx/ssl

Create a directory for HTTP-01 challenge

Then, modify the default Nginx configuration file.

sudo bash -c 'cat > /etc/nginx/sites-available/default << "EOF"
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;

    location ~ ^/.well-known/(acme-challenge|pki-validation)/ {
      root /var/www/letsencrypt;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}
EOF'

Modify default Nginx configuration

This configuration will redirect all requests on HTTP port 80 to HTTPS port 443, except for requests to /.well-known/acme-challenge/ and /.well-known/acme-challenge/pki-validation/, which will be served from the /var/www/letsencrypt directory.

These exceptions are necessary for the Let's Encrypt HTTP-01 challenge to work properly.

Reload Nginx:

nginx -t
nginx -s reload

Reload Nginx

Now we can issue SSL certificates for your domain name:

acme.sh --issue -d example.com -w /var/www/letsencrypt

Issue SSL certificates

💡
Replace example.com to your own domain name.

Then, install the certificates to /etc/nginx/ssl :

acme.sh --install-cert -d example.com \
--key-file       /etc/nginx/ssl/example.com.key  \
--fullchain-file /etc/nginx/ssl/example.com.crt \
--ca-file        /etc/nginx/ssl/example.com.ca.crt \
--reloadcmd     "systemctl restart nginx"

Install SSL certificates

Copy the Nginx configuration template from the Mastodon directory:

cp /home/mastodon/live/dist/nginx.conf /etc/nginx/sites-available/mastodon
ln -s /etc/nginx/sites-available/mastodon /etc/nginx/sites-enabled/mastodon

Copy Mastodon Nginx configuration

Modify /etc/nginx/sites-available/mastodon :

  • Remove the server block that starts with listen 80.
server {
  listen 80;
  listen [::]:80;
  server_name example.com;
  root /home/mastodon/live/public;
  location /.well-known/acme-challenge/ { allow all; }
  location / { return 301 https://$host$request_uri; }
}

Remove this server block

  • In the server block that starts with listens 443 ssl:
server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name example.com;

  ssl_protocols TLSv1.2 TLSv1.3;

  # You can use https://ssl-config.mozilla.org/ to generate your cipher set.
  # We recommend their "Intermediate" level.
  ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;

  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;
  ssl_session_tickets off;

  # Uncomment these lines once you acquire a certificate:
  # ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
  # ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

Modify this server block

💡
Change server_name example.com; to your own domain name.

Add the following under ssl_session_tickets off; line:

ssl_certificate     /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;

Use your SSL certificates

💡
Don't forget to change the SSL certificate and key file name to yours.

We can use Perl and sed to delete or replace them directly from the terminal:

sudo perl -i -0pe 's/server \{\n  listen 80;\n  listen \[::\]:80;\n  server_name example\.com;\n  root \/home\/mastodon\/live\/public;\n  location \/\.well-known\/acme-challenge\/ \{ allow all; \}\n  location \/ \{ return 301 https:\/\/\$host\$request_uri; \}\n\}//g' /etc/nginx/sites-available/mastodon

sudo sed -i '
s|# ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;|ssl_certificate     /etc/nginx/ssl/example.com.crt;|;
s|# ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;|ssl_certificate_key /etc/nginx/ssl/example.com.key;|
' /etc/nginx/sites-available/mastodon

Replace server block by two commands

Then, create a cache folder for Nginx and reload it:

mkdir -p /var/cache/nginx
chown www-data:www-data /var/cache/nginx -R
nginx -t
nginx -s reload

Create cache folder and reload Nginx


8.Setting Up Systemd Services

First, copy the systemd service templates from the Mastodon directory.

cp /home/mastodon/live/dist/mastodon-*.service /etc/systemd/system/

Copy systemd templates

Then, start and enable the new systemd services:

systemctl daemon-reload
systemctl enable --now mastodon-web mastodon-sidekiq mastodon-streaming

Enable and start Mastodon services

Now, you can visit https://example.com/ from your browser and enjoy your own Mastodon instance!