documentation/Running-Mastodon/Production-guide.md

379 lines
12 KiB
Markdown
Raw Normal View History

2017-01-21 22:49:08 +01:00
Production guide
================
2017-04-18 16:14:20 +02:00
The following HTTP headers 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',
```
2017-01-21 22:49:08 +01:00
## Nginx
Regardless of whether you go with the Docker approach or not, here is an example Nginx server configuration.
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.
2017-01-21 22:49:08 +01:00
```nginx
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
2017-04-05 03:43:21 +02:00
server {
listen 80;
listen [::]:80;
server_name example.com;
# Useful for Let's Encrypt
location /.well-known/acme-challenge/ { allow all; }
location / { return 301 https://$host$request_uri; }
2017-04-05 03:43:21 +02:00
}
2017-01-21 22:49:08 +01:00
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
2017-01-21 22:49:08 +01:00
server_name example.com;
2017-04-05 03:43:21 +02:00
ssl_protocols TLSv1.2;
Avoid hard-coding ciphers into configuration (#171) * Avoid hard-coding ciphers into configuration This change allows OpenSSL to choose the most appropriate available cipher(s) from the HIGH cipher suite. This is sufficient to get an A on the SSLLabs.com tests suite. If MEDIUM is allowed as well, the grade drops to a B which is still more than adequate for most deployments. This type of configuration would prevent problems such as the current inability of Tusky on Android 7 devices to connect to some Mastodon instances. The main benefit though, is this delegates the decisions about which ciphers are "good" and which ciphers are "bad" to the experts; the distribution security teams and the OpenSSL developers. If a weakness is found in a particular cipher it will get moved from HIGH to one of the lower classes (or removed entirely) and this will get deployed just like any other security update. Similarly, if new stronger ciphers are standardized (such as Curve 25519) - these will immediately become available without needing to change the configuration. Hope this helps! Note: I have not been able to test this change with Mastodon myself. I am using these settings in production elsewhere though, and they work quite well. Alternately, if people don't want to trust the OpenSSL definitions, please consider taking a look at https://wiki.mozilla.org/Security/Server_Side_TLS and implementing the recommendations from there. * Also avoid SHA1 As requested during review. :) * Fix a typo in the ssl_ciphers line I wrote !SHA1, should have written just !SHA. Very sorry about the noise.
2017-04-27 22:25:39 +02:00
ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA;
2017-04-05 03:43:21 +02:00
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
2017-01-21 22:49:08 +01:00
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;
2017-04-11 17:48:27 +02:00
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";
2017-01-21 22:49:08 +01:00
location / {
try_files $uri @proxy;
}
location ~ ^/(packs|system/media_attachments/files|system/accounts/avatars) {
2017-04-23 01:19:53 +02:00
add_header Cache-Control "public, max-age=31536000, immutable";
try_files $uri @proxy;
2017-04-23 01:19:53 +02:00
}
2017-01-21 22:49:08 +01:00
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;
2017-04-11 17:48:27 +02:00
proxy_set_header Proxy "";
2017-01-21 22:49:08 +01:00
proxy_pass_header Server;
proxy_pass http://127.0.0.1:3000;
2017-01-21 22:49:08 +01:00
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;
2017-04-11 17:48:27 +02:00
proxy_set_header Proxy "";
proxy_pass http://127.0.0.1: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;
}
2017-01-21 22:49:08 +01:00
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 -sHu mastodon`.
This command will create the user as needed:
sudo useradd --system --user-group --shell /bin/false --create-home --home /home/mastodon mastodon
home can be changed as needed
2017-01-21 22:49:08 +01:00
## General dependencies
### Ubuntu / Debian
sudo apt-get install imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev file git curl g++ libprotobuf-dev protobuf-compiler pkg-config
curl -sL https://deb.nodesource.com/setup_6.x | sudo bash -
sudo apt-get install nodejs
2017-01-21 22:49:08 +01:00
sudo npm install -g yarn
* **NOTE**: On Debian you have to first add the [Debian Backports](https://backports.debian.org/) repository to install `ffmpeg`.
2017-01-21 22:49:08 +01:00
### CentOS / RHEL
sudo yum install libxml2-devel ImageMagick libxslt-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
sudo yum group install "Development tools"
curl -sL https://rpm.nodesource.com/setup_6.x | sudo bash -
sudo yum install nodejs
sudo npm install -g yarn
2017-01-21 22:49:08 +01:00
## Redis
### Ubuntu / Debian
2017-01-21 22:49:08 +01:00
sudo apt-get install redis-server redis-tools
### CentOS / RHEL
sudo yum install redis rubygem-redis
2017-01-21 22:49:08 +01:00
## Postgres
### Ubuntu / Debian
2017-01-21 22:49:08 +01:00
sudo apt-get install postgresql postgresql-contrib
### CentOS / RHEL
sudo yum install postgresql-server postgresql postgresql-contrib postgresql-devel
Initial Setup postgres:
sudo postgresql-setup initdb
sudo systemctl start postgresql
sudo systemctl enable postgresql
### All Operating Systems:
Set up a user and database for Mastodon:
sudo -u postgres psql
In the prompt:
CREATE USER mastodon CREATEDB;
\q
### Ubuntu 16.04
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
```
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
### 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
```
2017-01-21 22:49:08 +01:00
## 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:
```
rbenv install 2.4.1
rbenv global 2.4.1
```
2017-01-21 22:49:08 +01:00
## Git
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:
2017-01-21 22:49:08 +01:00
cd ~
2017-04-04 23:45:29 +02:00
git clone https://github.com/tootsuite/mastodon.git live
2017-01-21 22:49:08 +01:00
cd live
git checkout $(git tag -l | sort -V | tail -n 1)
2017-01-21 22:49:08 +01:00
Then you can proceed to install project dependencies:
gem install bundler
bundle install --deployment --without development test
2017-04-24 15:21:23 +02:00
yarn install --pure-lockfile
2017-01-21 22:49:08 +01:00
## 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
2017-01-21 22:49:08 +01:00
2017-04-04 15:57:37 +02:00
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").
2017-01-21 22:49:08 +01:00
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.
2017-01-21 22:49:08 +01:00
## Setup
And set up the database for the first time, this will create the tables and basic data:
2017-01-21 22:49:08 +01:00
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`:
```systemd
[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`:
```systemd
[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
2017-01-21 22:49:08 +01:00
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`:
```systemd
[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
```
2017-04-03 00:10:51 +02:00
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.
2017-01-21 22:49:08 +01:00
## Cronjobs
2017-04-13 06:57:04 +02:00
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
2017-01-21 22:49:08 +01:00
```sh
RAILS_ENV=production
@daily cd /home/mastodon/live && /home/mastodon/.rbenv/shims/bundle exec rake mastodon:daily > /dev/null
2017-04-13 06:57:04 +02:00
```
2017-01-21 22:49:08 +01:00
## 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:
```sh
2017-04-20 02:17:52 +02:00
cd ~mastodon/live/
git fetch
git checkout $(git tag -l | sort -V | tail -n 1)
```
As part of your deploy, you may need to run:
2017-01-21 22:49:08 +01:00
- `RAILS_ENV=production bundle exec rails db:migrate`
if anything in the `/db/` directory has changed, and/or
2017-04-24 15:21:23 +02:00
- `yarn install --pure-lockfile`
2017-01-21 22:49:08 +01:00
- `RAILS_ENV=production bundle exec rails assets:precompile`
if anything in the `/app/assets` directory changed.
2017-04-20 02:17:52 +02:00
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:
2017-01-21 22:49:08 +01:00
```sh
2017-01-21 22:49:08 +01:00
sudo systemctl restart mastodon-*.service
```