How To Install Mastodon on Ubuntu 26.04 LTS

Install Mastodon on Ubuntu 26.04

Social media platforms come and go, but your data always ends up in someone else’s hands. Mastodon changes that. It is a free, open-source, decentralized social network that gives you full ownership of your community, your rules, and your content. If you want to install Mastodon on Ubuntu 26.04 and run your own federated social instance, you are in the right place.

This Linux server tutorial walks you through every step required to get a production-ready Mastodon instance online. From system dependencies to Nginx reverse proxy configuration and SSL certificates, every command comes with an explanation of not just how to run it, but why it matters. By the end, you will have a fully functional, self-hosted Mastodon on Ubuntu 26.04 LTS (Resolute Raccoon) ready to federate with the wider Fediverse.

What Is Mastodon and Why Self-Host It?

Mastodon is a microblogging platform built on the ActivityPub protocol. Unlike Twitter or Bluesky, there is no central company controlling your data or moderating your speech at scale. Each server, called an instance, runs independently but can communicate with every other compatible server in the Fediverse.

Self-hosting Mastodon gives you three clear advantages:

  • Full data ownership — your posts, media, and user data live on your server.
  • Custom moderation policies — you set the rules, not a remote corporate team.
  • Privacy control — you decide what gets logged, cached, and shared with other instances.

Running your own instance is also a smart move for organizations, developer communities, or anyone building a private social layer for their team. Ubuntu 26.04 LTS (codenamed Resolute Raccoon), released on April 23, 2026, ships with Linux kernel 7.0, OpenSSL with post-quantum cryptography support, and long-term security patches until 2031. That makes it an excellent foundation for a production Mastodon deployment.

Prerequisites

Before you start, make sure you have the following in place:

Server requirements:

  • Ubuntu 26.04 LTS (Resolute Raccoon) — fresh install recommended
  • Minimum 4 vCPUs and 8 GB RAM for a small production instance
  • At least 20 GB of disk space (media storage grows fast; consider object storage for scale)
  • Root or sudo access

Networking requirements:

  • A registered domain name with DNS A/AAAA records pointed to your server IP
  • Ports 80 and 443 open in your firewall
  • A valid SMTP server or email delivery service (e.g., Mailgun, Amazon SES, or Postmark) — Mastodon requires email for account verification

Knowledge requirements:

  • Basic Linux terminal comfort
  • Familiarity with editing files using nano or vim

Step 1: Update Your System

Why This Step Matters

Running an outdated package list before installing dependencies is a common cause of version conflicts and broken installations. Ubuntu 26.04 ships with a modern apt package manager, but repository metadata still needs a refresh before you pull new packages.

Log in as root or switch to root:

sudo -i

Update the package index and apply all available upgrades:

apt update && apt upgrade -y

Then install the essential tools you will need for adding external repositories securely:

apt install -y curl wget gnupg lsb-release ca-certificates

Why these tools?

  • curl and wget — download GPG keys and repository lists from the internet.
  • gnupg — verifies that packages you add are cryptographically signed by their publishers.
  • lsb-release — outputs the current Ubuntu release codename, which repository scripts rely on.
  • ca-certificates — ensures HTTPS connections to external package sources are trusted.

Expected output: You should see a progress bar and a summary ending in 0 upgraded, 0 newly installed if the system was already up to date.

Step 2: Add Required Repositories

Why You Need External Repositories

Ubuntu’s default apt repositories carry stable but often older versions of Node.js and PostgreSQL. Mastodon requires Node.js 24.x and PostgreSQL 16+ for full compatibility. Using the upstream vendor repositories ensures you get the correct versions with the correct security patches.

Add the Node.js Repository

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

Why these commands? The first command downloads the GPG signing key from NodeSource and stores it in /etc/apt/keyrings/. The gpg --dearmor part converts the key from ASCII-armored format to binary, which is what modern apt requires. The second command adds the Node.js 24.x repository and ties package verification to that specific key — this prevents supply chain attacks.

Add the PostgreSQL Repository

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

Why use the official PostgreSQL repository? The Ubuntu-bundled PostgreSQL version may lag behind by one or two major versions. The PGDG (PostgreSQL Global Development Group) repository ships the latest stable releases with faster security patch turnaround.

Now refresh the package list so apt knows about the new repositories:

apt update

Enable Yarn via Corepack

Mastodon uses Yarn as its JavaScript package manager. With Node.js 24.x installed, you enable it through corepack — a Node.js built-in tool for managing package manager versions:

corepack enable

Why corepack instead of npm install -g yarn? Corepack locks the Yarn version to what the project specifies in package.json. This prevents version mismatches during asset compilation, which is one of the most common reasons Mastodon deployments fail silently.

Step 3: Install System Packages

Why Each Package Group Is Needed

Mastodon is a Ruby on Rails application with a React.js frontend. It processes images, transcodes media, manages background jobs, and speaks to a relational database. That requires a broad set of system libraries. Installing them all in one shot avoids partial dependency errors.

Run the full package installation:

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

What each group does:

  • imagemagick, ffmpeg, libvips-tools — Mastodon processes user-uploaded images and video previews. Without these, media uploads will fail.
  • libpq-dev — provides the C header files Ruby’s pg gem needs to compile its PostgreSQL bindings.
  • build-essential, autoconf, bison — Ruby compiles native C extensions during installation. Without these build tools, rbenv install will error out.
  • libssl-dev, libyaml-dev, libreadline-dev, zlib1g-dev, libffi-dev, libgdbm-dev — these are Ruby’s core compilation dependencies. Missing any one of them causes cryptic build failures.
  • nginx — the reverse proxy that sits in front of Mastodon and handles HTTPS termination.
  • redis-server — Mastodon uses Redis for its job queue (Sidekiq) and real-time streaming. It is not optional.
  • postgresql — the primary relational database for all Mastodon data.
  • certbot, python3-certbot-nginx — automates Let’s Encrypt SSL certificate issuance and renewal.
  • libjemalloc-dev — an alternative memory allocator that significantly reduces Mastodon’s RAM fragmentation in production.
  • libidn-dev, libicu-dev — handle international domain names and Unicode text normalization, both critical for a federated social platform with global users.

Expected output: A long list of packages being installed. This step can take 3–8 minutes depending on your server’s bandwidth and CPU speed.

Step 4: Configure PostgreSQL and Create the Mastodon User

Why PostgreSQL Needs Its Own Mastodon User

Running Mastodon’s database operations under the postgres superuser is a security risk. A dedicated database user with scoped permissions limits the blast radius if something goes wrong. Mastodon also expects to create and manage its own database, so the user needs CREATEDB privilege.

Enable and start PostgreSQL:

systemctl enable --now postgresql

Open the PostgreSQL interactive shell as the postgres system user:

sudo -u postgres psql

Inside the psql prompt, create the Mastodon database user:

CREATE USER mastodon CREATEDB;
\q

Why CREATEDB instead of full superuser? Granting CREATEDB lets Mastodon set up its own schema during the wizard without giving it the ability to modify other databases or change server-level settings. It is the principle of least privilege applied to database access.

Optional: Tune PostgreSQL for Performance

For any server with 4 GB RAM or more, the default PostgreSQL configuration leaves most of that memory unused. Edit the PostgreSQL config file:

nano /etc/postgresql/18/main/postgresql.conf

Key values to adjust for an 8 GB RAM server:

shared_buffers = 2GB
effective_cache_size = 6GB
work_mem = 64MB
maintenance_work_mem = 512MB
max_connections = 100

Why tune this? PostgreSQL’s default shared_buffers is 128 MB, which is suitable for a development laptop but starves a production Mastodon instance serving hundreds of queries per second. Proper tuning can cut average query time by 30–50% on a loaded server.

Restart PostgreSQL to apply changes:

systemctl restart postgresql

Create the Linux mastodon User

Mastodon’s application code should never run as root. Create a dedicated system user with no login password:

adduser --disabled-password mastodon

Why a dedicated user? If a vulnerability in Mastodon’s Ruby code is ever exploited, an attacker running as the mastodon user has no sudo access and cannot touch system files or other users’ data.

Step 5: Install Ruby with rbenv and Clone Mastodon

Why rbenv Instead of the System Ruby

Ubuntu 26.04’s default Ruby version from apt may not match what the latest Mastodon release requires. rbenv is a Ruby version manager that lets you install and switch between specific Ruby versions per user without affecting the system. This is the approach the official Mastodon documentation endorses, and it avoids the “works on my machine” class of Ruby version bugs.

Switch to the mastodon user:

su - mastodon

Install rbenv and ruby-build:

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

What each line does:

  • git clone https://github.com/rbenv/rbenv.git ~/.rbenv — pulls the rbenv tool into the mastodon user’s home directory.
  • The two echo lines add rbenv to the user’s shell PATH and initialize it on every new session.
  • source ~/.bashrc — reloads the shell config so rbenv is immediately available without logging out.
  • The final git clone installs ruby-build, the rbenv plugin that knows how to compile Ruby versions from source.

Clone the Mastodon Repository

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)

Why this checkout command? The git tag pipeline filters out release candidates and pre-release tags, then sorts by version number and picks the highest stable release. This means you always install the latest production-ready Mastodon version without manually checking the GitHub releases page.

Install the Required Ruby Version

Mastodon’s repository includes a .ruby-version file that tells rbenv exactly which version to use. Compile it with jemalloc support for better memory management:

RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install

Why --with-jemalloc? Ruby’s default memory allocator can fragment heap memory over time, causing Mastodon’s RAM usage to creep up on long-running servers. Compiling Ruby with jemalloc — which you already installed via libjemalloc-dev — keeps memory usage flatter under sustained load.

This step compiles Ruby from source and typically takes 5–15 minutes.

Install Ruby and JavaScript Dependencies

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

Why these bundle config flags?

  • deployment 'true' locks dependency versions to Gemfile.lock, preventing accidental upgrades during install.
  • without 'development test' skips gems used only for testing and local development, making the production install leaner and faster.

Step 6: Generate the Mastodon Configuration

Why the Interactive Wizard Matters

Mastodon’s setup wizard does three things in one pass: it creates the .env.production configuration file, compiles frontend JavaScript and CSS assets, and builds the initial PostgreSQL database schema. Doing these manually is error-prone. The wizard validates your inputs as it goes, which saves debugging time.

Still inside the mastodon user session and inside the ~/live directory, run:

RAILS_ENV=production bin/rails mastodon:setup

The wizard will prompt you for:

  • Domain name — enter your Mastodon instance’s domain (e.g., social.yourdomain.com)
  • Single-user mode — answer no unless you want a personal-only instance
  • Database settings — defaults work because you already created the mastodon PostgreSQL user
  • Redis settings — defaults work for a local Redis setup
  • File storage — choose local storage or an S3-compatible bucket
  • SMTP settings — enter your email delivery provider credentials here

Asset precompilation runs at the end of the wizard. It can take 10–20 minutes on a CPU-constrained server. Do not cancel it.

Once the wizard completes, switch back to root:

exit

The configuration is saved to /home/mastodon/live/.env.production. Review it once to confirm all values are correct before proceeding.

Step 7: Configure Nginx as a Reverse Proxy with SSL

Why Mastodon Needs a Reverse Proxy

Mastodon’s web process (Puma) and streaming server listen on local ports and do not handle SSL directly. Nginx sits in front of them, terminates HTTPS, applies security headers, caches static assets, and passes traffic to the right backend process. Skipping this step means your instance is either insecure or inaccessible from the public internet.

Issue the SSL Certificate

certbot certonly --nginx -d yourdomain.com

Why certonly instead of --nginx alone? Using certonly lets certbot obtain the certificate without modifying your Nginx config. You will set up the Nginx config manually from Mastodon’s template, which is already tuned for Mastodon’s requirements.

Certbot saves the certificate to /etc/letsencrypt/live/yourdomain.com/.

Set Up the Nginx Configuration

Copy Mastodon’s pre-built Nginx template:

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

Why remove the default site? Nginx’s default site listens on port 80 and serves a placeholder page. Leaving it active causes a configuration conflict with Mastodon’s Nginx block.

Edit the configuration to match your domain:

nano /etc/nginx/sites-available/mastodon

Replace all instances of example.com with your actual domain. Then uncomment the SSL certificate lines:

ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

Allow Nginx to read Mastodon’s static asset files:

chmod o+x /home/mastodon

Test the configuration for syntax errors before reloading:

nginx -t

If the output says syntax is ok and test is successful, reload Nginx:

systemctl restart nginx

Step 8: Set Up systemd Services and Start Mastodon

Why systemd for Mastodon

Mastodon runs as three separate processes: the web process (Puma), the background job worker (Sidekiq), and the streaming API server. Managing all three manually with shell scripts is fragile. systemd handles process supervision, automatic restarts on crash, boot-time startup, and centralized logging through journalctl — all without any extra tooling.

Copy the systemd service unit files from Mastodon’s distribution folder:

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

Review the service files to confirm the username and paths match your setup:

nano /etc/systemd/system/mastodon-web.service
nano /etc/systemd/system/mastodon-sidekiq.service
nano /etc/systemd/system/mastodon-streaming.service

Reload systemd so it picks up the new unit files, then enable and start all three services:

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

Why enable --now together? The enable flag makes the services start automatically at boot. The --now flag starts them immediately without a separate systemctl start command. This confirms the services work right now while also guaranteeing they will survive a server reboot.

Verify all three are running:

systemctl status mastodon-web mastodon-sidekiq mastodon-streaming

You should see active (running) for all three. Open your browser and navigate to https://yourdomain.com. Your Mastodon instance is live.

Step 9: Optional — Enable Full-Text Search with Elasticsearch

Why Elasticsearch Is Worth Adding

By default, Mastodon only indexes hashtags for search. With Elasticsearch, users can search the full text of their own posts and posts they have interacted with. For any community-focused instance, this is a meaningful quality-of-life feature.

Install Elasticsearch:

apt install elasticsearch

Limit its memory usage (adjust based on available RAM):

bash -c 'echo "-Xms2g
-Xmx2g" > /etc/elasticsearch/jvm.options.d/jvm.options'

Enable and start the service:

systemctl enable --now elasticsearch

Add the following lines to /home/mastodon/live/.env.production:

ES_ENABLED=true
ES_HOST=localhost
ES_PORT=9200

Restart Mastodon’s services:

systemctl restart mastodon-web mastodon-sidekiq

Build the search index:

su - mastodon
RAILS_ENV=production /home/mastodon/live/bin/tootctl search deploy

Why run tootctl search deploy? This command creates the Elasticsearch index schema and populates it with existing posts. Without it, the search engine has no data to query even with the configuration in place.

Troubleshooting Common Errors

Even a clean installation can hit edge cases. Here are the five most common issues and how to fix them.

1. bundle install Fails with Missing Header Files

Error: mkmf.rb can't find header files for ruby

Cause: One or more lib*-dev packages from Step 3 did not install correctly.

Fix:

apt install -y build-essential libssl-dev libreadline-dev zlib1g-dev

Then re-run bundle install.

2. PostgreSQL Connection Refused

Error: PG::ConnectionBad: could not connect to server

Cause: PostgreSQL is not running, or the mastodon database user does not exist.

Fix:

systemctl status postgresql
sudo -u postgres psql -c "\du"

If the mastodon user is missing, create it again:

sudo -u postgres psql -c "CREATE USER mastodon CREATEDB;"

3. Nginx 502 Bad Gateway After Starting Services

Cause: Mastodon’s Puma web process has not fully started yet, or it crashed on boot.

Fix:

journalctl -u mastodon-web -n 50 --no-pager

Read the last 50 log lines. Common causes include missing environment variables in .env.production or a failed database migration.

4. SSL Certificate Not Renewing Automatically

Cause: The certbot renewal cron job or systemd timer is inactive.

Fix:

systemctl status certbot.timer
certbot renew --dry-run

5. Asset Precompilation Hangs or Runs Out of Memory

Cause: Servers with less than 2 GB free RAM will struggle with webpacker or vite during asset compilation.

Fix: Add a temporary swap file before running the setup wizard:

fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

Remove it after installation completes with swapoff /swapfile && rm /swapfile.

r00t is a Linux Systems Administrator and open-source advocate with over ten years of hands-on experience in server infrastructure, system hardening, and performance tuning. Having worked across distributions such as Debian, Arch, RHEL, and Ubuntu, he brings real-world depth to every article published on this blog. r00t writes to bridge the gap between complex sysadmin concepts and practical, everyday application — whether you are configuring your first server or optimizing a production environment. Based in New York, US, he is a firm believer that knowledge, like open-source software, is best when shared freely.

Related Posts