Install Mastodon without Docker (Ubuntu 20.04)

Snippet for running Mastodon instance (Twitter alternative) on Ubuntu 20.04 from source.
On this page

Mastodon is free and open-source software for running self-hosted social networking services. It has microblogging features similar to the Twitter service, which are offered by a large number of independently run nodes, known as instances, each with its own code of conduct, terms of service, privacy policy, privacy options, and moderation policies.

This article is my personal snippet for running Mastodon instance on Ubuntu 20.04 from source. I use self-signed certificate instead of cerbot because the instance will be run behind Cloudflare reverse proxy.

The video below is the whole process I install Mastodon instance (for reference)


Before starting, there are several things that need to be fulfilled:

  • Fresh Ubuntu 20.04 server with root access.
  • Domain name (or sub-domain) for the Mastodon instance (in this case I’m using and the Mastodon instance will be accessed from
  • SMTP Server for email delivery service.

Preparing the system

First, make sure the Ubuntu server we’re using is up to date.

1apt update && apt upgrade

Install curl, wget, gnupg, apt-transport-https, lsb-release and ca-certificates:

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

Install NodeJS 16:

1curl -sL | bash -

Use official PostgreSQL repository:

1wget -O /usr/share/keyrings/postgresql.asc
2echo "deb [signed-by=/usr/share/keyrings/postgresql.asc] $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/postgresql.list

Update and install required system package:

1apt update
2apt install -y \
3  imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev file git-core \
4  g++ libprotobuf-dev protobuf-compiler pkg-config nodejs gcc autoconf \
5  bison build-essential libssl-dev libyaml-dev libreadline6-dev \
6  zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev \
7  nginx redis-server redis-tools postgresql postgresql-contrib \
8  certbot python3-certbot-nginx libidn11-dev libicu-dev libjemalloc-dev

Enable NodeJS corepack feature and set Yarn version to classic:

1corepack enable
2yarn set version classic

Install Ruby with rbenv.

Note that rbenv must be installed for a single Linux user, therefore, first we must create linux user where Mastodon services will be running as (we’ll create mastodon user):

1adduser --disabled-login mastodon

Then switch to mastodon user:

1su - mastodon

And as mastodon user, proceed to install rbenv and rbenv-build:

1git clone ~/.rbenv
2cd ~/.rbenv && src/configure && make -C src
3echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
4echo 'eval "$(rbenv init -)"' >> ~/.bashrc
5exec bash
6git clone ~/.rbenv/plugins/ruby-build

Once Ruby environment setup is done, we can than install the required Ruby version and bundler:

1RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install 3.0.4
2rbenv global 3.0.4
3gem install bundler --no-document

Return to the root user:


Setting up PostgreSQL

For optimal performance, you may use pgTune to generate an appropriate configuration and edit values in /etc/postgresql/15/main/postgresql.conf before restarting PostgreSQL with systemctl restart postgresql.

Now, create a PostgreSQL user that Mastodon service could use. The easiest way is with ident authentication so the PostgreSQL user does not have a separate password and can be used by the Linux user with the same username.

Open PostgreSQL prompt:

1sudo -u postgres psql

In the psql prompt, execute:


The core system requirement is now ready, now we can move forward to setting up Mastodon instance along with it’s dependency.

Setting up Mastodon

It is time to download the Mastodon code. Switch to the mastodon user:

1su - mastodon

Use git to download the latest stable release of Mastodon:

1git clone live && cd live
2git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)

Install Ruby and JavaScript dependencies for Mastodon code:

1bundle config deployment 'true'
2bundle config without 'development test'
3bundle install -j$(getconf _NPROCESSORS_ONLN)
4yarn install --pure-lockfile

Run the interactive setup wizard:

1RAILS_ENV=production bundle exec rake mastodon:setup

The command above will be:

  • Create a configuration file
  • Run asset pre-compilation
  • Create the database schema

The configuration file is saved as .env.production.

In my case, I want Mastodon instance can be accessed from but use my main domain identity to serve @[email protected] (instead of @[email protected]) So I need to change LOCAL_DOMAIN configuration value to and add in the .env.production file configuration. Please refer to documentation on configuration for more detailed information.

When done with the configuration we can switch back to root user:


Setting up Nginx

Copy the Nginx configuration template that comes from Mastodon repository:

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

Then edit /etc/nginx/sites-available/mastodon and replace to our domain name (in my case

As I said before, the instance will be serve behind Cloudflare reverse proxy and I don’t want to use certbot to issue my SSL certificate. So I use my own self-signed certificate.

If you want to use certbot to issue the SSL certificate:

1systemctl reload nginx
2## Replace with your domain name.
3certbot --nginx -d

Setting up Mastodon systemd services

Copy the systemd service templates from the Mastodon directory to /etc/system/systemd directory:

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

Finally, start and enable Mastodon services:

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

Wait for a few minutes and try to access your instance from your web browser, and enjoy your self-hosted Twitter alternative!

If you want to join my instance, please do so : The data stored somewhere in Indonesia.