Mastodonが流行っているので、自分のVPSでインスタンスを立ち上げてみました。こちらです。
サーバにDockerとNginxをインストールして、という感じのやり方をされている人が多い印象ですが、NginxもDockerで構築してみます。
また、nginx-proxyとletsencrypt-nginx-proxy-companionを使ったリバースプロキシを別に立ち上げ、1つのサーバで複数のサービスを運用できるようにしました。
メールの配信サービスはSparkPostを利用してます。
ネットワークを作成する
色々試したんですが、front
とback-mstdn
という2種類のネットワークをあらかじめ作っておくといい感じに動作しました。
-
front
: リバースプロキシと、Mastodon(や他のサービス)を繋ぐためのネットワーク -
back-mstdn
: Mastodonの各コンテナを繋ぐためのネットワーク
サービスが増えるとback-hoge
、back-fuga
のようにback
が増えていくことを想定してみました。
# ネットワークを作成する
$ docker network create --driver bridge front
$ docker network create --driver bridge back-mstdn
リバースプロキシの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
リバースプロキシの方はこれだけです。
letsencrypt-nginx-proxy-companionが、Let's Encryptを使ったSSL証明書の発行や更新をいい感じにおこなってくれます。
発行されたSSL証明書などは、docker-compose.ymlと同じ階層のcerts
ディレクトリ以下に保存されます。
Mastodonのdocker-compose.ymlを編集
Mastodonのリポジトリをcloneして、docker-compose.yml
を編集していきます。
何を編集するかというと、
- Nginxコンテナを新たに追加する
- ポートは適当に
9090
番で
- ポートは適当に
- 各コンテナを
back-mstdn
ネットワークで繋ぐ- Nginxはリバースプロキシとやり取りするので、
front
とback-mstdn
の両方のネットワークに繋ぐ
- Nginxはリバースプロキシとやり取りするので、
- データを永続化するために、
db
とredis
のvolumes
のコメントアウトを解除
という感じです。
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
Mastodonに追加したNginxの、volumes_fromの設定
volumes_from:
- container:proxy-nginx
こんな設定がMastodonのNginxのところにあります。これは、リバースプロキシで作成したSSLの証明書と秘密鍵をMastodon Nginxからもアクセスできるようにするための設定です。
Mastodon Nginxの中に入って確認すると、/etc/nginx/certs
というディレクトリができていて、リバースプロキシのcerts
ディレクトリと内容が同期されるようになります。
Nginxの設定ファイルを追加
mastodon/setting/nginx/conf.d/default.conf
を作成して、Production guideにあるような感じで、Nginxの設定をやっていきます。
SSLの設定をやっておかないとリモートフォローが動かないので、ちゃんと設定していきます。
Production Guideの例では、HTTPでのアクセス(80番ポート)をHTTPS(443番ポート)にリダイレクトするような記述があります。ただ、今回はそういうのはリバースプロキシのnginx-proxyが全部やってくれるので、9090番ポートにいきなりHTTPSでのアクセスが飛んでくることを想定して設定を変更していきます。
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 9090 ssl;
server_name mstdn.brdr.jp;
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/nginx/certs/mstdn.brdr.jp/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/mstdn.brdr.jp/key.pem;
# 以下省略
ssl_certificate /etc/nginx/certs/mstdn.brdr.jp/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/mstdn.brdr.jp/key.pem;
ssl_certificate
とssl_certificate_key
は、リバースプロキシのNginxに保存されている証明書と秘密鍵をそれぞれ指定します。
.env.productionを編集
.env.production.sample
をコピー&リネームした、.env.production
を編集していきます。Mastodonの設定もなんですが、リバースプロキシ用の環境変数も追記していきます。
編集すべきところを抜粋していきます。
# リバースプロキシ用の設定
# 一番上とかに追記
VIRTUAL_HOST=mstdn.brdr.jp
VIRTUAL_PORT=9090
VIRTUAL_PROTO=https
LETSENCRYPT_HOST=mstdn.brdr.jp
LETSENCRYPT_EMAIL=mail@example.com
LETSENCRYPT_TEST=false
# 探して編集
LOCAL_DOMAIN=example.com
LOCAL_HTTPS=true
# 探して編集
# `docker-compose run --rm web rake secret`を3回実行して、出力された文字列をそれぞれ入れる
PAPERCLIP_SECRET=
SECRET_KEY_BASE=
OTP_SECRET=
# 探して編集
# SparkPostの場合です
SMTP_SERVER=smtp.sparkpostmail.com
SMTP_PORT=587
SMTP_LOGIN=SMTP_Injection
SMTP_PASSWORD=<API Key>
SMTP_FROM_ADDRESS=<好きなアドレス>@mail.example.com
こんな感じです。
nginx-proxyは超便利で、VIRTUAL_HOST
に設定したドメインへのアクセスがあった場合、自動でVIRTUAL_PORT
で設定したポート番号へのアクセスを待ち受けているサーバに転送してくれます。
VIRTUAL_PROTO=https
の設定はとても大事で、リバースプロキシからバックエンドへの接続をHTTPSでやってくれるようになります。ここに説明があります。
VIRTUAL_PROTO=https
を設定しないと、MastodonへのアクセスがHTTP(9090番ポート)になってしまうので、先程のNginxの設定ではうまく処理できず、「400 Bad Request The plain HTTP request was sent to HTTPS」みたいなエラーが出てしまいます。
「じゃあProduction Guideの通りリダイレクトすればええやん」という感じなんですけど、うまく設定できずリダイレクトループが発生してしまったので、この形に落ち着きました。
SparkPostの設定
下記の投稿の通りにやると、ばっちりです!(力尽きた)
文系非エンジニアでも立てられるマストドン(Mastodon) CentOS7+Docker+SparkPost
リバースプロキシとMastodonを起動するドン
以上で設定ができたので、リバースプロキシとMastodonを起動しましょう。
# リバースプロキシの起動
$ cd ~/proxy
$ docker-compose up -d
# Mastodonの起動
$ cd ~/service/mastodon
$ docker-compose up -d
nginx-proxyは最高なので、今後、Mastodon以外のサービスを作って起動した場合も、VIRTUAL_HOST
とVIRTUAL_PORT
をバックエンドの環境変数に設定しておくだけで、起動や変更を検知して自動でいい感じにアクセスを振り分けてくれます。
以上
サーバサイドの知識が全然ない僕ですが、なんとかMastodonのインスタンスを立ち上げることができました!
ドメインでアイデンティティを確立していきたいと思います。ちなみに僕のアカウントは以下なので、良かったらフォローしてください。
DockerやNginxのセキュリティに対する知見がないので、おいおいその辺りは勉強していこうと思います。