Mastodon-documentation/Running-Mastodon/Production-guide.md
Erwan Leboucher 0b5cb11d08 Use the united command for daily task (#81)
commit of mastodon here e17f9d5e1a
2017-04-17 17:13:15 +02:00

8,2 KiB

Production guide

The following HTTP readers are already set internally and should not be set again:

'Server'                 => 'Mastodon',
'X-Frame-Options'        => 'DENY',
'X-Content-Type-Options' => 'nosniff',
'X-XSS-Protection'       => '1; mode=block',

Nginx

Regardless of whether you go with the Docker approach or not, here is an example Nginx server configuration:

map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

server {
  listen 80;
  listen [::]:80;
  server_name example.com;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  server_name example.com;

  ssl_protocols TLSv1.2;
  ssl_ciphers EECDH+AESGCM:EECDH+AES;
  ssl_ecdh_curve prime256v1;
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;

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

  keepalive_timeout    70;
  sendfile             on;
  client_max_body_size 0;

  root /home/mastodon/live/public;

  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 Strict-Transport-Security "max-age=31536000";

  location / {
    try_files $uri @proxy;
  }

  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;
}

Running in production without Docker

It is recommended to create a special user for mastodon on the server (you could call the user mastodon), though remember to disable outside login for it. You should only be able to get into that user through sudo su - mastodon.

General dependencies

sudo apt-get install imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev nodejs file git curl
curl -sL https://deb.nodesource.com/setup_4.x | sudo bash -

sudo apt-get install nodejs

sudo npm install -g yarn

Redis

sudo apt-get install redis-server redis-tools

Postgres

sudo apt-get install postgresql postgresql-contrib

Set up a user and database for Mastodon:

sudo su - postgres
psql

In the prompt:

CREATE USER mastodon CREATEDB;
\q

Under Ubuntu 16.04, you will need to explicitly enable ident authentication so that local users can connect to the database without a password:

sudo sed -i '/^local.*postgres.*peer$/a host    all     all     127.0.0.1/32    ident' /etc/postgresql/9.?/main/pg_hba.conf

and install an ident daemon, which does not come installed by default:

sudo apt-get install pidentd
sudo systemctl enable pidentd
sudo systemctl start pidentd
sudo systemctl restart postgresql

Rbenv

It is recommended to use rbenv (exclusively from the mastodon user) to install the desired Ruby version. Follow the guides to install rbenv and rbenv-build (I recommend checking the prerequisites for your system on the rbenv-build project and installing them beforehand, obviously outside the unprivileged mastodon user)

Then once rbenv is ready, run rbenv install 2.4.1 to install the Ruby version for Mastodon.

Git

You need the git-core package installed on your system. If it is so, from the mastodon user:

cd ~
git clone https://github.com/tootsuite/mastodon.git live
cd live
git checkout $(git tag | tail -n 1)

Then you can proceed to install project dependencies:

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

Configuration

Then you have to configure your instance:

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

Fill in the important data, like host/port of the redis database, host/port/username/password of the postgres database, your domain name, SMTP details (e.g. from Mailgun or equivalent transactional e-mail service, many have free tiers), whether you intend to use SSL, etc. If you need to generate secrets, you can use:

rake secret

To get a random string. If you are setting up on one single server (most likely), then REDIS_HOST is localhost and DB_HOST is /var/run/postgresql, DB_USER is mastodon and DB_NAME is mastodon_production while DB_PASS is empty because this setup will use the ident authentication method (system user "mastodon" maps to postgres user "mastodon").

Setup

And set up the database for the first time, this will create the tables and basic data:

RAILS_ENV=production bundle exec rails db:setup

Finally, pre-compile all CSS and JavaScript files:

RAILS_ENV=production bundle exec rails assets:precompile

Systemd

Example systemd configuration for the web workers, to be placed in /etc/systemd/system/mastodon-web.service:

[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

Example systemd configuration for the background workers, to be placed in /etc/systemd/system/mastodon-sidekiq.service:

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

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

[Install]
WantedBy=multi-user.target

Example systemd configuration file for the streaming API, to be placed in /etc/systemd/system/mastodon-streaming.service:

[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

This allows you to sudo systemctl enable /etc/systemd/system/mastodon-*.service and sudo systemctl start mastodon-web.service mastodon-sidekiq.service mastodon-streaming.service to get things going.

Cronjobs

There are several tasks that should be run once a day to ensure that mastodon is running smoothly. As your mastodon user run crontab -e and enter the following

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

Things to look out for when upgrading Mastodon

You can upgrade Mastodon with a git fetch; git checkout $(git tag | tail -n 1) from the repository directory. You may need to run:

  • RAILS_ENV=production bundle exec rails db:migrate
  • RAILS_ENV=production bundle exec rails assets:precompile

Depending on which files changed, e.g. if anything in the /db/ or /app/assets directory changed, respectively. Also, Mastodon runs in memory, so you need to restart it before you see any changes. If you're using systemd, that would be:

sudo systemctl restart mastodon-*.service