「20171024][Mastodon] IPv6しか繋がらない、そんなインスタンスを作ってみる

はじめに

これまで、インスタンスづくりは外部のサイトを見様見真似で作ってきた経緯があり、今回も見様見真似で作ったものの、色々内容が整理できてきたこともあり、ブログに構築手順を書き起こしてみました。

※一部、手順を修正しました。具体的にはnodejsのインストール周りです。

先に言っとくんですが、あくまで備忘録として頭の中のものをExportしたものになります。本来はMastodonのProduction Guideを参照することが望ましいです。ただ、当該ドキュメントはubuntuベースとなっていて、当方のCentOSには合わないところもあったりするため、そこを補正する際にいろんなサイトをチラ見してます。

なので、正確性についてはどうぞご容赦賜りたく・・・(結局言いたい所はそれかというツッコミは勘弁を)

方針

とりあえず、こんな方針で作ってみることにしました。

  • IPv6アドレスだけを受け付けるインスタンスを構築する
  • サーバは自宅仮想基盤内にVMを構築し、それを使用する
    • 2vCPU/2GB RAM/40GB VHD(SSDデータストア配置)のスペックで構築
  • DNSに登録するレコードはAAAAレコードだけにする。IPv4アドレスは名前解決しない。
    • あくまでIPv4はyumリポジトリやメール配送など、クライアント用途としてしか使用しない
  • インスタンス名とサーバ名は異なるものとする。
    • 当該インスタンスでは、サーバ名はsns-v6.bluecore.netと言う名称ですが、インスタンス名はまた別物(v6don.bluecore.net)です。
  • OSはCentOS7の最新を使う(yum -y updateでコンポーネントを最新化する)
  • インスタンスはオールインワン構成にする(AP/Redis/DBを同一サーバ内で構成する)
  • 証明書はLet’s Encryptを使うことにする
  • 設置セグメントは本番/ステージングインスタンスと同じところにする
  • Dockerは使用しない
    • 非Dockerの方がログが見やすいというのがあります。サービス監視も楽です。
    • Dockerの構成も利点はあって、とっととイメージを組み込むことで、前提アプリケーション導入をバイパスできる点などが挙げられます。Linux不慣れな人はこちらが良いのかも。
  • フィルタリングはサーバ側で行わずに、ゲートウェイ側のACLで行う
  •  メールサーバは本番/ステージングと同様に、内部メールサーバを経由する。
    • メールは外向けに関しては【内部メールサーバ】⇒【メールゲートウェイ】⇒【インターネット】と言う経路で発送される。

環境の準備

以下の環境準備を予め行っておきます。

  • 内部権威DNSサーバにAAAAレコードを追加しておく。
    • サーバ本体の名前、Mastodonインスタンスの名前を登録する必要がある
    • 私の場合、内部にActive Directoryサーバが存在するので、これにAAAAレコードを登録してます。
  • 外部権威DNSサーバにAAAAレコードを追加しておく。
    • Mastodonインスタンスの名前だけで良い
    • 私の場合、CloudFlareのDNS設定としてAAAAレコードを登録してます。
  • ルーター側のACLルールに、IPv6アドレスに対する80/tcp, 443/tcpの疎通許可を発行する。

三番目に述べたACLルールなのだけど、こんな感じ。雰囲気だけ感じてもらえれば。

ipv6 filter 4009 pass * 2001:470:fc89:100::101 tcp * https
ipv6 filter 4013 pass * 2001:470:fc89:100::101 tcp * www
tunnel select 6
ipv6 tunnel secure filter in 4001 4002 4003 4004 4005 4006 4007 4008 4009 4013
 4010 4011 4012 4998

IPv4は静的NATなどにより外部からの接続をある程度規制しやすい、IPv6はグローバルアドレスが振られるから外部からの防御が難しい・・ということで、そこを気にするケースが多いんですが、結局のところACLの定義で単純にポートを規制すればそれで済む話だったりするんすよね。iptablesとかだとINPUT/OUTPUTの他にFORWARDがあるので、感覚がつかみにくかったりするんですが、ネットワーク機器だと大抵がinbound/outboundだけだったりするから、もう少しばかり規制の方向をつかみやすいです。

サーバの準備

OSインストール及び以下の対応を行っておく。

  • SELinuxの無効化
  • firewalldの無効化
  • 「yum -y update」の実行

アドレスの付与

アドレスを付与します。NetworkNodeManager使ってる環境なので、nmtuiで設定します。

# nmtui

「Edit a Connection」⇒NICを選択した後、アドレスの設定を行います。本当はIPv6アドレスしか振らない予定だったのですが、以下理由によりIPv4アドレスでもアクセスできるよう、アドレスを割り当てています。

  • 既存メールサーバがIPv4オンリーであること
  • 一部リポジトリがIPv4でしかアクセスを受け付けてないこと

我が家では、サーバセグメントのIPv6設定については、RAを使用しています。その為、IPv6ConfigurationはManualではなく、Automaticを使い、デフォルトゲートウェイはRA設定に従うようにしています。

「OK」を押した後はリブートなり、Activateし直しなり好きにしてよいです。何れにしても反映されれば御の字です。

[root@sns-v6 ~]# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
 inet 192.168.100.154 netmask 255.255.255.0 broadcast 192.168.100.255
 inet6 2001:470:fc89:100::101 prefixlen 128 scopeid 0x0<global>
 inet6 fe80::ff15:161c:a0b1:4c7b prefixlen 64 scopeid 0x20<link>
 inet6 2001:470:fc89:100:912c:5c80:359f:aed1 prefixlen 64 scopeid 0x0<global>
 ether 00:50:56:a7:70:17 txqueuelen 1000 (Ethernet)
 RX packets 726766 bytes 529032570 (504.5 MiB)
 RX errors 0 dropped 20 overruns 0 frame 0
 TX packets 488824 bytes 189506037 (180.7 MiB)
 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
 inet 127.0.0.1 netmask 255.0.0.0
 inet6 ::1 prefixlen 128 scopeid 0x10<host>
 loop txqueuelen 1 (Local Loopback)
 RX packets 6030770 bytes 772770845 (736.9 MiB)
 RX errors 0 dropped 0 overruns 0 frame 0
 TX packets 6030770 bytes 772770845 (736.9 MiB)
 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

Nginxインストール

[root@sns-v6 ~]# vi /etc/yum.repos.d/nginx.repo
--------以下を挿入
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1

[root@sns-v6 ~]# yum -y --enablerepo=nginx install nginx
----------以下、yumの実行処理の流れを記載しておく。以降は割愛する。
読み込んだプラグイン:fastestmirror, langpacks
nginx | 2.9 kB 00:00 
nginx/x86_64/primary_db 0% [ ] 0.0 B/s | 0 B --:-- ETA nginx/x86_64/primary_db | 31 kB 00:00 
Loading mirror speeds from cached hostfile
 * base: mirror.lax.hugeserver.com
 * extras: mirror.lax.hugeserver.com
 * updates: mirror.lax.hugeserver.com
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> パッケージ nginx.x86_64 1:1.12.2-1.el7_4.ngx を インストール
--> 依存性解決を終了しました。

依存性を解決しました

================================================================================
 Package アーキテクチャー
 バージョン リポジトリー 容量
================================================================================
インストール中:
 nginx x86_64 1:1.12.2-1.el7_4.ngx nginx 716 k

トランザクションの要約
================================================================================
インストール 1 パッケージ

総ダウンロード容量: 716 k
インストール容量: 2.5 M
Downloading packages:
nginx-1.12.2-1.el7_4.ngx.x86_64.rpm | 716 kB 00:02 
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
インストール中 : 1:nginx-1.12.2-1.el7_4.ngx.x86_64 1/1 
----------------------------------------------------------------------

Thanks for using nginx!

Please find the official documentation for nginx here:
* http://nginx.org/en/docs/

Please subscribe to nginx-announce mailing list to get
the most important news about nginx:
* http://nginx.org/en/support.html

Commercial subscriptions for nginx are available on:
* http://nginx.com/products/

----------------------------------------------------------------------
 検証中 : 1:nginx-1.12.2-1.el7_4.ngx.x86_64 1/1

インストール:
 nginx.x86_64 1:1.12.2-1.el7_4.ngx

完了しました!

前提パッケージインストール

[root@sns-v6 ~]# yum -y install openssl openssl-devel libxml2-devel ImageMagick libxslt-devel git curl file gcc gcc-c++ protobuf-compiler protobuf-devel readline-devel libicu-devel libidn-devel
(出力に関しては割愛)

EPELリポジトリ有効化

[root@sns-v6 ~]# rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

NUX-DEXTOPリポジトリ有効化

[root@sns-v6 ~]# rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm

ffmpeg/nodejs/npm/yarnインストール

[root@sns-v6 ~]# yum -y install ffmpeg ffmpeg-devel nodejs npm yarn

この手順を10/31に更新しました。もともとはnodejsはnodesourceリポジトリからダウンロードするようにしていました。

後日、パッケージのアップデートをするとnodejsのリポジトリ競合が発生し、nodejsとnpmが更新できなくなってました。nodesourceにあるnodejsのほうがバージョンとしては新しいのですが、今後の更新作業を考慮して、今はnodejs/npm/yarnはいずれもepelからダウンロードするようにしています。

Mastodon実行ユーザ作成・パスワード定義

[root@sns-v6 ~]# useradd mastodon
[root@sns-v6 ~]# passwd mastodon

Redisインストール・起動

[root@sns-v6 ~]# yum -y install redis rubygem-redis
[root@sns-v6 ~]# vi /etc/redis.conf
----------以下設定を追加
bind 127.0.0.1 ::1
⇒当初127.0.0.1を除外していたが、諸事情によりやむなく127.0.0.1を指定

[root@sns-v6 ~]# systemctl start redis
[root@sns-v6 ~]# systemctl enable redis

PostgreSQLインストール・起動

[root@sns-v6 ~]# yum -y install postgresql-server postgresql postgresql-contrib postgresql-devel
[root@sns-v6 ~]# postgresql -setup initdb
[root@sns-v6 ~]# vi /var/lib/pgsql/data/pg_hba.conf
-----以下の通り修正
# IPv4 local connections:
host all all 127.0.0.1/32 trust
# IPv6 local connections:
host all all ::1/128 trust

※基本的にlocalhostからの通信しか許容しない
※localhostからの接続は基本的に信用する
-----

[root@sns-v6 ~]# systemctl start postgresql
[root@sns-v6 ~]# systemctl enable postgresql

PostgreSQLに対するMastodonユーザ作成・DB作成権限付与

[root@sns-v6 ~]# sudo -u postgres psql
postgres=# CREATE USER mastodon CREATEDB;
postgres=# \q

※mastodonユーザに対してDB作成権限を付与する

rbenv導入

[root@sns-v6 ~]# su - mastodon
[mastodon@sns-v6 ~]$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
[mastodon@sns-v6 ~]$ cd ~/.rbenv && src/configure && make -C src && cd ~
[mastodon@sns-v6 ~]$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
[mastodon@sns-v6 ~]$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
[mastodon@sns-v6 ~]$ source ~/.bash_profil

Ruby導入

[mastodon@sns-v6 ~]$ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/ plugins/ruby-build
[mastodon@sns-v6 ~]$ rbenv install 2.4.1 && rbenv global $_ && rbenv rehash

※rbenv installで指定するバージョンを2.4.2にしとくと、Mastodon2.0.0も導入できると思う。

Mastodonの取り込み

[mastodon@sns-v6 ~]$ git clone https://github.com/tootsuite/mastodon.git live
[mastodon@sns-v6 ~]$ cd live

バージョン決定

[mastodon@sns-v6 live]$ git tag
(中略)
v1.5.0
v1.5.0rc1
v1.5.0rc2
v1.5.0rc3
v1.5.1
v1.6.0
v1.6.0rc1
v1.6.0rc2
v1.6.0rc3
v1.6.0rc4
v1.6.0rc5
v1.6.1
v2.0.0
v2.0.0rc1
v2.0.0rc2
v2.0.0rc3
v2.0.0rc4
[mastodon@sns-v6 live]$ git tagcheckout v1.6.1
⇒git上では執筆時点では2.0.0が最新だが、今回はv1.6.1を採用する。

Mastodon構成要素のインストール

[mastodon@sns-v6 live]$ gem install bundler
[mastodon@sns-v6 live]$ bundle install --deployment --without development test
[mastodon@sns-v6 live]$ yarn install --pure-lockfile

.env.protectionファイルの準備

[mastodon@sns-v6 live]$ cp .env.production.sample .env.production

鍵の生成

以下コマンドを3回実行する
[mastodon@sns-v6 live]$ RAILS_ENV=production bundle exec rake secret

以下コマンドを1回実行する
[mastodon@sns-v6 live]$ RAILS_ENV=production bundle exec rake mastodon:webpush:generate_vapid_key

.env.protectionファイルの編集

[mastodon@sns-v6 live]$ vi .env.production

------以下を修正
REDIS_HOST=localhost

DB_HOST=
DB_USER=mastodon
DB_NAME=mastodon
DB_PASS=
DB_PORT=5432

LOCAL_DOMAIN=v6don.bluecore.net
LOCAL_HTTPS=true

PAPERCLIP_SECRET=(生成した鍵1つ目)
SECRET_KEY_BASE=(生成した鍵2つ目)
OTP_SECRET=(生成した鍵3つ目)

SMTP_SERVER=(内部メールサーバアドレス)
SMTP_PORT=25
SMTP_FROM_ADDRESS=words@bluecore.net
↑SMTP_LOGINおよびSMTP_PASSWORDは削除する(SMTP認証を使ってないので)

以下は「rake mastodon:webpush:generate_vapid_key」の出力結果と置き換える
VAPID_PRIVATE_KEY=
VAPID_PUBLIC_KEY=

Mastodonデータベースの構築

[mastodon@sns-v6 live]$ RAILS_ENV=production bundle exec rails db:setup

プリコンパイルの実行

[mastodon@sns-v6 live]$ RAILS_ENV=production bundle exec rails assets:precompile

編集が終了したら、一旦mastodonユーザから抜ける
[mastodon@sns-v6 live]$ exit
[root@sns-v6 ~]#

Mastodonサービス定義(mastodon-web)

[root@sns-v6 ~]# vi /etc/systemd/system/mastodon-web.service
------------
[Unit]
Description=mastodon-web
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="RAILS_SERVE_STATIC_FILES=true"
Environment="PORT=3000"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target

Mastodonサービス定義(mastodon-sidekiq)

Sidekiqのキューはオールインワン構成としてますが、サービスファイルを分けることで役割ごとにキューを構成することが出来ます。本番インスタンスなんかはキューを分けて構成しています。

[root@sns-v6 ~]# vi /etc/systemd/system/mastodon-sidekiq.service
------------
[Unit]
Description=mastodon-sidekiq
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="DB_POOL=10"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 10 -q default -q mailers -q pull -q push
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target

Mastodonサービス定義(mastodon-streaming)

[root@sns-v6 ~]# vi /etc/systemd/system/mastodon-streaming.service
-------------
[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

Mastodonサービスの起動

[root@sns-v6 ~]# systemctl start mastodon-{web,sidekiq,streaming}
[root@sns-v6 ~]# systemctl enable mastodon-{web,sidekiq,streaming}

Nginxの設定

Nginxの設定は、MastodonのProduction Guideを参考にしています。

node.jsの関係上、リバースプロキシのURLにIPv6アドレスが適用できないとのことで、そこはIPv4アドレスを明示的に指定するようにしています。(localhostを指定してもIPv6アドレスが優先されるので)

また、listenは[::]のみを指定することでIPv6しか受け付けないようにしています。

[root@sns-v6 ~]# vi /etc/nginx/conf.d/mstdn.conf
map $http_upgrade $connection_upgrade {
 default upgrade;
 '' close;
}

server {
 listen [::]:80;
 server_name (インスタンスのFQDN);
 # Useful for Let's Encrypt
 location /.well-known/acme-challenge/ { allow all; }
 location / { return 301 https://$host$request_uri; }
}

server {
 listen [::]:443 ssl http2;
 server_name (インスタンスのFQDN);

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

 ssl_certificate /etc/letsencrypt/live/(インスタンスのFQDN)/fullchain.pem;
 ssl_certificate_key /etc/letsencrypt/live/(インスタンスのFQDN)/privkey.pem;

 keepalive_timeout 70;
 sendfile on;
 client_max_body_size 0;

 root /home/mastodon/live/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";

 location / {
  try_files $uri @proxy;
 }

 location ~ ^/(emoji|packs|system/accounts/avatars|system/media_attachments/files) {
 add_header Cache-Control "public, max-age=31536000, immutable";
 try_files $uri @proxy;
 }

location /sw.js {
 add_header Cache-Control "public, max-age=0";
 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://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;
 }

error_page 500 501 502 503 504 /500.html;
}

Let’s Encryptの設定

今回、Let’s Encryptの証明書発行は手作業で行っています。自動化は別途検討予定。CentOSではcertbotというアプリケーションを使ってLet’s Encryptionから証明書の発行を受けます。挙動を見る限り、IPv6ベースで今回発行できているようです。

IPv4に関しては、当方ではSSLオフロードを前提として組んでるんですが、どうもcertbotはそのあたりがうまく連携できないようで、今回立てたインスタンスがIPv6限定となっているのは、それが理由だったりします。(外に直接NAT出しできるグローバルIPがない・・)

[root@sns-v6 ~]# yum install certbot
[root@sns-v6 ~]# certbot certonly --standalone -d (インスタンスのFQDN)


Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator standalone, Installer None
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel): 
Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org

-------------------------------------------------------------------------------
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf. You must agree
in order to register with the ACME server at
https://acme-v01.api.letsencrypt.org/directory
-------------------------------------------------------------------------------
(A)gree/(C)ancel: A ←Agree(同意)する

-------------------------------------------------------------------------------
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about EFF and
our work to encrypt the web, protect its users and defend digital rights.
-------------------------------------------------------------------------------
(Y)es/(N)o: Y ←Yを押す
Starting new HTTPS connection (1): supporters.eff.org
Obtaining a new certificate
Performing the following challenges:
tls-sni-01 challenge for v6don.bluecore.net
Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
 /etc/letsencrypt/live/v6don.bluecore.net/fullchain.pem
 Your key file has been saved at:
 /etc/letsencrypt/live/v6don.bluecore.net/privkey.pem
 Your cert will expire on 2018-01-18. To obtain a new or tweaked
 version of this certificate in the future, simply run certbot
 again. To non-interactively renew *all* of your certificates, run
 "certbot renew"
 - Your account credentials have been saved in your Certbot
 configuration directory at /etc/letsencrypt. You should make a
 secure backup of this folder now. This configuration directory will
 also contain certificates and private keys obtained by Certbot so
 making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
 Donating to EFF: https://eff.org/donate-le
この時点で、証明書が発行され、以下箇所に保存されている。
/etc/letsencrypt/live/(インスタンスのFQDN)/fullchain.pem;
/etc/letsencrypt/live/(インスタンスのFQDN)/privkey.pem;

Nginx起動

[root@sns-v6 ~]# systemctl start nginx
[root@sns-v6 ~]# systemctl enable nginx

Mastonインスタンスへの接続試行・ユーザ登録

これで、必要なサービスは一通り立ち上がったので、Mastodonインスタンスへアクセスし、まずは自分自身を登録します。

  • ブラウザでインスタンス( https://(インスタンスのFQDN )) へアクセスする。
  • インスタンス画面にてユーザ登録を行う(下図赤枠内に必要事項を入力して「登録する」をクリック)
  • ユーザ登録を行うと、メールが届くので、そのメールにあるリンクをクリックし、アクティベーションする

自身のアカウントに管理者権限を付与

以下コマンドをmastodonユーザとなり、liveディレクトリへ移動後に実行することで、管理者権限が付与されます。これでインスタンスのサイト設定変更やアドレスブロックやSidekiq状態の確認等が行えるようになります。

RAILS_ENV=production bundle exec rails mastodon:make_admin USERNAME=(登録したユーザ名)

見といたほうが良いログなど

Mastodon稼働上、見といたほうが良いログなんかは以下のとおりです。

Nginxログ

/var/log/nginx/access.log
/var/log/nginx/error.log

messagesログ

/var/log/messages

例えばMessagesログで以下の内容

bundle: 2017-10-23T20:36:18.928Z 27605 TID-ovr7seb9o WARN: 
Mastodon::UnexpectedResponseError: Delivery failed for https://******.host/inbox: 
https://******.host/inbox returned code 502

と言うログが出力された場合、retrun codeからプロキシサービスが動いていないと判断できます。恐らくインスタンスのサービスが停止し、nginxだけが動いてる状態であると推察されます。インスタンスがバージョンアップしている際に、サービス停止を伴ったりする場合に出てくるエラーです。

このあたりのエラーはSidekiqの再試行一覧などにも表記されるので、細かくログを追っかけるよりSidekiqのダッシュボードなどを見たほうが良いように思います。

おわりに

今回IPv6インスタンスを作った思い出として記事に残しましたが、ちょっとした応用でIPv4インスタンス作成にも役立てることが出来ると思います。同様に、以下の様なことも応用してできると思います(主にIPv4的な観点で)。

  • DBやRedisを別サーバ構成にする
    • .env.productionの修正とDB/Redisの接続構成をちゃんと組めば比較的容易にできると思います。
    • DBをクラスタ化して可用性向上を図ることも可能ではないかなと思います。
    • 我が家では、本番インスタンスでサーバ分離をしています。
  • nginxサーバを別サーバ構成にする
    • nginxサーバを別構成にし、複数並べてロードバランサ配下に置くという負荷分散も可能ではないかなぁとか思ったりします。
    • 我が家では、この対応は行えていません・・・(´・ω・`)体力的に厳しいなぁと。
  • Sidekiqのキュー構成を変更し、並列動作可能にする
    • これは比較的容易です。サービス定義ファイルを分割し、割り当てるキューを分けて構成すれば良いです。今回の構成だとdefault/push/pull/mailの動作いずれかが分づまると全体的に影響が及びますが、そのあたりを回避させることが可能になります。
    • 我が家では、default/push/pull/mailでキューを分割してます。
    • push/pullに関しては複数キューを構成することもどうやら出来るっぽいですけど、そこは実際どうやるのか分かってません・・
    • キューのスレッド数を増やす際はDBの接続数に注意してください。DB側のチューニングなどが必要になると思います。
  • WAFを噛ませてみる
    • nginxの代わりにWAFを通すようにすることで、SSLオフロードやセキュリティ確保が可能になるのかなと思います。
    • 我が家ではステージングインスタンス(IPv4通信のみ)をWAFを通す(SSLオフロード含む)ようにしています(ただ、Streamingポートはhttpではなく、webSocketになるので、そこだけ注意が必要です。WAFがwebSocketに対応しているかどうかを確認しといたほうが良いですよ。我が家では、対応してなかったのですが、ちょっと手を加えて無理やりwebSocketに対応させています)

IPv6専用インスタンスをこうして作ったものの、実は結構閑古鳥が鳴いていて。

というのも、日本国内三大インスタンス(JP,friends.nico,Pawoo)がIPv6に対応していないためです。構成が大規模になっているため、それぞれにIPv6アドレスを割り当てるのが大変というのも要因としてあるようなんですが・・・・そんなにIPv6アドレス割り当てるの大変かねぇ?と正直感じています。アドレスの振り方次第だと、あまりIPv4と変わらんと思うんだがなぁ・・・いずれにしても大規模だからこそ踏み切れない所がかなりあるのでしょうね。

また、意外とデュアルスタックで構えてるインスタンスも多くないようで、Federation Timelineにいろんなtootは流れてくるものの、フォローできるユーザはだいぶ限られてるなぁ・・・という感じがします。フォローできるかどうかですが、はいこん( @hcm@mastodon.home.js4.in )さんがそのやり方を教えて下さいました。ありがとうございます。(ちなみに、はいこんさんところのリンクはIPv6アドレス持ってないと多分つながりません。こちらもIPv6専用インスタンスだから。あしからず・・)

何れにしろ、面白いインスタンスが組めたなーと思います。自分にとっても良い復習になりました。

No tags for this post.