A source-based Mastodon install runs the Rails web app, streaming server, Sidekiq workers, PostgreSQL, Redis, and Nginx directly on the host. Use it when the server should follow upstream source releases without Docker Compose and the operator is ready to maintain Ruby, Node.js, systemd units, and reverse-proxy files.

The upstream source path uses NodeSource for Node.js, PGDG for PostgreSQL, Corepack for Yarn, and rbenv for the Ruby version declared by the checked-out Mastodon release. Keeping the default Mastodon user, application directory, and service template layout avoids manual path edits when the Nginx and systemd templates are installed.

Finish DNS, SMTP, and certificate planning before running the setup wizard because LOCAL_DOMAIN and mail settings are written into Mastodon's production environment file and affect federation and account recovery. A completed install has the three Mastodon systemd services active, Nginx proxying HTTPS traffic, and the public instance API returning 200 OK.

Steps to install Mastodon from source:

  1. Open a terminal with sudo privileges.

    The upstream source install currently targets Ubuntu 24.04 or Debian 13. Use a host in that family for the repository commands in this flow.

  2. Refresh the package index.
    $ sudo apt update
  3. Install the repository helper packages.
    $ sudo apt install --assume-yes curl wget gnupg lsb-release ca-certificates
  4. Add the NodeSource signing key.
    $ curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
  5. Add the Node.js 24 package repository.
    $ echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_24.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
    deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_24.x nodistro main

    Mastodon 4.6 requires Node.js 22 or newer. The upstream install path currently uses the NodeSource 24.x repository so Corepack can install the Yarn version pinned in package.json.

  6. Add the PostgreSQL repository signing key.
    $ sudo wget -O /usr/share/keyrings/postgresql.asc https://www.postgresql.org/media/keys/ACCC4CF8.asc
    ##### snipped #####
  7. Add the PGDG PostgreSQL package repository.
    $ echo "deb [signed-by=/usr/share/keyrings/postgresql.asc] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/postgresql.list
    deb [signed-by=/usr/share/keyrings/postgresql.asc] http://apt.postgresql.org/pub/repos/apt noble-pgdg main

    The shown output is for Ubuntu 24.04. On Debian 13, lsb_release -cs should expand to the Debian codename.

  8. Refresh the package index with the new repositories.
    $ sudo apt update
  9. Install Mastodon runtime and build packages.
    $ sudo apt install --assume-yes \
      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

    Mastodon 4.6 uses libvips for media processing. Older ImageMagick-only install notes do not match the current release line.

  10. Enable Corepack for the pinned Yarn version.
    $ sudo corepack enable
  11. Create the Mastodon system user.
    $ sudo adduser --disabled-password mastodon
  12. Create the PostgreSQL role used by Mastodon.
    $ sudo -u postgres createuser --createdb mastodon

    The default source install uses peer authentication, so the Linux user mastodon can connect as the PostgreSQL role mastodon without storing a database password in /home/mastodon/live/.env.production.

  13. Open a login shell as the Mastodon user.
    $ sudo -iu mastodon
  14. Clone the current Mastodon source release.
    $ git clone --branch v4.6.2 --depth 1 https://github.com/mastodon/mastodon.git live

    Use the current stable release tag for a real production install. Avoid deploying the default branch unless the instance is deliberately tracking unreleased code.

  15. Change into the Mastodon application directory.
    $ cd ~/live
  16. Verify the checked-out release tag.
    $ git describe --tags --exact-match
    v4.6.2
  17. Install rbenv for the Mastodon user.
    $ git clone https://github.com/rbenv/rbenv.git ~/.rbenv
  18. Add rbenv to the Mastodon shell path.
    $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
  19. Enable rbenv shell initialization.
    $ echo 'eval "$(rbenv init -)"' >> ~/.bashrc
  20. Load the updated shell configuration.
    $ source ~/.bashrc
  21. Install ruby-build for rbenv.
    $ git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
  22. Install the Ruby version declared by the release.
    $ RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install
    ##### snipped #####
    Installed ruby-4.0.5 to /home/mastodon/.rbenv/versions/4.0.5

    rbenv install reads /home/mastodon/live/.ruby-version from the current directory. The --with-jemalloc build option matches the upstream service templates that preload libjemalloc.

  23. Verify the Ruby version.
    $ ruby -e 'puts RUBY_VERSION'
    4.0.5
  24. Enable Bundler deployment mode.
    $ bundle config set --local deployment 'true'
  25. Exclude development and test gems.
    $ bundle config set --local without 'development test'
  26. Install the Ruby dependencies.
    $ bundle install
  27. Install the JavaScript dependencies.
    $ yarn install --immutable

    Corepack reads the Yarn version from package.json. Current Mastodon source declares Yarn 4.x, so do not replace this with the old global npm install -g yarn path.

  28. Run the Mastodon setup wizard.
    $ RAILS_ENV=production bin/rails mastodon:setup

    Use social.example.com as LOCAL_DOMAIN unless a split-domain plan is already chosen, enter the SMTP service details, keep PostgreSQL and Redis on localhost for this single-host layout, and let the wizard create /home/mastodon/live/.env.production, precompile assets, and initialize the database.
    Related: How to configure a Mastodon domain
    Related: How to configure Mastodon SMTP email

  29. Return to the sudo user shell.
    $ exit
  30. Request the HTTPS certificate.
    $ sudo certbot certonly --nginx -d social.example.com
    Successfully received certificate.
    Certificate is saved at: /etc/letsencrypt/live/social.example.com/fullchain.pem
    Key is saved at:         /etc/letsencrypt/live/social.example.com/privkey.pem

    Port 80 must reach this host from the public internet for the Nginx challenge to pass. Use the real Mastodon web hostname, not the account-only domain from a split-domain setup.

  31. Copy the upstream Nginx virtual host template.
    $ sudo cp /home/mastodon/live/dist/nginx.conf /etc/nginx/sites-available/mastodon
  32. Enable the Nginx virtual host.
    $ sudo ln -s /etc/nginx/sites-available/mastodon /etc/nginx/sites-enabled/mastodon
  33. Disable the default Nginx site.
    $ sudo rm /etc/nginx/sites-enabled/default
  34. Edit the Mastodon Nginx virtual host.
    $ sudoedit /etc/nginx/sites-available/mastodon
  35. Set the server name and certificate paths.
    server_name social.example.com;
     
    ssl_certificate     /etc/letsencrypt/live/social.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/social.example.com/privkey.pem;

    Keep the upstream backend and streaming upstreams on 127.0.0.1:3000 and 127.0.0.1:4000 unless the systemd service ports were changed.

  36. Allow Nginx to read the public assets under the Mastodon home directory.
    $ sudo chmod o+x /home/mastodon
  37. Test the Nginx configuration.
    $ sudo nginx -t
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful
  38. Restart Nginx with the Mastodon virtual host.
    $ sudo systemctl restart nginx
  39. Install the Mastodon systemd unit files.
    $ sudo cp /home/mastodon/live/dist/mastodon-*.service /etc/systemd/system/
  40. Reload systemd.
    $ sudo systemctl daemon-reload
  41. Enable and start the Mastodon services.
    $ sudo systemctl enable --now mastodon-web mastodon-sidekiq mastodon-streaming
  42. Confirm the Mastodon services are active.
    $ sudo systemctl is-active mastodon-web mastodon-sidekiq mastodon-streaming
    active
    active
    active
  43. Verify the public instance endpoint over HTTPS.
    $ curl --head https://social.example.com/api/v2/instance
    HTTP/2 200
    server: nginx
    content-type: application/json; charset=utf-8
    ##### snipped #####

    Create the first Owner account after the service and HTTPS checks pass.
    Related: How to create a Mastodon admin user