めでたくインスタンスを立ち上げて遊んでるわけですが、当初の構成だといろいろ不具合が出ました。当初の構成はこんな感じです。
当初はこの構成で正常動作してると思っていたのですが、以下の不具合が発生してました。
- 外部からブラウザUIで開いた場合、タイムラインが動的更新されない
- 場合によっては、外部からブラウザUIでログインしようとすると失敗する
特に1番目の不具合は致命的で、これはマズイなと思ってUTMのライブログを調べてみるとこんなログが出てました。
2017:05:15-00:00:10 meiji reverseproxy: id=“0299” srcip=“<外部IP>” localip=“<我が家IP>” size=“39” user=“-” host=“<外部IP>" method="GET" statuscode="401" reason="-" extra="-" exceptions="-" time="12676" url="/api/v1/streaming/" server="elephant.bluecore.net" referer="-" cookie="remember_user_token=(省略); _mastodon_session=(省略) " set-cookie="-"
当初は/api/v1/streamingに対するサイトパスルーティングを通していないことで404エラーが帰ってきてることがわかり、早速修正したのですが、今度は何故か/api/v1/streamingに対して401返却が行われているんですね。これの原因がわからずう~んと悩む羽目に。
結局原因がわからないのと、その後DBが崩壊したこともあったりで、次作り直す際はだいぶ単純化した構成にしています。
単にルーターでReverse NATしただけの構成。それで通常運転できるようになってたんですが、その後どうしても納得がいかなくて、ステージング環境を別途作ることに。そこにWAFを通すことにしました。
そして調査したんですが、以下の情報に行き着きました。
Streaming notification broken in a new installation
なんと、/api/v1/streamingに対する通信は「http://」ではなく「ws://」であるとのこと。nginxではそこは意識しなくていいみたいなのですが、今私が使ってるWAFのようなApacheベースのものの場合、ここのURLを正確に表現する必要があります。「ws://」ってのは何かな?って調べてみるとWebsocketとあり、どうやらプロトコル自体が違うみたいですね。たっはー、これがうまくいかない原因かと。
更に調べると、なんと今使ってるWAF、Websocketに対応する気がゼロみたいで。
Sophos-Ideas/websocket support for WAF
色んな人の雄叫びが垣間見られます。心の底から「F○○k!!」ってつぶやきそうになるのを堪えて読み進めてみると、以下のように対応すると良いことがわかりました。
UTMに対してSSHログインを行い、以下の通りにコマンドを実行してコンフィグファイルを開きます。
> su - # cd /var/storage/chroot-reverseproxy/usr/apache/conf # vi reverseproxy.conf
続いて、以下のように4000番ポートにアクセスする設定のURLを全て「ws://」に変えます。
KeepAlive On ServerName meiji ServerAdmin localYouser@gmail.com Listen ***.***.***.***:443 https <VirtualHost ***.***.***.***:443> ServerName elephant.bluecore.net SSLProxyEngine On SSLEngine On SSLCertificateFile /usr/apache/conf/ssl/REF_CaHosElephantbl.pem SSLCACertificateFile /usr/apache/conf/ssl/REF_CaHosElephantbl.CAs SSLCertificateKeyFile /usr/apache/conf/ssl/REF_CaHosElephantbl.key Include conf/waf/REF_WAFDefaultProfileBasic.rules RequestHeader set X-Forwarded-Proto https DocumentRoot /var/www/REF_RevFroElephantbl SetEnv proxy-initial-not-pooled <Proxy balancer://cd107d9706d71153bafd4ab15f1c6b5d> BalancerMember http://***.***.***.***:3000 status=-SE timeout=300 </Proxy> <Proxy balancer://39b4eada215c97c750464aabd919c2b7> BalancerMember ws://***.***.***.***:4000 status=-SE timeout=300 </Proxy> <Proxy balancer://93bb0dd069aa830c31eb1abaec665a2e> BalancerMember ws://***.***.***.***:4000 status=-SE timeout=300 </Proxy> <Location "/"> SetEnv proxy-aside-c ProxyPass "balancer://cd107d9706d71153bafd4ab15f1c6b5d/" lbmethod=bybusyness ProxyPassReverse "http://***.***.***.***:3000/" ProxyPassReverse "http://elephant.bluecore.net:3000/" SetOutputFilter AvScan;DEFLATE <RequireAll> Require all granted </RequireAll> SetInputFilter AvScan AvScanEngines single AvScanSocketTimeout 90 AvScanLogOnly On AvScanBlockUnscannable Off AvScanSizelimit 0 </Location> <Location "/api/v1/streaming"> SetEnv proxy-aside-c ProxyPass "balancer://93bb0dd069aa830c31eb1abaec665a2e/api/v1/streaming" lbmethod=bybusyness ProxyPassReverse "ws://***.***.***.***:4000/api/v1/streaming" ProxyPassReverse "ws://elephant.bluecore.net:4000/api/v1/streaming" SetOutputFilter AvScan;DEFLATE <RequireAll> Require all granted </RequireAll> SetInputFilter AvScan AvScanEngines single AvScanSocketTimeout 90 AvScanLogOnly On AvScanBlockUnscannable Off AvScanSizelimit 0 </Location> <Location "/api/v1/streaming/"> SetEnv proxy-aside-c ProxyPass "balancer://39b4eada215c97c750464aabd919c2b7/api/v1/streaming/" lbmethod=bybusyness ProxyPassReverse "ws://***.***.***.***:4000/api/v1/streaming/" ProxyPassReverse "ws://elephant.bluecore.net:4000/api/v1/streaming/" SetOutputFilter AvScan;DEFLATE <RequireAll> Require all granted </RequireAll> SetInputFilter AvScan AvScanEngines single AvScanSocketTimeout 90 AvScanLogOnly On AvScanBlockUnscannable Off AvScanSizelimit 0 </Location> </VirtualHost>
で、終わったらWAFサービスを再起動します。
# /var/mdw/scripts/reverseproxy restart
そして接続したらこう見えるようになりまする。
2017:05:26-01:18:54 meiji reverseproxy: id="0299" srcip="(外部クライアントIP)" localip="(サーバ外部IP)" size="0" user="-" host="(外部クライアントIP)" method="GET" statuscode="200" reason="-" extra="-" exceptions="-" time="9218" url="/api/v1/streaming/" server="elephant.bluecore.net" referer="-" cookie="remember_user_token=(省略); _mastodon_session=(省略)" set-cookie="-"
おお、無事200が返却されました。ウェブUIでも正常に動的更新が行われるようになりました。というわけで、どうやらMastodonはタイムラインの更新周りに関してWebsocketを使ってるということを理解しました。Webの時代ってどんどん移り変わり、仕組みも変わっていってるんだなぁということを実感。なかなか時代について行けぬ自分を自覚しました。
No responses yet