ConoHa VPSへMastodonインスタンスを引っ越しメモ

# 前提
- さくらVPSなど他のサービスでMastodonを実行中
- ConoHa VPSは初期設定済み(http://qiita.com/jqtype/items/e394fb9e027892e9a2a4)
- Mastodonは今現在ネイティブで動いてる
- 移行先はDocker環境


## Dockerのネットワーク構成
- front: nginx proxyと他のdocker-composeで動くサービスを繋ぐ
- back-mastodon: mastodonの各コンテナを繋ぐ

```
$ docker network create --driver bridge front
$ docker network create --driver bridge back-mastodon
```

## Nginx Proxyの設定
まずはConoHaの方でNginx proxyの設定を進める。$HOME/proxy以下にletsencryptの証明書とかdocker-composeの設定ファイルとか入れる。

```
$ mkdir -p ~/proxy
$ touch proxy/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
```

# Mastodonの設定
## docker-composeの設定
mastodonは`$HOME/apps`ディレクトリ以下に作成

```
$ mkdir -p ~/apps
$ git clone https://github.com/tootsuite/mastodon.git
```
`~/apps/mastodon/docker-compose.yml`をまず編集。nginxリバースプロキシ向けのコンテナを追加している。

```app/mastodon/docker-compose.yml
version: '2'
services:
  nginx:
    image: nginx:alpine
    container_name: mastodon-nginx
    expose:
      - "20090"
    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
      - ./setting/nginx/tmp:/var/tmp/nginx:ro
    volumes_from:
      - container:proxy-nginx
    networks:
      - front
      - back-mastodon

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

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

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

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

  sidekiq:
    build: .
    image: gargron/mastodon
    container_name: mastodon-sidekiq
    restart: always
    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-mastodon

networks:
  front:
    external: true
  back-mastodon:
    external: true
```

## Nginxの設定
追加したnginxコンテナの設定を作る。

```
$ mkdir -p ~/apps/mastodon/setting/nginx/conf.d/
$ touch ~/apps/mastodon/setting/nginx/conf.d/default.conf
```

```apps/mastodon/setting/nginx/conf.d/default.conf
map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

server {
  listen 20090 ssl;
  server_name <domain>;

  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/<domain>/fullchain.pem;
  ssl_certificate_key /etc/nginx/certs/<domain>/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";

  set_real_ip_from 10.10.0.0/16; # nginx-proxyのinternalなアドレス空間を指定。
  real_ip_header X-Forwarded-For;

  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://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;
}
```

## Mastodonの細かい設定
続いてMastodon本体の設定ファイルであるところの`~/apps/mastodon/.env.production`を編集。letsencrypt向けの設定を入れている。

```apps/mastodon/.env/production
VIRTUAL_HOST=<your domain name>
VIRTUAL_PORT=20090
VIRTUAL_PROTO=https
LETSENCRYPT_HOST=<your domain name>
LETSENCRYPT_EMAIL=<your email address>
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
# Note: Changing LOCAL_DOMAIN or LOCAL_HTTPS at a later time will cause unwanted side effects.
# LOCAL_DOMAIN should *NOT* contain the protocol part of the domain e.g https://example.com.
LOCAL_DOMAIN=<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

# Use this if you want to have several aliases handler@example1.com
# handler@example2.com etc. for the same user. LOCAL_DOMAIN should not
# be added. Comma separated values
# ALTERNATE_DOMAINS=example1.com,example2.com

# Application secrets
# Generate each with the `RAILS_ENV=production bundle exec rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose)
PAPERCLIP_SECRET=<docker-compose run --rm web rake secret 1回目>
SECRET_KEY_BASE=<docker-compose run --rm web rake secret 2回目>
OTP_SECRET=<docker-compose run --rm web rake secret 3回目>

# VAPID keys (used for push notifications
# You can generate the keys using the following command (first is the private key, second is the public one)
# You should only generate this once per instance. If you later decide to change it, all push subscription will
# be invalidated, requiring the users to access the website again to resubscribe.
#
# Generate with `RAILS_ENV=production bundle exec rake mastodon:webpush:generate_vapid_key` task (`docker-compose run --rm web rake mastodon:webpush:generate_vapid_key` if you use docker compose)
#
# For more information visit https://rossta.net/blog/using-the-web-push-api-with-vapid.html
VAPID_PRIVATE_KEY=
VAPID_PUBLIC_KEY=

# 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=en

# 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 and SMTP_OPENSSL_VERIFY_MODE to 'none' and 
# *comment* SMTP_LOGIN and SMTP_PASSWORD (leaving them blank is not enough).
SMTP_SERVER=pumpkins.sakura.ne.jp
SMTP_PORT=587
SMTP_LOGIN=<mail address>
SMTP_PASSWORD=<mail password>
SMTP_FROM_ADDRESS=<mail address>
#SMTP_DOMAIN= # defaults to LOCAL_DOMAIN
#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
#SMTP_TLS=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=https://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=

# Swift (optional)
# SWIFT_ENABLED=true
# SWIFT_USERNAME=
# SWIFT_TENANT=
# SWIFT_PASSWORD=
# SWIFT_AUTH_URL=
# SWIFT_CONTAINER=
# SWIFT_OBJECT_URL=

# 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

# Docker mastodon user
# If you use Docker, you may want to assign UID/GID manually.
# UID=1000
# GID=1000
```

# 前の環境からデータ持ってくる
さくらvpsネイティブで実行している前のサーバからデータをバックアップ。各ファイルのユーザIDが違うことがあるので、その場合は`chown`して修正しておく。

Postgre SQL/Redisのバックアップ

```
$ pg_dump mastodon > pg_dump.sql # Postgre SQL

$ redis-cli save # Redis
$ cp /var/lib/redis/dump.rdb redis_dump.rdb
```

Mastodonの画像等のデータのバックアップ

```
$ tar zcvf assets.tar.gz <path to mastodon>/public/assets
$ tar zcvf system.tar.gz <path to mastodon>/public/system
```

Postgre SQL/Redisのレストア

```
$ docker cp pg_dump.sql mastodon-db:/dump.sql #Postogre SQL
$ docker exec mastodon-db psql -f ./dump.sql -U postgres

$ docker stop mastodon-redis # Redis
$ cp redis_dump.rdb ~/apps/mastodon/docker/dump.rdb
$ docker start mastodon-redis

$ docker-compose run --rm web rake db:migrate
```

Mastodonの画像等のデータのレストア

```
$ tar zxvf assets.tar.gz
$ sudo mv public/assets/* ~/apps/mastodon/public/assets/

$ tar zxvf system.tar.gz
$ sudo mv public/system/* ~/apps/mastodon/public/system/
```


# mastodonの実行

`assets:precompile`と`db:migrate`をしておく。

```
$ docker-compose run --rm web rails db:migrate
$ docker-compose run --rm web rake assets:precompile
```

ようやく起動。

```
# nginx-proxyの起動
$ cd ~/proxy
$ docker-compose up -d

# mastodonの起動
$ cd ~/apps/mastodon
$ docker-compose up -d
```

# `cron`の設定 [追記 Oct. 22, 2017]
すっかり忘れていた。mastodon:dailyはsidekiqが実行してくれるようになったので`cron`で回す必要はない。ただ、1週間以上前の動画像のキャッシュを削除をするのにmastodon:media:remove_remoteを週1回で設定しておく。

```
$ crontab -e

# crontabの内容
# 毎週月曜日の3:00amに実行
0 3 * * 1 cd /home/<your id>/apps/mastodon && docker-compose run --rm web rake mastodon:media:remove_remote
```

# まとめ
超めんどくさい。初めからdockerで立てておけばよかった。 

- logging driver (syslogに投げてlogwatchでメール送信)
- letsencryptがどうも挙動不審なので詳細確認

上記は要確認事項。


参考: [Docker🐳でMastodon🐘のインスタンスを立てるドン (リバースプロキシにnginx-proxy + letsencrypt-nginx-proxy-companionを使う)](http://qiita.com/ryo_dg/items/e0cc93e6a8688e5116c8)