Switch branches/tags
Nothing to show
Find file Copy path
355 lines (199 sloc) 14.3 KB

Running a Mastodon instance on Ubuntu 16.04 with Docker & nginx

This guide assumes you have:

  1. Root access to a fresh Ubuntu 16.04 x64 machine.
  2. A domain name (preferably a wacky TLD) pointed towards the IP address of the machine
  3. Some patience... please work all the way through to the "Troubleshooting" section before calling it a day 😃

These instructions have been tested and verified with the standard Ubuntu 16.04 x64 image on a $10/mo Vultr instance, a $20/mo DigitalOcean instance, and a $5/mo Linode instance. 2GB memory is recommended, but 1GB will work for small instances. You'll also find things faster if you can select the region nearest you geographically.

Step 1. Create a mastodon user with root privileges

First login via SSH as the root user, then add a new user:

adduser mastodon

Then give the user root privileges:

usermod -aG sudo mastodon

Switch to the new user:

su - mastodon

Install Docker

First, update the package database:

sudo apt-get update

Then install APT repository management tools and support for https repositories:

sudo apt-get install apt-transport-https software-properties-common

Now let's install Docker. Add the GPG key for the official Docker repository to the system:

sudo apt-key adv --keyserver hkp:// --recv-keys 58118E89F3A912897C070ADBF76221572C52609D

Add the Docker repository to APT sources:

sudo apt-add-repository 'deb ubuntu-xenial main'

Update the package database with the Docker packages from the newly added repo:

sudo apt-get update

Tell the system to install from the Docker repo instead of the default Ubuntu 16.04 repo:

sudo apt-cache policy docker-engine

Finally, install Docker:

sudo apt-get install -y docker-engine

Docker should now be installed, the daemon started, and the process enabled to start on boot. Check that it's running:

sudo systemctl status docker

Look for the text "active (running)" under the docker.service

So you don't have to prepend sudo to every docker command in the future, add yourself to the docker group that was just created:

sudo usermod -aG docker $(whoami)

Exit the SSH session and then log back in before moving to the next step.

Install Docker Compose

Check the latest release number here and run the following command, swapping out the release number ("1.18.0" below):

sudo curl -o /usr/local/bin/docker-compose -L "$(uname -s)-$(uname -m)"

Set the necessary permissions:

sudo chmod +x /usr/local/bin/docker-compose

Verify it installed by checking the version:

docker-compose -v

If you see the version number, we're in business.

Create temporary swap file (optional)

If you're using a machine with a small amount of RAM (like a 1GB VPS), you will probably need to create a temporary swap file in order to complete the rest of the guide. These commands will create a 1GB swap file:

sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

Install Mastodon

We're now reading to clone the git repo and start setting up Mastodon. Make sure you're in your home directory by running:

cd /home/mastodon

Clone the repo into this directory:

git clone

Next up, navigate to the cloned app directory:

cd mastodon

Copy the production environment configuration file:

cp .env.production.sample .env.production

We need to generate some secret keys before we configure everything, so we'll build the Docker image and get it running unconfigured first:

docker-compose build <== this may take a while, go make yourself a cup of tea ☕️

Now that the image is built, we're going to generate 3 secret keys that are required for the configuration. Run this command 3 times and note down each of the keys generated, we'll need them in a minute:

docker-compose run --rm web rake secret

Once you have your 3 secret keys noted somewhere, it's time to edit the configuration file:

nano .env.production

Edit the settings, and use the 3 secret keys you generated to populate the PAPERCLIP_SECRET, SECRET_KEY_BASE and OTP_SECRET settings. The order in which you copy/paste the keys doesn't matter, so long as each value is different.

Next, we need to update the following values:

  • (Required) Change the LOCAL_DOMAIN setting to match the domain you have pointing at the machine.
  • (Required) Email settings:
    • Setup a Mailgun account (make sure to enter your CC details for the 10k/mo free email tier)
    • Go through the domain verification process and make sure the domain is listed as green and "active"
    • From the domains page click your domain and then copy/paste the "Default SMTP Login" into your config file as the SMTP_LOGIN value and the "Default Password" as the SMTP_PASSWORD
    • Change the SMTP_FROM_ADDRESS value to something like notifications@
  • Optional If you want to store images and media on S3 instead of your machine (ie. if you don't have a lot of disk space) then generate the required settings via AWS and populate the S3 details (recommended for production use)

Once done, press ^X, type Y and hit Enter to save your changes. You can also use any text editor you'd like, if you're not a fan of nano

As we've changed the config, we'll need to build again:

docker-compose build

Now it's time to run migrations:

docker-compose run --rm web rails db:migrate

We can pre-compile assets too to make things snappier:

docker-compose run --rm web rails assets:precompile

Once completed, run the container:

docker-compose up -d

Setup nginx in front of Docker

First, let's install nginx:

sudo apt-get install nginx

We'll remove the default site profile:

sudo rm /etc/nginx/sites-available/default

...and it's symbolic link:

sudo rm /etc/nginx/sites-enabled/default

Then create a new profile for our Mastodon instance:

sudo touch /etc/nginx/sites-available/mastodon

...and a symbolic link enabling it:

sudo ln -s /etc/nginx/sites-available/mastodon /etc/nginx/sites-enabled/mastodon

Now let's configure nginx:

sudo nano /etc/nginx/sites-available/mastodon

Copy the nginx config from here and paste it into the nano editor window.

Find all intances of and replace with the domain name you have pointed to your machine. These are the only changes you should make.

Once done, press ^X, type Y and hit Enter to save your changes.

Setup SSL/HTTPS with Certbot

On Ubuntu systems, the Certbot team maintains a PPA. Once you add it to your list of repositories all you'll need to do is apt-get the following packages:

sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update

Now we can install Certbot:

sudo apt-get install python-certbot-nginx

Once installed, we can generate the SSL certificates. First you'll need to stop your nginx server so that Certbot can run its standalone authenticator:

sudo systemctl stop nginx.service

Then simply run the following command replacing with the domain you have pointed at your machine:

sudo certbot --nginx -d

Follow the prompts to complete the process.

Run Mastodon

We've made a lot of progress, let's get everything running. First, make sure you're in the Mastodon install directory:

cd /home/mastodon/mastodon

Now let's stop Docker and rebuild everything to be safe. Run these commands one line at a time, making sure none fail:

docker-compose down
docker-compose build
docker-compose run --rm web rails assets:precompile
docker-compose run --rm web rails db:migrate
docker-compose up -d

Lastly, let's bring nginx back online:

sudo systemctl restart nginx.service

You should be able to visit your domain now, be auto-directed to the HTTPS protocol and see your running Mastodon instance!

NOTE: If you created a temporary swap file, you can now delete it by running sudo swapoff /swapfile and sudo rm -rf /swapfile.

Setup cron jobs

Automate Mastodon tasks

To keep Mastodon running smoothly, we need to set up some cron jobs to regularly tidy things up in the background. First, make sure you're in the home directory of your mastodon user:

cd /home/mastodon

Next up, we'll create a file with the commands we'd like to schedule:

nano mastodon_cron

Copy/paste in everything below:

cd /home/mastodon/mastodon
docker-compose run --rm web rake mastodon:media:clear
docker-compose run --rm web rake mastodon:push:refresh
docker-compose run --rm web rake mastodon:push:clear
docker-compose run --rm web rake mastodon:feeds:clear

Once done, press ^X, type Y and hit Enter to save your changes. Now we need to tell cron to run this periodically:

sudo chmod +x mastodon_cron && sudo crontab -e

If you're prompted to select a text editor, just hit 2 then Enter to select nano. The crontab file should open up in edit mode, copy/paste and add this to the end of the file:

0 0 * * * /home/mastodon/mastodon_cron > /home/mastodon/mastodon_log

Once again, press ^X, type Y and hit Enter to save your changes. This has just told cron to run the specified commands at 12 midnight each day. You can adjust the /home/mastodon/mastodon_cron file to change what gets run daily, or change the scheduling by editing the crontab file and saving it again.

Auto-renew Let's Encrypt SSL certificate

Let's Encrypt SSL certificates expire every 90 days, so it's important that we schedule a job to automatically renew this periodically in the background - otherwise our instance will eventually lose SSL.

Let's fire up crontab again:

sudo crontab -e

Press the down arrow until you reach the end of the file, you should see your mastodon_cron job that we setup previously. Below that, copy/paste the following:

0 1 * * 1 /usr/bin/letsencrypt renew >> /home/mastodon/letsencrypt.log
5 1 * * 1 /bin/systemctl reload nginx

Once done, press ^X, type Y and hit Enter to save your changes.

We just created a new cron job that will execute the letsencrypt-auto renew command every Monday at 1:00am, and reload Nginx at 1:05am (so the renewed certificate will be used). If the certificate is less than 60 days old, letsencrypt will not try to renew it.

The output produced by the command will be piped to a log file located at /home/mastodon/letsencrypt.log

Next Steps: Managing your instance

Information on managing your instance can be found here on the Mastodon repository itself. Before you start editing site settings etc. however, you need to make yourself an admin.

Granting admin permissions

After registering on your newly created instance and confirming your account, you'll need to navigate to your Mastodon directory:

cd /home/mastodon/mastodon

Then run this command:

docker-compose run --rm web rails mastodon:make_admin USERNAME=yourusername

Logout and log back in again, then visit your.domain/admin/settings to start customizing your instance.

Other guides


Webpacker compliation error

If you're getting an error during the compilation process (like The code generator has deoptimised the styling of "/mastodon/node_modules/emoji-mart/dist-es/data/data.js" as it exceeds the max of "500KB"), you need more RAM. This can be solved by following the steps in the "Create temporary swap file" section.

Error uploading profile picture/background/other images

If you see an error message when you try to upload a profile picture, profile background, or other images, you may need to update permissions for the public/system folder. Make sure you are logged into the mastodon user, and run this command:

sudo chown -R 991:991 /home/mastodon/mastodon/public/system

The site loads but looks funky / doesn't respond properly

If you are seeing server errors or assets not rendering on the frontend, something might just need a gentle push to rebuild and start working.

A good first step is to run this block of commands one line at a time from your /home/mastodon/mastodon directory, making sure none of them fail - then check https://your.domain again to see if things are working.

docker-compose down
docker-compose build
docker-compose run --rm web rails assets:precompile
docker-compose run --rm web rails db:migrate
docker-compose up -d
sudo systemctl restart nginx.service

Note: docker-compose down will remove all containers, meaning it will clear out the database. If you'd like to avoid potential data loss, substitute it with docker-compose stop. This is less of an issue for a fresh install, but you'll want to switch to the latter once you have registered users.

Email confirmation isn't working

Is your host blacklisted?

Some mail hosts will blacklist or bounce emails coming from newly created email addresses or domains. Thankfully Mailgun will try sending these messages again and it should eventually get through.

If you are not receiving emails and need to confirm a user account, go to the "Logs" tab inside the Mailgun UI and click your domain. You should see a green row with the verification email that it attempted to send. Click the cog icon to the left of the row and then "View Message", from here you can manually copy/paste the confirmation URL into your browser to get around this problem.

After your instance is live for ~24 hours, you shouldn't be having this issue any longer.

Is your SMTP sending port blocked?

Some ISPs and hosts such as Scaleway block email sending on the standard SMTP port, 25. To see if that's happening view the web container's logs using docker logs mastodon_web_1 and look for connection timeouts. To correct this edit the .env.production configuration file and change SMTP_PORT: 25 to port 2525, which Mailgun and SparkPost support.

After doing so you'll need to rebuild the containers:

docker-compose stop
docker-compose build
docker-compose up -d