Browse Source

Complete rewrite of Mastodon Production Guide (#352)

* Complete re-write of Mastodon Production Guide

I re-wrote the Mastodon Production Guide so that it has a better structure.

Work on this re-write was done on my own repo:
https://github.com/staticsafe/mastodon-documentation

* Fix typo in a heading

* Change node.js Repository section to use curl|bash method.
For simplicity's sake

* Add an explanation of the dependencies
Added in the "Various Other Dependencies" section.

* Fix links to the Ruby project, was using the link to Rails previously.
Sadiq Saif 6 years ago
parent
commit
88b89e61d9
1 changed files with 299 additions and 209 deletions
  1. 299 209
      Running-Mastodon/Production-guide.md

+ 299 - 209
Running-Mastodon/Production-guide.md

@@ -1,20 +1,190 @@
-Production guide
-================
+# Mastodon Production Guide
 
-The following HTTP headers are already set internally and should not be set again:
+**Disclaimer:**
 
+This guide was written for [Ubuntu Server 16.04](https://www.ubuntu.com/server), you may run into issues if you are using another operating system. We are welcoming contributions for guides to other distributions.
+
+This document is also written with the expectation that you have a technical level high enough to administrate Linux servers.
+
+## What is this guide?
+
+This guide is a walk through of the setup process of a [Mastodon](https://github.com/tootsuite/mastodon/) instance.
+
+We use example.com to represent a domain or sub-domain. Example.com should be replaced with your instance domain or sub-domain.
+
+## Prerequisites
+
+You will need the following for this guide:
+
+- A server running [Ubuntu Server 16.04](https://www.ubuntu.com/server).
+- Root access to the server.
+- A domain or sub-domain to use for the instance.
+
+## DNS
+
+DNS records should be added before anything is done on the server.
+
+The records added are:
+
+-  A record (IPv4 address) for example.com
+-  AAAA record (IPv6 address) for example.com
+
+> ### A Helpful And Optional Note
+>
+> Using `tmux` when following through with this guide will be helpful.
+>
+>
+> Not only will this help you not lose your place if you are disconnected, it will let you have multiple terminal windows open for switching contexts (root user versus the mastodon user).
+>
+> You can install [tmux](https://github.com/tmux/tmux/wiki) from the package manager:
+>
+> ```sh
+> apt -y install tmux
+> ```
+
+## Dependency Installation
+
+All dependencies should be installed as root.
+
+### node.js Repository
+
+You will need to add an external repository so we can have the version of [node.js](https://nodejs.org/en/) required.
+
+We run this script to add the repository:
+
+```sh
+curl -sL https://deb.nodesource.com/setup_6.x | bash -
+```
+
+The [node.js](https://nodejs.org/en/) repository is now added.
+
+###  Yarn Repository
+
+Another repository needs to be added so we can get the version of [Yarn](https://yarnpkg.com/en/) used by [Mastodon](https://github.com/tootsuite/mastodon/).
+
+This is how you add the repository:
+
+```sh
+apt -y install curl
+curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
+echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
+apt update
+```
+
+### Various Other Dependencies
+
+Now you need to install [Yarn](https://yarnpkg.com/en/) plus some more software.
+
+#### Explanation of the dependencies
+
+- imagemagick - Mastodon uses imagemagick for image related operations
+- ffmpeg - Mastodon uses ffmpeg for conversion of GIFs to MP4s
+- libprotobuf-dev and protobuf-compiler - Mastodon uses these for language detection
+- nginx - nginx is our frontend web server
+- redis-* - Mastodon uses redis for its in-memory data structure store
+- postgresql-* - Mastodon uses PostgreSQL as it's SQL database
+- nodejs - Node is used for Mastodon's streaming API
+- yarn - Yarn is a Node.js package manager
+- Other -dev packages, g++ - these are needed for the compilation of Ruby using ruby-build.
+
+```sh
+apt -y install imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev file git g++ libprotobuf-dev protobuf-compiler pkg-config nodejs gcc-6 autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm3 libgdbm-dev nginx redis-server redis-tools postgresql postgresql-contrib nginx letsencrypt yarn
+```
+
+### Dependencies That Need To Be Added As A Non-Root User
+
+Let us create this user first:
+
+```sh
+adduser mastodon
+```
+
+Log in as the `mastodon` user:
+
+
+```sh
+su - mastodon
 ```
-'Server'                 => 'Mastodon',
-'X-Frame-Options'        => 'DENY',
-'X-Content-Type-Options' => 'nosniff',
-'X-XSS-Protection'       => '1; mode=block',
+
+We will need to set up [`rbenv`](https://github.com/rbenv/rbenv) and [`ruby-build`](https://github.com/rbenv/ruby-build):
+
+```sh
+git clone https://github.com/rbenv/rbenv.git ~/.rbenv
+cd ~/.rbenv && src/configure && make -C src
+echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
+# Restart shell
+exec bash
+# Check if rbenv is correctly installed
+type rbenv
+# Install ruby-build as rbenv plugin
+git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
+```
+
+Now that [`rbenv`](https://github.com/rbenv/rbenv) and [`ruby-build`](https://github.com/rbenv/ruby-build) are installed, we will install the
+[Ruby](https://www.ruby-lang.org/en/) version which [Mastodon](https://github.com/tootsuite/mastodon/) uses. That version will also need to be enabled.
+
+To enable [Ruby](https://www.ruby-lang.org/en/), run:
+
+```sh
+rbenv install 2.4.1
+rbenv global 2.4.1
+```
+
+**This will take some time. Go stretch for a bit and drink some water while the commands run.**
+
+### node.js And Ruby Dependencies
+
+Now that [Ruby](https://www.ruby-lang.org/en/) is enabled, we will clone the [Mastodon git repository](https://github.com/tootsuite/mastodon/) and install the [Ruby](https://www.ruby-lang.org/en/) and [node.js](https://nodejs.org/en/) dependancies.
+
+Run the following to clone and install:
+
+```sh
+# Return to mastodon user's home directory
+cd ~
+# Clone the mastodon git repository into ~/live
+git clone https://github.com/tootsuite/mastodon.git live
+# Change directory to ~live
+cd ~/live
+# Checkout to the latest stable branch
+git checkout $(git tag -l | sort -V | tail -n 1)
+# Install bundler
+gem install bundler
+# Use bundler to install the rest of the Ruby dependencies
+bundle install --deployment --without development test
+# Use yarn to install node.js dependencies
+yarn install --pure-lockfile
 ```
 
-## Nginx
+That is all we need to do for now with the `mastodon` user, you can now `exit` back to root.
 
-Regardless of whether you go with the Docker approach or not, here is an example Nginx server configuration.
+## PostgreSQL Database Creation
 
-At a minimum, you'll want to replace any occurrence of `example.com` with your actual hostname, and `/home/mastodon/live/public` with the location of your actual mastodon `public/` directory.
+[Mastodon](https://github.com/tootsuite/mastodon/) requires access to a [PostgreSQL](https://www.postgresql.org) instance.
+
+Create a user for a [PostgreSQL](https://www.postgresql.org) instance:
+
+```
+# Launch psql as the postgres user
+sudo -u postgres psql
+
+# In the following prompt
+CREATE USER mastodon CREATEDB;
+\q
+```
+
+**Note** that we do not set up a password of any kind, this is because we will be using ident authentication. This allows local users to access the database without a password.
+
+## nginx Configuration
+
+You need to configure [nginx](http://nginx.org) to serve your [Mastodon](https://github.com/tootsuite/mastodon/) instance.
+
+**Reminder: Replace all occurrences of example.com with your own instance's domain or sub-domain.**
+
+`cd` to `/etc/nginx/sites-available` and open a new file:
+
+`nano /etc/nginx/sites-available/example.com.conf`
+
+Copy and paste the following and make edits as necessary:
 
 ```nginx
 map $http_upgrade $connection_upgrade {
@@ -109,172 +279,161 @@ server {
 }
 ```
 
-## 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 -sHu mastodon`.
-
-This command will create the user as needed:
+Activate the [nginx](http://nginx.org) configuration added:
 
-    sudo useradd --system --user-group --shell /bin/false --create-home --home /home/mastodon mastodon
+```sh
+cd /etc/nginx/sites-enabled
+ln -s ../sites-available/example.com.conf
+```
 
-home can be changed as needed
+This configuration makes the assumption you are using [Let's Encrypt](https://letsencrypt.org) as your TLS certificate provider.
 
+**If you are going to be using Let's Encrypt as your TLS certificate provider, see the
+next sub-section. If not edit the `ssl_certificate` and `ssl_certificate_key` values
+accordingly.**
 
-## General dependencies
+## Let's Encrypt
 
-### Ubuntu / Debian
+This section is only relevant if you are using [Let's Encrypt](https://letsencrypt.org/)
+as your TLS certificate provider.
 
-    sudo apt-get install imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev libreadline-dev file git curl build-essential libprotobuf-dev protobuf-compiler pkg-config
-    curl -sL https://deb.nodesource.com/setup_6.x | sudo bash -
-    curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
-    echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
-    sudo apt-get update
-    sudo apt-get install nodejs yarn
+### Generation Of The Certificate
 
-* **NOTE**: On Debian you have to first add the [Debian Backports](https://backports.debian.org/) repository to install `ffmpeg`.
+We need to generate Let's Encrypt certificates.
 
-### CentOS / RHEL
+**Make sure to replace any occurrence of 'example.com' with your Mastodon instance's domain.**
 
-    sudo yum install libxml2-devel ImageMagick libxslt-devel readline-devel git curl file protobuf-compiler protobuf-devel
-    sudo yum -y install epel-release
-    sudo rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
-    sudo rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm
-    sudo yum -y install ffmpeg ffmpeg-devel
+Make sure that [nginx](http://nginx.org) is stopped at this point:
 
-    sudo yum group install "Development tools"
-    curl -sL https://rpm.nodesource.com/setup_6.x | sudo bash -
-    sudo wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo
-    sudo yum install nodejs yarn
+```sh
+systemctl stop nginx
+```
 
-## Redis
+We will be creating the certificate twice, once with TLS SNI validation in standalone mode and the second time we will be using the webroot method. This is required due to the way
+[nginx](http://nginx.org) and the [Let's Encrypt](https://letsencrypt.org/) tool works.
 
-### Ubuntu / Debian
+```sh
+letsencrypt certonly --standalone -d example.com
+```
 
-    sudo apt-get install redis-server redis-tools
+After that successfully completes, we will use the webroot method. This requires [nginx](http://nginx.org) to be running:
 
-### CentOS / RHEL
+```sh
+systemctl start nginx
+# The letsencrypt tool will ask if you want issue a new cert, please choose that option
+letsencrypt certonly --webroot -d example.com -w /home/mastodon/live/public/
+```
 
-    sudo yum install redis rubygem-redis
+### Automated Renewal Of Let's Encrypt Certificate
 
-## Postgres
+[Let's Encrypt](https://letsencrypt.org/) certificates have a validity period of 90 days.
 
-### Ubuntu / Debian
+You need to renew your certificate before the expiration date. Not doing so will make users of your instance unable to access the instance and users of other instances unable to federate with yours.
 
-    sudo apt-get install postgresql postgresql-contrib
+We can create a cron job that runs daily to do this:
 
-### CentOS / RHEL
+```sh
+nano /etc/cron.daily/letsencrypt-renew
+```
 
-    sudo yum install postgresql-server postgresql postgresql-contrib postgresql-devel
+Copy and paste this script into that file:
 
-Initial Setup postgres:
+```sh
+#!/usr/bin/env bash
+letsencrypt renew
+systemctl reload nginx
+```
 
-    sudo postgresql-setup initdb
-    sudo systemctl start postgresql
-    sudo systemctl enable postgresql
+Save and exit the file.
 
-### All Operating Systems:
+Make the script executable and restart the cron daemon so that the script runs daily:
 
-Set up a user and database for Mastodon:
+```sh
+chmod +x /etc/cron.daily/letsencrypt-renew
+systemctl restart cron
+```
 
-    sudo -u postgres psql
+That is it. Your server will renew your [Let's Encrypt](https://letsencrypt.org/) certificate.
 
-In the prompt:
+## Mastodon Application Configuration
 
-    CREATE USER mastodon CREATEDB;
-    \q
+We will configure the Mastodon application.
 
-### Ubuntu 16.04
+For this we will switch to the `mastodon` system user:
 
-Under Ubuntu 16.04, you will need to explicitly enable ident authentication so that local users can connect to the database without a password:
 
 ```sh
-    sudo sed -i '/^local.*postgres.*peer$/a host    all     all     127.0.0.1/32    ident' /etc/postgresql/9.?/main/pg_hba.conf
+su - mastodon
 ```
 
-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
+Change directory to `~live` and edit the [Mastodon](https://github.com/tootsuite/mastodon/) application configuration:
 
-### Debian 8
-
-Under Debian 8, the default version of nginx available is too old to work with the above configuration file (as it uses http2). To install a newer version of nginx that supports http2 (v1.9.5+), you have to add the jessie-backports repo to your `sources.list.d`:
-
-```bash
-$ echo "deb http://ftp.debian.org/debian/ jessie-backports main" | sudo tee /etc/apt/sources.list.d/backports.list
-$ sudo apt-get update
-$ sudo apt-get install -t jessie-backports nginx
+```sh
+cd ~/live
+cp .env.production.sample .env.production
+nano .env.production
 ```
 
-## Rbenv
-
-It is recommended to use rbenv (exclusively from the `mastodon` user) to install the desired Ruby version. Follow the guides to [install rbenv][1] and [rbenv-build][2] (I recommend checking the [prerequisites][3] for your system on the rbenv-build project and installing them beforehand, obviously outside the unprivileged `mastodon` user)
-
-[1]: https://github.com/rbenv/rbenv#installation
-[2]: https://github.com/rbenv/ruby-build#installation
-[3]: https://github.com/rbenv/ruby-build/wiki#suggested-build-environment
-
-Then once `rbenv` is ready, install and enable the Ruby version for Mastodon using:
+For the purposes of this guide, these are the values to be edited:
 
 ```
-rbenv install 2.4.1
-rbenv global 2.4.1
+# Your Redis host
+REDIS_HOST=127.0.0.1
+# Your Redis port
+REDIS_PORT=6379
+# Your PostgreSQL host
+DB_HOST=/var/run/postgresql
+# Your PostgreSQL user
+DB_USER=mastodon
+# Your PostgreSQL DB name
+DB_NAME=mastodon_production
+# Leave DB password empty
+DB_PASS=
+# Your DB_PORT
+DB_PORT=5432
+
+# Your instance's domain
+LOCAL_DOMAIN=example.com
+# We have HTTPS enabled
+LOCAL_HTTPS=true
+
+# Application secrets
+# Generate each eith `RAILS_ENV=production bundle exec rake secret`
+PAPERCLIP_SECRET=
+SECRET_KEY_BASE=
+OTP_SECRET=
+
+# All SMTP details, Mailgun and Sparkpost have free tiers
+SMTP_SERVER=
+SMTP_PORT=
+SMTP_LOGIN=
+SMTP_PASSWORD=
+SMTP_FROM_ADDRESS=
 ```
 
-## Git
+We now need to set up the [PostgreSQL](https://www.postgresql.org) database for the first time:
 
-You need the `git-core` package installed on your system. If it is so, run the shell from the `mastodon` user:
-
-    sudo -sHu mastodon
-
-And enter the following commands:
-
-    cd ~
-    git clone https://github.com/tootsuite/mastodon.git live
-    cd live
-    git checkout $(git tag -l | sort -V | tail -n 1)
-
-Then you can proceed to install project dependencies:
-
-    gem install bundler
-    bundle install --deployment --without development test
-    yarn install --pure-lockfile
-
-## 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:
-
-    RAILS_ENV=production bundle exec 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").
-
-Configuring the instance hostname:
-
-- `LOCAL_DOMAIN` should be the domain/hostname of your instance. This is **absolutely required** as it is used for generating unique IDs for everything federation-related.
-- `LOCAL_HTTPS` set it to `true` if HTTPS works on your website. This is used to generate canonical URLs, which is also important when generating and parsing federation-related IDs.
+```sh
+RAILS_ENV=production bundle exec rails db:setup
+```
 
-## Setup
+Then we will need to precompile all CSS and JavaScript files:
 
-And set up the database for the first time, this will create the tables and basic data:
+```sh
+RAILS_ENV=production bundle exec rails assets:precompile
+```
 
-    RAILS_ENV=production bundle exec rails db:setup
+**The assets precompilation takes a couple minutes, so this is a good time to take another break.**
 
-Finally, pre-compile all CSS and JavaScript files:
+## Mastodon systemd Service Files
 
-    RAILS_ENV=production bundle exec rails assets:precompile
+We will need three [systemd](https://github.com/systemd/systemd) service files for each Mastodon service.
 
-## Systemd
+Now switch back to the root user.
 
-Example systemd configuration for the web workers, to be placed in `/etc/systemd/system/mastodon-web.service`:
+For the [Mastodon](https://github.com/tootsuite/mastodon/) web workers service place the following in `/etc/systemd/system/mastodon-web.service`:
 
-```systemd
+```
 [Unit]
 Description=mastodon-web
 After=network.target
@@ -293,9 +452,9 @@ Restart=always
 WantedBy=multi-user.target
 ```
 
-Example systemd configuration for the background workers, to be placed in `/etc/systemd/system/mastodon-sidekiq.service`:
+For [Mastodon](https://github.com/tootsuite/mastodon/) background queue service, place the following in `/etc/systemd/system/mastodon-sidekiq.service`:
 
-```systemd
+```
 [Unit]
 Description=mastodon-sidekiq
 After=network.target
@@ -314,9 +473,9 @@ Restart=always
 WantedBy=multi-user.target
 ```
 
-Example systemd configuration file for the streaming API, to be placed in `/etc/systemd/system/mastodon-streaming.service`:
+For the [Mastodon](https://github.com/tootsuite/mastodon/) streaming API service place the following in `/etc/systemd/system/mastodon-streaming.service`:
 
-```systemd
+```
 [Unit]
 Description=mastodon-streaming
 After=network.target
@@ -335,89 +494,20 @@ Restart=always
 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.
+Now you need to enable all of these services:
 
-## Let's Encrypt
-
-This section is only relevant if you are using [Let's Encrypt](https://letsencrypt.org/)
-as your TLS certificate provider.
-
-Other assumptions - Ubuntu 16.04, letsencrypt tool installed from distro repositories.
-
-### Installation of tool
-
-This is how you install the `letsencrypt` package:
-
-`sudo apt -y install letsencrypt`
-
-### Generation of certificate
-
-This is the command you should use to generate a Let's Encrypt certificate.
-Make sure to replace any instances of 'example.com' with your Mastodon instance's domain.
-
-Additional note: This command will require that nginx or another web server is correctly
-configured with your Mastodon instance's domain.
-
-`letsencrypt certonly --webroot -d example.com -w /home/mastodon/live/public/`
-
-### Automated renewal of Let's Encrypt certificate
-
-Let's Encrypt certificates have a validity period of 90 days.
-
-You need to renew your certificate before the expiration date. Failure to do so will
-result in your users being unable to access your instance and other instances being unable 
-to federate with yours.
-
-We can do this with a cron job that runs daily:
-
-`nano /etc/cron.daily/letsencrypt-renew`
-
-Copy and paste this script into that file:
-
-```
-#!/usr/bin/env bash
-letsencrypt renew
-systemctl reload nginx
-```
-
-Save and exit the file.
-
-Make the script executable and restart the cron daemon so that the script runs daily:
-```
-chmod +x /etc/cron.daily/letsencrypt-renew
-systemctl restart cron
+```sh
+systemctl enable /etc/systemd/system/mastodon-*.service
 ```
 
-That is it. Your server will now automatically renew your Let's Encrypt certificate(s).
-
-## Things to look out for when upgrading Mastodon
-
-If you want a stable release for production use, you should use tagged releases. To checkout the latest available tagged version:
+Now start the services:
 
 ```sh
-    cd ~mastodon/live/
-    git fetch
-    git checkout $(git tag -l | sort -V | tail -n 1)
+systemctl start mastodon-web.service
+systemctl start mastodon-sidekiq.service
+systemctl start mastodon-streaming.service
 ```
 
-As part of your deploy, you may need to run:
-
-- `RAILS_ENV=production bundle exec rails db:migrate`
-
-if anything in the `/db/` directory has changed, and/or
-
-- `yarn install --pure-lockfile`
-- `RAILS_ENV=production bundle exec rails assets:precompile`
+That is all! If everything was done correctly, a [Mastodon](https://github.com/tootsuite/mastodon/) instance will appear when you visit `https://example.com` in a web browser.
 
-if anything in the `/app/assets` directory changed.
-
-Please read the [**release notes**](https://github.com/tootsuite/mastodon/releases/) when you upgrade,
-they might contain specific instructions about how to update (and they always include information
-about which new features the release has, and which bugs are fixed).
-
-Also, Mastodon runs in memory, so you need to restart it before you see any changes (including new
-precompiled assets). If you're using systemd, that would be:
-
-```sh
-    sudo systemctl restart mastodon-*.service
-```
+Congratulations and welcome to the fediverse!