Raspberry Pi 2でMastodonインスタンスを立てようとして失敗した件 その2

2017年4月29日


うちで動いているRaspberry PiをMastodonインスタンスにしようと試行錯誤しているのは先日書いたとおりなのですが、トップページを確認できるとこまでいったので手順を公開します。でも最終的にはやっぱり失敗していますので不完全です。
手順は入れたばかりのまっさらなRaspbian Liteを想定しています。

手順の概要

用意するもの

  • Raspberry Pi 2 Model B
    (検証にはPi2B・Pi3Bを併用しました)

動作確認環境

  • Raspbian GNU/Linux 8.0 Lite (Jessie)
  • Docker 17.04.0-ce ※今回導入します
  • docker-compose 1.13.0dev ※今回導入します
  • Mastodon ※今回導入します

他の人のやり方との相違点

  • Dockerを使用します
  • docker-composeをビルドします(イメージ取ってくる方法だとダメだった)
  • forkされたrpi-mastodonを使います(公式の方法だとダメだった)
  • Let’s Encryptを使用します(オレオレ証明書じゃないよ)
  • 最小構成を目指しました(リバースプロキシなどのスケールさせるための要素は除いています)

手順

インストールを始める前に、スワップ領域を拡大しておきます。スワップ領域を使うとSDカードの寿命を縮めますので、やりたくない方は飛ばしてください。

swapon -s

おそらく初期状態ではこのように表示されます。(Raspberru Pi 2の場合)

$ swapon -s
Filename                                Type            Size    Used    Priority
/var/swap                               file            102396  0       -1

設定ファイルを編集します。

sudo systemctl stop dphys-swapfile
sudo vi /etc/dphys-swapfile

このように変更します。

CONF_SWAPSIZE=2048

変更されたことを確認します。

sudo systemctl start dphys-swapfile
swapon -s

サイズが増えていればOKです。

$ swapon -s
Filename                                Type            Size    Used    Priority
/var/swap                               file            2097148 0       -1

Dockerをインストールします。こちらを参考にしました。

curl -sSL https://get.docker.com/ | sh

これで処理が15分ほど走ります。
バージョンは5/1現在、このように表示されました。

$ docker version
Client:
 Version:      17.04.0-ce
 API version:  1.28
 Go version:   go1.7.5
 Git commit:   4845c56
 Built:        Mon Apr  3 18:22:23 2017
 OS/Arch:      linux/arm
Server:
 Version:      17.04.0-ce
 API version:  1.28 (minimum version 1.12)
 Go version:   go1.7.5
 Git commit:   4845c56
 Built:        Mon Apr  3 18:22:23 2017
 OS/Arch:      linux/arm
 Experimental: false

続いて、自分がroot権限がなくてもdockerコマンドを使えるようにしておきます。
(ユーザ名は仮にpiとしています)

sudo gpasswd -a pi docker

一度ログアウトし再度ログインします。
docker-composeをインストールします。Raspbianなのでそのままではインストールできません。なのでこちらを参考にしました。

git clone https://github.com/docker/compose.git
cd compose
docker build -t docker-compose:armhf -f Dockerfile.armhf .
docker run --rm --entrypoint="script/build/linux-entrypoint" -v $(pwd)/dist:/code/dist -v $(pwd)/.git:/code/.git "docker-compose:armhf"

docker buildのところは気を付けて下さい。Raspberry Pi 2(swapなし)だと処理するのに1時間、Pi 3(swapあり)だと40分ほどかかりました。
docker-composeファイルができたことを確認します。

ls -l dist/

このように表示されます。

$ ls -l dist/
total 6844
-rwxr-xr-x 1 pi pi 7004340 Apr 29 18:15 docker-compose-Linux-armv7l

docker-composeファイルを/usr/local/bin/に配置します。

sudo cp dist/docker-compose-Linux-armv7l /usr/local/bin/docker-compose
sudo chown root:root /usr/local/bin/docker-compose
sudo chmod 0755 /usr/local/bin/docker-compose
docker-compose version

バージョンは5/1現在、このように表示されました。

$ docker-compose version
docker-compose version 1.13.0dev, build baf457c
docker-py version: 2.2.1
CPython version: 2.7.13
OpenSSL version: OpenSSL 1.0.1t  3 May 2016

Mastodonをインストールします。こちらを参考にしましたが、公式の方法だとうまくいかないのでforkされたラズパイ専用のものを使います。

cd ..
git clone https://github.com/gilir/rpi-mastodon
cd rpi-mastodon

docker-compose.ymlの永続化設定は初めからされているので不要です。
続いて、.env.productionを編集します。

cp .env.production.sample .env.production
vi .env.production

LOCAL_DOMAINの部分を自分の所持するドメインに変えます。私は「m.yagi.tc」にしました。
メールアドレスは設定しなくても済む方法がありますが、私は個人用にGoogle Apps(GSuite)を使っているのでアカウントを払い出して設定しました。

# Federation
LOCAL_DOMAIN=m.yagi.tc
LOCAL_HTTPS=true
...省略...
DEFAULT_LOCALE=ja
...省略...
SMTP_SERVER=smtp.gmail.com
SMTP_PORT=587
SMTP_LOGIN=mastodon@yagi.tc
SMTP_PASSWORD=********************************
SMTP_FROM_ADDRESS=mastodon@yagi.tc

ビルドします。1時間ほどかかります。

docker-compose build

ネットワークとボリュームを作成します。

docker network create proxy-network
docker volume create --name=mastodon_public_assets
docker volume create --name=mastodon_public_system
docker volume create --name=mastodon_postgres
docker volume create --name=mastodon_redis
docker-compose run --rm web rake secret
docker-compose run --rm web rake secret
docker-compose run --rm web rake secret

数分かかります。
3回繰り返した”docker-compose run –rm web rake secret”の結果得られたキーを.env.productionに追記します。

vi .env.production

以下のように編集します。

PAPERCLIP_SECRET= 取得できたキー1
SECRET_KEY_BASE= 取得できたキー2
OTP_SECRET= 取得できたキー3

データベースのマイグレーションとフロントエンドのプリコンパイルを行います。30分ぐらいかかります。

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

立ち上げます。

docker-compose up -d

続いて、Let’s Encryptをインストールします。

cd ..
git clone https://github.com/letsencrypt/letsencrypt.git
cd letsencrypt/
./letsencrypt-auto --help

nginxをインストールします。

sudo aptitude install nginx

証明書を取得します。

./letsencrypt-auto certonly --webroot -d m.yagi.tc --webroot-path /var/www/html(nginxで指定するルート)

メールアドレスを入力し、利用規約を読んだ上で同意します。
nginxの設定を編集します。

sudo vi /etc/nginx/sites-available/m.yagi.tc

MastodonのGitHubドキュメントを丸コピーして必要なところだけ編集します。
編集箇所は矢印で示した6箇所です。

map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}
server {
  listen 80;
  listen [::]:80;
  server_name m.yagi.tc; ←ホスト名
  # Useful for Let's Encrypt
  location /.well-known/acme-challenge/ { allow all; }
  location / { return 301 https://$host$request_uri; }
}
server {
  listen 443 ssl;
  listen [::]:443 ssl;
  server_name m.yagi.tc; ←ホスト名
  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/letsencrypt/live/m.yagi.tc/fullchain.pem; ←鍵の場所
  ssl_certificate_key /etc/letsencrypt/live/m.yagi.tc/privkey.pem; ←鍵の場所
  ssl_dhparam         /etc/ssl/certs/dhparam.pem;
  keepalive_timeout    70;
  sendfile             on;
  client_max_body_size 0;
  root /var/www/html; ←ルートディレクトリ
  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";
  location / {
    try_files $uri @proxy;
  }
  location /assets {
    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://127.0.0.1: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://localhost: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;
}

DH鍵を作成し、設定を有効化する準備をします。

sudo openssl dhparam 2048 -out /etc/ssl/certs/dhparam.pem
sudo ln -s /etc/nginx/sites-available/m.yagi.tc /etc/nginx/sites-enabled/m.yagi.tc

準備ができたら事前テストをかけます。

sudo nginx -t

このような結果が出たら大丈夫です。

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

nginxを再起動し、設定を有効化します。

sudo service nginx restart

これでローカルIPアドレスを指定してHTTPSで接続すればこのようなページが表示されます。(ローカルIPアドレスだと証明書とURLが異なるのでブラウザの警告が出ます)

ところが……

ここまで来たんですけど、いざサインアップしてみるとログイン後にグレーの画面になったまま何も表示されません。どうやらトップページのHTMLだけは読めているのに、そこから先のリソースが足りてない(読み込まれてない?)ようです。ここで力尽きました。今日はここまで。
個人的にはこのあたりが怪しいと思っているdocker-compose.ymlの内容を貼っておきます。

$ cat docker-compose.yml
version: '2'
services:
  db:
    restart: always
    image: armhf/postgres:9.6-alpine
    networks:
      - proxy-network
    volumes:
      - mastodon_postgres:/var/lib/postgresql/data
  redis:
    restart: always
    image: armhf/redis
    networks:
      - proxy-network
    volumes:
      - mastodon_redis:/data
  web:
    restart: always
    build: .
    image: gilir/rpi-mastodon
    env_file: .env.production
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    ports:
      - "3000:3000"
    depends_on:
      - db
      - redis
    networks:
      - proxy-network
    volumes:
      - mastodon_public_assets:/mastodon/public/assets
      - mastodon_public_system:/mastodon/public/system
    labels:
      - "traefik.frontend.rule=Host:mastodon.lavergne.online"
#      - "traefik.frontend.passHostHeader=true"
      - "traefik.port=3000"
    environment:
      - WEB_CONCURRENCY=1
      - MAX_THREADS=5
  streaming:
    restart: always
    build: .
    image: gilir/rpi-mastodon
    env_file: .env.production
    command: npm run start
    ports:
      - "4000:4000"
    depends_on:
      - db
      - redis
    networks:
      - proxy-network
  sidekiq:
    restart: always
    build: .
    image: gilir/rpi-mastodon
    env_file: .env.production
    command: bundle exec sidekiq -q default -q mailers -q pull -q push
    depends_on:
      - db
      - redis
    volumes:
      - mastodon_public_system:/mastodon/public/system
    networks:
      - proxy-network
networks:
  proxy-network:
    external:
      name: proxy-network
volumes:
  mastodon_postgres:
    external: true
  mastodon_redis:
    external: true
  mastodon_public_assets:
    external: true
  mastodon_public_system:
    external: true

以上。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です