How to install Mastodon on Debian 8

As many of you may have noticed there is a new player around that may cause some trouble to the micro-blogging platform called Twitter.

fluffy elephant 200x224This new player, called Mastodon, isn't the usual type of centralised "free" service that attracts millions of users with the intent of monetise them by selling their data and selling advert spaces, quite the contrary. Mastodon is very similar to Twitter in terms of features but it has the added bonuses of being really free, Open Source and decentralised.

This means that each one of us could download the software and create a Twitter-like service for his/her own family/friends/colleagues linked with the Mastodon servers around the world.

To know more about why and when Mastodon has been created check out the following links:

What follows is a step by step guide on how to install Mastodon on your own server.

Setting up mastodon on Debian 8

Setting up Mastodon on Debian Jessie is generally a copy/paste exercise of the commands you'll find below but keep in mind that this guide doesn't include (yet) information on how to setup and configure many other important elements such as firewall, Nginx, Postfix, etc....

Those that aren't used to configure Linux servers every day could find it easier and faster to use Webmin/Virtualmin or similar management tools which may introduce slight variations in the commands you'll have to type.

If you'd like to create a test environment and you have some experience with Docker then follow this guide.

It is strongly advised to proceed with the installation on a freshly installed Debian to avoid interfering with production environments.

General dependencies

The following commands must be run as "root".

Add Jessie backports to install ffmpeg .

echo "deb http://httpredir.debian.org/debian jessie-backports main" >> /etc/apt/sources.list
apt update && apt full-upgrade -y
apt-get install imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev file curl git

Install Node.js

curl -sL https://deb.nodesource.com/setup_4.x | bash -
apt install nodejs
npm install -g yarn

Install Redis

apt install redis-server redis-tools

Install PostgreSQL

apt-get install postgresql postgresql-contrib

Create the user mastodon giving it rights to create databases:

su - postgres
psql
CREATE USER mastodon CREATEDB;
\q
exit

create the user Mastodon

The mastodon user will be used to install and manage all the components necessary to run Mastodon. This user cannot login to the console directly so you'll have to su to it.

adduser --disabled-password --disabled-login mastodon -s /bin/bash

To login as mastodon user:

su - mastodon

To go back to the previous user:

exit

Install Ruby

apt install autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm3 libgdbm-dev

Install rbenv

In this section all commands will need to be run as user mastodon

su - mastodon
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
cd ~/.rbenv && src/configure && make -C src
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile

In the section above some environment variables are set, to apply them to the user mastodon logout and login again.

exit
su - mastodon

Make sure you logged in as mastodon again before continuing.

Install ruby-build

git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build

Install Ruby

rbenv install 2.4.1

Prepare yourself a coffee as it's going to take a few minutes.

Install Mastodon

cd ~
git clone https://github.com/tootsuite/mastodon.git live
cd live

With the following command we'll install the latest production ready version of Mastodon.

git checkout $(git tag | tail -n 1)

Install the remaining packets:

gem install bundler
bundle install --deployment --without development test
yarn install

Configuration

Copy the existing sample file into .env.production :

cp .env.production.sample .env.production
nano .env.production

Modify the following lines:

REDIS_HOST=localhost
DB_HOST=/var/run/postgresql
DB_USER=mastodon
DB_NAME=mastodon_production
LOCAL_DOMAIN=mastodon.partecipa.digital # this must be your full domain name
LOCAL_HTTPS=true # make sure this is set to true

Use the command bundle exec rake secret 3 times to create 3 random strings similar to this one:

d250201baf31243159865836db1826b8cf1d442ea5cc37119908cadde0d160b3f248b6e47a8035c62d7fd9538fb3a5bcec6bc808040bc4995426a5c27b230420

Copy each of the generated strings after the = sign (no spaces) in each of the following lines:

PAPERCLIP_SECRET=
SECRET_KEY_BASE=
OTP_SECRET=

Mail server configuration:

SMTP_SERVER=smtp.mailgun.org # or your mail server FQDN
SMTP_PORT=587 # or 25 if you don't plan to use TLS
SMTP_LOGIN=
SMTP_PASSWORD=
SMTP_FROM_ADDRESS=This email address is being protected from spambots. You need JavaScript enabled to view it.
#SMTP_DOMAIN= # defaults to LOCAL_DOMAIN
#SMTP_DELIVERY_METHOD=smtp # delivery method can also be sendmail
#SMTP_AUTH_METHOD=plain
#SMTP_OPENSSL_VERIFY_MODE=peer
#SMTP_ENABLE_STARTTLS_AUTO=true

The section above depends on the mail server you will be using and the eventual limits imposed by your service providers if you are using one. The example shows a configuration for Mailgun, a mass mail provider, which you could use if you plan/hope to have thousands of accounts on your Mastodon instance, otherwise configure your local Postfix and related MX/SPF records to manage the emails from your local server.

If you plan to have mainly English speaking users then set this variable:

DEFAULT_LOCALE=en

create and populate the db

RAILS_ENV=production bundle exec rails db:setup

precompile all the assets (css/js)

RAILS_ENV=production bundle exec rails assets:precompile

Once the assets have been compiled you can return to the user root:

exit

End of the section where you must use the user mastodon.

Configure the Systemd scripts

Mastodon requires to run 3 Systemd scripts.

Run the following commands as root.

web Services

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

Paste the following lines:

[Unit]
 Description=mastodon-web
 After=network.target

[Service]
 Type=simple
 User=mastodon
 WorkingDirectory=/home/mastodon/live
 Environment="RAILS_ENV=production"
 Environment="PORT=3000"
 ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
 TimeoutSec=15
 Restart=always

[Install]
 WantedBy=multi-user.target

Background workers

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

Paste the following lines:

[Unit]
 Description=mastodon-sidekiq
 After=network.target

[Service]
 Type=simple
 User=mastodon
 WorkingDirectory=/home/mastodon/live
 Environment="RAILS_ENV=production"
 Environment="DB_POOL=20"
 ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 20 -q default -q mailers -q pull -q push
 TimeoutSec=15
 Restart=always

[Install]
 WantedBy=multi-user.target

Streaming API

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

Paste the following lines:

[Unit]
 Description=mastodon-streaming
 After=network.target

[Service]
 Type=simple
 User=mastodon
 WorkingDirectory=/home/mastodon/live
 Environment="NODE_ENV=production"
 Environment="PORT=4000"
 ExecStart=/usr/bin/npm run start
 TimeoutSec=15
 Restart=always

[Install]
 WantedBy=multi-user.target

Activate the scripts:

systemctl enable /etc/systemd/system/mastodon-*.service

Run the services:

systemctl start mastodon-web.service mastodon-sidekiq.service mastodon-streaming.service

If you make changes to the configuration or update Mastodon restart the services:

systemctl restart mastodon-web.service mastodon-sidekiq.service mastodon-streaming.service

Check if the services are running:

systemctl status mastodon-web.service mastodon-sidekiq.service mastodon-streaming.service

If all the services are active (running) then you are good to go:

Stato dei servizi Systemd di Mastodon

If you see some errors then check the logs (replace mastodon-<servicename> with eg. mastodon-web.service:

journalctl -u mastodon-<servicename>

Create the cronjob

Edit the cronjob for the user mastodon:

crontab -e -u mastodon

Past the following line:

@daily cd /home/mastodon/live && RAILS_ENV=production /home/mastodon/.rbenv/shims/bundle exec rake mastodon:daily

Install and configure Nginx

Debian 8 provides a dated version of Nginx so we'll add the official repository to use the latest one:

wget -O - https://nginx.org/keys/nginx_signing.key | apt-key add -
echo "deb http://nginx.org/packages/debian/ $(lsb_release -sc) nginx" > /etc/apt/sources.list.d/nginx.list
apt update
apt install nginx

Note: If you use Virtualmin you should create the directories sites-available and sites-enabled, as root, under /etc/nginx as they are not created by default and Virtualmin likes to use them.

Create a new conf file for mastodon:

nano /etc/nginx/conf.d/mastodon.conf

Paste inside it the following configuration (replace the example domain mastodon.partecipa.digital with your own and edit the relevant path) :

map $http_upgrade $connection_upgrade {
 default upgrade;
 '' close;
}
server {
 listen 80;
 listen [::]:80;
 server_name mastodon.partecipa.digital;
 
# Redirect all requests to https location / { return 301 https://$host$request_uri; }

# Useful if you use Let's Encrypt
location /.well-known/acme-challenge/ { allow all; } access_log /dev/null; error_log /dev/null; } server { listen 443 ssl http2; # listen [::]:443 ssl http2; # Remove # if you are using IPv6 server_name mastodon.partecipa.digital;
root /home/mastodon/live/public; index index.html index.htm index.php;

access_log /var/log/mastodon.partecipa.digital_access_log;
error_log /var/log/mastodon.partecipa.digital_error_log;
# If you don't use a subdomain (eg. mastodon.partecipa.digital) remove the # from the 3 lines below
#if ($host = www.partecipa.digital) { # return 301 https://partecipa.digital$request_uri; #}


#HTTPS
ssl on;
ssl_protocols TLSv1.2; ssl_ecdh_curve prime256v1;
ssl_ciphers EECDH+AESGCM:EECDH+AES;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_certificate /home/partecipa/domains/mastodon.partecipa.digital/ssl.cert;
ssl_certificate_key /home/partecipa/domains/mastodon.partecipa.digital/ssl.key;

keepalive_timeout    70;
sendfile             on;
client_max_body_size 0;

gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

add_header Content-Security-Policy "default-src 'none'; font-src 'self'; media-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self'; img-src 'self' data:; connect-src 'self' wss://mastodon.partecipa.digital; frame-ancestors 'none';";
add_header Referrer-Policy "no-referrer";
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload;";

location / {
try_files $uri @proxy;
root /home/mastodon/live/public;
}

location ~ ^/(assets|system/media_attachments/files|system/accounts/avatars) {
add_header Cache-Control "public, max-age=31536000, immutable";
}

location @proxy {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Proxy "";
proxy_pass_header Server;
proxy_pass http://127.0.0.1:3000;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
tcp_nodelay on;
}

location /api/v1/streaming {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Proxy "";
proxy_pass http://localhost:4000;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
tcp_nodelay on;
}

error_page 500 501 502 503 504 /500.html;

}

Once you saved the file you can start Nginx:

systemctl start nginx

Or. if Nginx was already running, you can simply reload the configuration:

systemctl reload nginx

upgrades management

Upgrade Ruby

You may want to update Mastodon quite often, especially now that plenty of new features and patches are becoming available, and that may require to upgrade Ruby as well. Read carefully the release notices to check what steps or upgrades are required.

If required upgrade Ruby as follows (replace X.X.X with the version of Ruby required) :

su - mastodon
rbenv install X.X.X
rbenv global X.X.X
gem install bundler --no-ri

Then follow Mastodon's upgrade procedures.

Upgrading mastodon

Before starting any upgrades remember that backups and snapshots may help if something goes wrong.

Update your repositories and upgrade your system:

apt update && apt full-upgrade

Especially if you are installing a major release don't forget to stop Mastodon's services:

systemctl stop mastodon-web.service mastodon-sidekiq.service mastodon-streaming.service

Main commands generally used to upgrade Mastodon:

(It may not be necessary to run all the commands so check the release notes before performing an upgrade)

su - mastodon
cd live
git fetch
git checkout $(git tag | tail -n 1)
bundle install
npm upgrade yarn
yarn install
RAILS_ENV=production bundle exec rails assets:clean
RAILS_ENV=production bundle exec rails assets:precompile
RAILS_ENV=production bundle exec rails db:migrate
exit

Start Mastodon's services:

systemctl start mastodon-web.service mastodon-sidekiq.service mastodon-streaming.service

Have you found errors or you'd like to suggest improvements? Then contact the author of this article.