Edited at

Ubuntu16.04にDockerでMastodonインスタンスを立てる

More than 1 year has passed since last update.


はじめに

Dockerの勉強がてらに、今更感がありますが、Mastodonのインスタンスを立ててみました。

リバースプロキシや、サーバ証明書の自動更新をすべてDockerで

動かしたかったので以下の記事を参考にさせていただきました。

Docker🐳でMastodon🐘のインスタンスを立てるドン

リバースプロキシ + https + 全てコンテナ、な Mastodon インスタンス(無料)を構築してみたメモ

構築にあたっては、基本的に、ほとんど参考記事に従っただけですが、異なる部分や、何点かハマッたポイントもありましたので、備忘録として残しておこうと思います。


0. 前提条件


0.1. 環境


  • サーバ:さくらVPS

  • OS:Ubuntu16.04

  • Mastodon:v1.3.3


0.2. 構築のポイント


  • Nginxによるリバースプロキシを立てる

  • Let's Encrypt によるサーバ証明書自動更新を行う

  • 上記を含め、すべてDockerで動かす

  • メールは手抜きでGmailを使用


0.3. 注意点


  • 証明書を取得するのに、Aレコードに登録した独自ドメインが必要。

  • Let's Encryptには証明書作成の制限がある。
     (知らずに作って潰して繰り返してたら制限掛かった)

  • Mastodonは、バージョンタグを指定してcheckoutする。


1. 事前準備


1.1. ポートの開放

$ sudo iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT

$ sudo iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT


1.2. Dockerのインストール

$ sudo apt-get install apt-transport-https ca-certificates curl software-properties-common

$ sudo apt-get install apt-transport-https \
 ca-certificates curl software-properties-common

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add
$ sudo add-apt-repository \
 "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable"

$ sudo apt-get update
$ sudo apt-get install docker-ce
$ sudo apt-get upgrade
$ sudo docker run hello-world

$ sudo groupadd docker
$ sudo usermod -aG docker $USER
$ exit
$ docker run hello-world
$ sudo systemctl enable docker


1.3. Docker-composeのインストール

$ sudo -i

$ curl -L https://github.com/docker/compose/releases/download/1.12.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose
$ exit


1.4. Dockerネットワークを作成する

フロント(リバースプロキシ)側と

Mastodon側のDockerネットワークをそれぞれ作成します。

$ docker network create --driver bridge front

$ docker network create --driver bridge back-mstdn


2. リバースプロキシの設定と起動

ホームディレクトリ配下にproxyというディレクトリを作成し、

その中にまとめました。


2.1. docker-compose.ymlを作成する

#ディレクトリを作成

$ sudo mkdir -p proxy
$ cd proxy

#ファイルを新規で作成して編集
$ sudo vi docker-compose.yml

docker-compose.ymlの内容は以下の通り。

これはどんな環境でも変わりはなさそうです。


~/proxy/docker-compose.yml

version: '2'

services:
proxy:
image: jwilder/nginx-proxy:alpine
container_name: proxy-nginx
ports:
- 80:80
- 443:443
restart: always
tty: false
privileged: true
volumes:
- ./certs:/etc/nginx/certs:ro
- /var/run/docker.sock:/tmp/docker.sock:ro
- /etc/nginx/vhost.d
- /usr/share/nginx/html
networks:
- front

letsencrypt:
image: jrcs/letsencrypt-nginx-proxy-companion
container_name: proxy-letsencrypt
restart: always
tty: false
privileged: true
volumes:
- ./certs:/etc/nginx/certs:rw
- /var/run/docker.sock:/var/run/docker.sock:ro
volumes_from:
- proxy
networks:
- front

networks:
front:
external: true



2.2. コンテナ起動

$ docker-compose up -d

#起動後のプロセスやログを確認する場合
以下のコマンドを実行する。
$ docker-compose ps
$ docker-compose logs -f


3. Mastdonのビルドする

他のアプリケーションを動かす場合に備えて、

ホームディレクトリ配下にappsディレクトリをして、

その中にまとめる。


3.1. Mastodonのクローン

$ sudo mkdir ~/apps

$ cd ~/apps
$ sudo git clone https://github.com/tootsuite/mastodon.git


3.2 Mastodonのビルド

注意点は、きちんとバージョンタグを指定してチェックアウトすること。

タイミングが悪いと、何やっても動かなかったりします。

以下はv1.3.3の例です。

$ cd mastodon

#バージョンタグの確認
$ git tag -l

#バージョン指定
$ sudo git checkout refs/tags/v1.3.3

#環境変数ファイルのコピー
$ sudo cp .env.production.sample .env.production

#ビルド実行
$ docker-compose build


4. Mastodonの設定


4.1. 環境変数ファイルの編集

以下のコマンドを三回実行して、それぞれ出力された値をメモしておく。

$ docker-compose run --rm web rake secret

続いて、環境変数ファイルを編集する。

$ sudo vi .env.production

ファイルの内容は以下の通り。

【】内を自身の環境に合わせて編集して下さい。


~/apps/mastodon/.env.production

VIRTUAL_HOST=【自分のドメイン】

VIRTUAL_PORT=9090
VIRTUAL_PROTO=https
LETSENCRYPT_HOST=【自分のドメイン】
LETSENCRYPT_EMAIL=【自分のメールアドレス】
LETSENCRYPT_TEST=false

# Service dependencies
# You may set REDIS_URL instead for more advanced options
REDIS_HOST=redis
REDIS_PORT=6379
# You may set DATABASE_URL instead for more advanced options
DB_HOST=db
DB_USER=postgres
DB_NAME=postgres
DB_PASS=
DB_PORT=5432

# Federation
LOCAL_DOMAIN=【自分のドメイン】
LOCAL_HTTPS=true

# Use this only if you need to run mastodon on a different domain than the one used for federation.
# You can read more about this option on https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Serving_a_different_domain.md
# DO *NOT* USE THIS UNLESS YOU KNOW *EXACTLY* WHAT YOU ARE DOING.
# WEB_DOMAIN=mastodon.example.com

# Application secrets
# Generate each with the `rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose)
PAPERCLIP_SECRET=【3.3でコマンド実行して1回目に出力された値】
SECRET_KEY_BASE=【3.3でコマンド実行して2回目に出力された値】
OTP_SECRET=【3.3でコマンド実行して3回目に出力された値】

# Registrations
# Single user mode will disable registrations and redirect frontpage to the first profile
# SINGLE_USER_MODE=true
# Prevent registrations with following e-mail domains
# EMAIL_DOMAIN_BLACKLIST=example1.com|example2.de|etc
# Only allow registrations with the following e-mail domains
# EMAIL_DOMAIN_WHITELIST=example1.com|example2.de|etc

# Optionally change default language
DEFAULT_LOCALE=ja

# E-mail configuration
# Note: Mailgun and SparkPost (https://sparkpo.st/smtp) each have good free tiers
# If you want to use an SMTP server without authentication (e.g local Postfix relay)
# then set SMTP_AUTH_METHOD to 'none' and *comment* SMTP_LOGIN and SMTP_PASSWORD.
# Leaving them blank is not enough for authentication method 'none'.
SMTP_SERVER=smtp.gmail.com
SMTP_PORT=587
SMTP_OPENSSL_VERIFY_MODE=none
SMTP_LOGIN=【自分のメールアドレス※ユーザ登録時の送信元になる】
SMTP_PASSWORD=【Gmailのパスワード】
SMTP_FROM_ADDRESS=【自分のメールアドレス※ユーザ登録時の送信元になる】
SMTP_DOMAIN=gmail.com
#SMTP_DELIVERY_METHOD=smtp # delivery method can also be sendmail
#SMTP_AUTH_METHOD=plain
#SMTP_CA_FILE=/etc/ssl/certs/ca-certificates.crt
#SMTP_OPENSSL_VERIFY_MODE=peer
#SMTP_ENABLE_STARTTLS_AUTO=true

# Optional user upload path and URL (images, avatars). Default is :rails_root/public/system. If you set this variable, you are responsible for making your HTTP server (eg. nginx) serve these files.
# PAPERCLIP_ROOT_PATH=/var/lib/mastodon/public-system
# PAPERCLIP_ROOT_URL=/system

# Optional asset host for multi-server setups
# CDN_HOST=assets.example.com

# S3 (optional)
# S3_ENABLED=true
# S3_BUCKET=
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=
# S3_REGION=
# S3_PROTOCOL=http
# S3_HOSTNAME=192.168.1.123:9000

# S3 (Minio Config (optional) Please check Minio instance for details)
# S3_ENABLED=true
# S3_BUCKET=
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=
# S3_REGION=
# S3_PROTOCOL=https
# S3_HOSTNAME=
# S3_ENDPOINT=
# S3_SIGNATURE_VERSION=

# Optional alias for S3 if you want to use Cloudfront or Cloudflare in front
# S3_CLOUDFRONT_HOST=

# Streaming API integration
# STREAMING_API_BASE_URL=

# Advanced settings
# If you need to use pgBouncer, you need to disable prepared statements:
# PREPARED_STATEMENTS=false

# Cluster number setting for streaming API server.
# If you comment out following line, cluster number will be `numOfCpuCores - 1`.
STREAMING_CLUSTER_NUM=1



4.2. Mastodonのdocker-compose.ymlを編集

$ sudo vi docker-compose.yml

ファイルの内容は以下の通り。


~/apps/mastodon/docker-compose.yml

version: '2'

services:
nginx:
image: nginx:1.11.10-alpine
container_name: mstdn-nginx
ports:
- "9090:9090"
restart: always
tty: false
env_file: .env.production
links:
- web
- streaming
volumes:
- ./setting/nginx/conf.d:/etc/nginx/conf.d:ro
- ./setting/nginx/conf:/etc/nginx/conf:ro
volumes_from:
- container:proxy-nginx
networks:
- front
- back-mstdn

db:
restart: always
image: postgres:alpine
container_name: mstdn-db
volumes:
- ./postgres:/var/lib/postgresql/data
networks:
- back-mstdn

redis:
restart: always
image: redis:alpine
container_name: mstdn-redis
volumes:
- ./redis:/data
networks:
- back-mstdn

web:
restart: always
build: .
image: gargron/mastodon
container_name: mstdn-web
env_file: .env.production
command: bundle exec rails s -p 3000 -b '0.0.0.0'
ports:
- "3000:3000"
depends_on:
- db
- redis
volumes:
- ./public/assets:/mastodon/public/assets
- ./public/system:/mastodon/public/system
networks:
- back-mstdn

streaming:
restart: always
build: .
image: gargron/mastodon
container_name: mstdn-streaming
env_file: .env.production
command: npm run start
ports:
- "4000:4000"
depends_on:
- db
- redis
networks:
- back-mstdn

sidekiq:
restart: always
build: .
image: gargron/mastodon
container_name: mstdn-sidekick
env_file: .env.production
command: bundle exec sidekiq -q default -q mailers -q pull -q push
depends_on:
- db
- redis
volumes:
- ./public/system:/mastodon/public/system
networks:
- back-mstdn

networks:
front:
external: true
back-mstdn:
external: true



4.3. Nginxの設定ファイルを新規作成

ディレクトリを作成して、ファイルを編集する。

$ sudo mkdir -p setting/nginx/conf.d

$ sudo vi setting/nginx/conf.d/default.conf

ファイルの内容は以下の通り。


~/apps/mastodon/setting/nginx/conf.d/default.conf

map $http_upgrade $connection_upgrade {

default upgrade;
'' close;
}

server {
listen 9090 ssl;
server_name 【自分のドメイン】;

ssl_protocols TLSv1.2;
ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_ecdh_curve prime256v1;

ssl_certificate /etc/nginx/certs/【自分のドメイン】/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/【自分のドメイン】/key.pem;
ssl_dhparam /etc/nginx/certs/dhparam.pem;

keepalive_timeout 70;
sendfile on;
client_max_body_size 0;

root 【mastodon配下の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";
add_header Content-Security-Policy "style-src 'self' 'unsafe-inline'; script-src 'self'; object-src 'self'; img-src data: https:; media-src data: https:; connect-src 'self' wss://【自分のドメイン】; upgrade-insecure-requests";

location / {
try_files $uri @proxy;
}

location ~ ^/(assets|system/media_attachments/files|system/accounts/avatars) {
add_header Cache-Control "public, max-age=31536000, immutable";
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://web: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://streaming: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;
}



5. Mastodonの起動


5.1 データベースのマイグレーション

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


5.2. アセットプリコンパイルの実行

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


5.3. Mastodonの起動

$ docker-compose up -d

#起動後のプロセスやログを確認する場合
以下のコマンドを実行する。
$ docker-compose ps
$ docker-compose logs -f


6. 起動後


6.1. 起動確認

自分のドメインにアクセスして、接続出来るか確認。

サインアップの画面が表示されれば成功。

もし、「we're sorry, but something went wrong」というメッセージが出るようだったら、データベースのマイグレーションが出来ていない可能性があるので、再度コマンドを実行すると、たぶん動きます。


6.2. 管理者登録

アクセスした画面からサインアップを行った後、以下のコマンドを実行して

管理者に登録します。

$ docker-compose run --rm web rails mastodon:make_admin USERNAME=【登録ユーザー名】


あとがき

Mastodonは、dockerを学ぶにはとてもよい題材だと感じました。

今回、初めてDockerを使ったのですが、それでもうっすらと概要を理解できました。