Skip to content

TutorialsCommunication

How to install Mastodon from source on Ubuntu 24.04 or Debian 13

Install a Mastodon server from source as the official docs describe: Ruby, Node.js, PostgreSQL, Redis, Nginx with Certbot, systemd units, backups and upgrades.

  • Advanced
  • 90 min read
  • Updated

Tested on: Ubuntu 24.04 LTS, Debian 13

This guide is not available in your language yet, so it is shown in English.

On this page
  1. Prerequisites
  2. Step 1 — Update the server and open the firewall
  3. Step 2 — Add the Node.js and PostgreSQL repositories
  4. Step 3 — Install the system packages and create the mastodon user
  5. Step 4 — Create the PostgreSQL user
  6. Step 5 — Get the code and install Ruby
  7. Step 6 — Install the Ruby and JavaScript dependencies
  8. Step 7 — Run the setup wizard
  9. Step 8 — Get a certificate and configure Nginx
  10. Step 9 — Start the Mastodon services
  11. Step 10 — Finish the admin setup and schedule media cleanup
  12. Back up and restore
  13. Update Mastodon
  14. Troubleshooting
  15. The browser shows the error page with the elephant
  16. Pages load without styles or images
  17. Confirmation emails never arrive
  18. The disk fills up
  19. bundle install fails after an upgrade with a Ruby version error
  20. Next steps

Mastodon is a decentralised social network: each server runs its own community and federates with thousands of others over ActivityPub. This guide installs Mastodon from source, the way the official documentation describes it, on Ubuntu 24.04 LTS or Debian 13: Node.js and PostgreSQL from their upstream repositories, Ruby through rbenv, Redis, Nginx with a Let's Encrypt certificate from Certbot, and the three systemd services that run the web app, the background workers and the streaming API. You then create the owner account, schedule media cleanup, and set up backups and upgrades.

Prerequisites

  • A fresh server running Ubuntu 24.04 LTS or Debian 13. These are the two releases the official guide targets; Ubuntu 26.04 and Debian 12 are not covered.
  • A non-root user with sudo rights and SSH key login: see Secure a new Linux server and Set up SSH keys.
  • A domain such as social.example.com with an A record (and AAAA record if you use IPv6) pointing to the server.
  • SMTP credentials from an email provider: host, port, user name, password and a sender address.
  • Optional: an S3-compatible bucket for media, for example from Self-hosted S3 storage.

The Mastodon project does not publish minimum requirements. The figures below are a conservative starting point for a small instance, not official numbers:

ResourceMinimum (official)Suggested starting point
CPUNot published2 vCPU
RAMNot published4 GB, because asset compilation and Sidekiq need memory
DiskNot published40 GB SSD plus media, or object storage for media
SoftwareRuby 3.3+, PostgreSQL 14+, Redis 7.0+, Node.js 22+ (Mastodon 4.7)The versions the steps below install

Step 1 — Update the server and open the firewall

Open a root shell, install updates and allow only SSH and web traffic. The official prerequisites use iptables rules for the same ports; ufw gives the same result with less typing:

Bash
sudo -i
apt update && apt upgrade -y
apt install -y ufw
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
ufw status verbose

Step 2 — Add the Node.js and PostgreSQL repositories

Mastodon's guide installs Node.js 24 from NodeSource and PostgreSQL from the PostgreSQL project's own apt repository:

Bash
apt install -y curl wget gnupg lsb-release ca-certificates
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_24.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
wget -O /usr/share/keyrings/postgresql.asc https://www.postgresql.org/media/keys/ACCC4CF8.asc
echo "deb [signed-by=/usr/share/keyrings/postgresql.asc] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/postgresql.list

Step 3 — Install the system packages and create the mastodon user

Install the build tools, media libraries, Nginx, Node.js, Redis, PostgreSQL and Certbot in one command, enable corepack (which provides Yarn), and create the unprivileged mastodon user that will own the code:

Bash
apt update
apt install -y imagemagick ffmpeg libvips-tools libpq-dev libxslt1-dev file git \
  protobuf-compiler pkg-config autoconf bison build-essential \
  libssl-dev libyaml-dev libreadline-dev zlib1g-dev libffi-dev libgdbm-dev \
  nginx nodejs redis-server postgresql certbot python3-certbot-nginx \
  libidn-dev libicu-dev libjemalloc-dev
corepack enable
adduser --disabled-password mastodon
node -v

node -v should print a v24 version. adduser asks for optional user details; press Enter to skip them.

Step 4 — Create the PostgreSQL user

Mastodon connects to PostgreSQL over the local socket as the Linux user of the same name, so the database user needs no password:

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

For larger instances the guide suggests tuning PostgreSQL with values from pgTune in /etc/postgresql/18/main/postgresql.conf and restarting PostgreSQL. A small server runs fine with the defaults.

Step 5 — Get the code and install Ruby

Switch to the mastodon user, clone the repository, check out the latest stable release tag, and install the Ruby version the release asks for with rbenv:

Bash
su - mastodon
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)
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
source ~/.bashrc
git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install
ruby -v

rbenv install reads the version from the .ruby-version file in the repository and compiles Ruby with jemalloc, which takes several minutes. ruby -v should print the same version.

Step 6 — Install the Ruby and JavaScript dependencies

Still as the mastodon user, in ~/live:

Bash
bundle config deployment 'true'
bundle config without 'development test'
bundle install
yarn install

The two bundle config lines are only needed on the first install. Both installs take a while; errors here usually mean a system package from Step 3 is missing.

Step 7 — Run the setup wizard

The interactive wizard writes .env.production, generates all secrets and encryption keys, creates the database schema, compiles the assets and can create the first admin account:

Bash
RAILS_ENV=production bin/rails mastodon:setup

Answer the questions like this:

QuestionAnswer for this guide
Domain namesocial.example.com; this becomes LOCAL_DOMAIN
Single user modeNo, unless the server is only for you
Are you using DockerNo
PostgreSQL host, port, database, user, passwordAccept the defaults: /var/run/postgresql, 5432, mastodon_production, mastodon, empty password
Redis host, port, passwordAccept the defaults: localhost, 6379, empty password
Store uploaded files on the cloudNo for local storage; Yes to enter your S3-compatible bucket
Send e-mails from localhostNo; then enter your SMTP server, for example smtp.example.com, port 587, user name, password and sender address
Send a test e-mailYes, to check SMTP now
Save configuration, prepare the database, compile assetsYes
Create an admin userYes; choose a user name and email, then copy the password the wizard prints

When the wizard has finished, return to the root shell:

Bash
exit

Step 8 — Get a certificate and configure Nginx

Request a certificate with Certbot's Nginx plugin, then install Mastodon's Nginx configuration from the repository:

Bash
certbot certonly --nginx -d social.example.com
cp /home/mastodon/live/dist/nginx.conf /etc/nginx/sites-available/mastodon
ln -s /etc/nginx/sites-available/mastodon /etc/nginx/sites-enabled/mastodon
rm /etc/nginx/sites-enabled/default
sed -i 's/example\.com/social.example.com/g' /etc/nginx/sites-available/mastodon
nano /etc/nginx/sites-available/mastodon

The sed command replaces the placeholder domain in the template with yours; use your real domain in place of social.example.com. In the editor, find the two commented certificate lines and remove the leading # so they read:

Nginx
ssl_certificate     /etc/letsencrypt/live/social.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/social.example.com/privkey.pem;

Let Nginx read the asset files in the mastodon home directory, test the configuration and restart Nginx:

Bash
chmod o+x /home/mastodon
nginx -t
systemctl restart nginx

Opening https://social.example.com now shows Mastodon's error page with the elephant, because the Mastodon processes are not running yet. Certbot's package renews the certificate automatically; certbot renew --dry-run tests the renewal.

Step 9 — Start the Mastodon services

The repository ships systemd units for the web app (Puma), the background workers (Sidekiq) and the streaming API. They assume the mastodon user and /home/mastodon/live, which this guide uses:

Bash
cp /home/mastodon/live/dist/mastodon-*.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now mastodon-web mastodon-sidekiq mastodon-streaming
systemctl status mastodon-web mastodon-sidekiq mastodon-streaming --no-pager

All three should be active (running). Open https://social.example.com and log in with the admin account from the wizard, then change its password under Preferences > Account.

Step 10 — Finish the admin setup and schedule media cleanup

If you skipped the admin account in the wizard, create the owner account with tootctl. Mastodon's setup guide notes that browser registration is disabled by default, so this is the way to create the first account:

Bash
su - mastodon
cd live
RAILS_ENV=production bin/tootctl accounts create alice --email [email protected] --confirmed --role Owner
RAILS_ENV=production bin/tootctl accounts modify alice --approve
exit

The first command prints a random password. Then go to Preferences > Administration > Server Settings and fill in the contact user name, a business email, the server description and the rules or code of conduct. Review the registration mode in the same area before you open sign-ups; requiring approval lets you check each new account.

Mastodon caches media and link previews from other servers, and the cache grows every day. tootctl media remove deletes cached remote attachments older than a number of days (7 by default), and tootctl preview_cards remove deletes link preview thumbnails (180 days by default). Schedule both as the mastodon user:

Bash
su - mastodon
crontab -e
Text
PATH=/home/mastodon/.rbenv/shims:/home/mastodon/.rbenv/bin:/usr/local/bin:/usr/bin:/bin
RAILS_ENV=production
15 3 * * * cd /home/mastodon/live && bin/tootctl media remove --days 7
45 3 * * 0 cd /home/mastodon/live && bin/tootctl preview_cards remove --days 180

Save, leave the editor and run exit. The PATH line lets cron find the Ruby version installed with rbenv. RAILS_ENV=production bin/tootctl media usage shows how much space media uses.

Back up and restore

Mastodon's backup guide lists four things, in order of importance: the PostgreSQL database (losing it means losing the whole server), the .env.production file with the secrets (losing it logs everyone out and breaks two-factor authentication), user-uploaded files in public/system when you use local storage, and the Redis database, which is the least critical. Run these commands in the root shell:

Bash
mkdir -p /opt/backups
chmod 700 /opt/backups
sudo -u mastodon pg_dump -Fc mastodon_production > /opt/backups/mastodon-db-$(date +%F).dump
cp /home/mastodon/live/.env.production /opt/backups/mastodon-env-$(date +%F)
redis-cli SAVE
cp /var/lib/redis/dump.rdb /opt/backups/mastodon-redis-$(date +%F).rdb
tar czf /opt/backups/mastodon-system-$(date +%F).tar.gz --exclude=system/cache -C /home/mastodon/live public/system
ls -lh /opt/backups

The --exclude=system/cache option skips media cached from other servers, which Mastodon can fetch again. With object storage, back up the bucket with your provider's tools instead of public/system. The best backups are off-site, so copy these files to another machine.

To restore on a new server, follow Steps 1 to 6 with the same version tag, then Step 8 and the cp and daemon-reload lines of Step 9 without starting the services. Do not run the setup wizard. Then load the backups as root:

Bash
systemctl stop 'mastodon-*.service'
sudo -u mastodon createdb -T template0 mastodon_production
sudo -u mastodon pg_restore -Fc -U mastodon -n public --no-owner --role=mastodon -d mastodon_production < /opt/backups/mastodon-db-2026-10-09.dump
cp /opt/backups/mastodon-env-2026-10-09 /home/mastodon/live/.env.production
chown mastodon:mastodon /home/mastodon/live/.env.production
tar xzf /opt/backups/mastodon-system-2026-10-09.tar.gz -C /home/mastodon/live
chown -R mastodon:mastodon /home/mastodon/live/public/system
systemctl stop redis-server
cp /opt/backups/mastodon-redis-2026-10-09.rdb /var/lib/redis/dump.rdb
chown redis:redis /var/lib/redis/dump.rdb
systemctl start redis-server

Finally rebuild the assets and home feeds, start the services and restart Nginx:

Bash
su - mastodon
cd live
RAILS_ENV=production bundle exec rails assets:precompile
RAILS_ENV=production ./bin/tootctl feeds build
exit
systemctl enable --now mastodon-web mastodon-sidekiq mastodon-streaming
systemctl restart nginx

Update Mastodon

Every Mastodon release on GitHub has its own upgrade instructions, and the order of steps matters. Mastodon's upgrade guide says you may skip patch releases, but you should deploy at least one release from each minor series and run every instruction at least once. Read the notes for each version between yours and the target, and take a backup first.

The steps below follow the non-Docker instructions of the 4.7 releases. Replace v4.7.3 with the release you are upgrading to:

Bash
su - mastodon
cd live
git fetch --tags
git checkout v4.7.3
bundle install
yarn install --immutable
RAILS_ENV=production bundle exec rails assets:precompile
SKIP_POST_DEPLOYMENT_MIGRATIONS=true RAILS_ENV=production bundle exec rails db:migrate
exit

Restart the processes, then run the remaining post-deployment migrations:

Bash
systemctl restart mastodon-sidekiq
systemctl reload mastodon-web
systemctl restart mastodon-streaming
su - mastodon
cd live
RAILS_ENV=production bundle exec rails db:migrate
exit

systemctl reload mastodon-web performs a phased restart without downtime; restarting the streaming service disconnects clients briefly. When the release notes ask for a new Ruby version, update ruby-build with git -C ~/.rbenv/plugins/ruby-build pull and run RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install in ~/live before bundle install.

Troubleshooting

The browser shows the error page with the elephant

Nginx works, but Puma does not answer. Check systemctl status mastodon-web and journalctl -u mastodon-web -n 50 --no-pager. A wrong path or Ruby version in the unit file, or a failed asset compilation, are the usual causes.

Pages load without styles or images

Nginx cannot read the compiled assets. Run chmod o+x /home/mastodon again, and if the files are missing, rebuild them as the mastodon user with RAILS_ENV=production bundle exec rails assets:precompile.

Confirmation emails never arrive

Mail is sent by Sidekiq. Read journalctl -u mastodon-sidekiq -n 100 --no-pager for SMTP errors, check the SMTP_ values in .env.production, and restart all three Mastodon services after every change to that file. SMTP_PORT should be 587, the relay port from Step 7.

The disk fills up

Run RAILS_ENV=production bin/tootctl media usage as the mastodon user to see where the space goes. Make sure the cron jobs from Step 10 run (grep CRON /var/log/syslog on Ubuntu, journalctl -u cron on Debian), lower --days if needed, or move media to object storage.

bundle install fails after an upgrade with a Ruby version error

The release needs a Ruby version that is not installed yet. Update ruby-build, run RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install in ~/live, then repeat bundle install and the remaining upgrade steps.

Next steps

Frequently asked questions

Can I change my Mastodon domain later?

No. Mastodon's configuration docs say LOCAL_DOMAIN and WEB_DOMAIN cannot be safely changed once set: remote servers would treat your accounts as new ones and communication with them can break. Even a reinstall does not fix it, so decide before you run the setup wizard.

Do I need an email server?

Yes. Mastodon sends confirmation links, password resets and notifications through the SMTP server you configure. Outbound port 25 is closed by default on HyperDC VPS. For services bought for a term of 3 months or longer, it is opened on request through a support ticket. Until then, send mail through an SMTP relay on port 587.

Why does this guide use Nginx instead of Caddy?

The Mastodon repository ships an Nginx configuration for its web, streaming and static file routes, and the official installation guide uses it with Certbot. Staying with it keeps your server close to the documentation and to the release notes.

Should I store media in object storage?

It is optional. Local storage keeps uploads and cached remote media in public/system on the server. S3-compatible object storage moves them off the machine; the setup wizard can configure it, and the bucket must support ACLs according to Mastodon's configuration docs.

Can I run Mastodon with Docker instead?

The official installation guide documents the from-source install on Ubuntu 24.04 or Debian 13 and does not describe a Docker deployment, so this guide follows the source install. Its systemd services, tootctl commands and release notes all assume this layout.

Which HyperDC servers can run Mastodon?

A HyperDC Linux VPS, VDS or dedicated server with root access running Ubuntu 24.04 LTS or Debian 13. Plan disk space for media, because files cached from other servers keep growing unless you clean them up.

Sources

Jelszó létrehozása

Please confirm