立ち上げてみたらかなりかっこよく動きそうに見えたDiscourse、とはいえ他のサービスも調べたいので試験環境に同居させたいと考えたが、失敗していた。
考え方としては、Dockerで構築された環境の中にあるNGINXの出入り口を unix domain socket に変えて、そこへProxyすれば良いのかな…と思うんだけど。
Discourse / Running other websites on the same machine as Discourse
やること。
環境
VMwareでUbuntu 18.04を立ち上げ、そこにdiscourseを導入。
既に動作している前提。
色々試してキャッシュされるせいか、Chromeでテストすると見えないはずのページが見えちゃったりするので、シークレットモードでテストしてみている。
コンテナの設定変更
コンテナの内容を変更する。
やっているのは、sslをやめること、unix domein socketを導入すること、ポートを使用しないようにすること。
/opt/discourse/containers/app.yml
… templates: - "templates/postgres.template.yml" - "templates/redis.template.yml" - "templates/web.template.yml" - "templates/web.ratelimited.template.yml" ## Uncomment these two lines if you wish to add Lets Encrypt (https) # - "templates/web.ssl.template.yml" # - "templates/web.letsencrypt.ssl.template.yml" - "templates/web.socketed.template.yml" … expose: # - "80:80" # http # - "443:443" # https …
再構築。
./launcher rebuild app
NGINXでProxy設定
まず、ちゃんと動くのはこれ、という環境を作って確かめてからApacheに差し替えることを考えようと思った。インストール直後に色々試したときに、CSRFの問題に悩まされたから。
設定ファイルの作成
Proxy設定のconfファイルを作成。
/etc/nginx/sites-available/discourse
server { listen 80; listen [::]:80; server_name hogeserver.hogeddns.jp; return 301 https://$host$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name hogeserver.hogeddns.jp; ssl_certificate /etc/ssl/private/temp.hogeserver.hogeddns.jp.crt; ssl_certificate_key /etc/ssl/private/temp.hogeserver.hogeddns.jp.key; # ssl_dhparam /var/discourse/shared/standalone/ssl/dhparams.pem; ssl_session_tickets off; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA; http2_idle_timeout 5m; # up from 3m default location / { proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:; proxy_set_header Host $http_host; proxy_http_version 1.1; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Real-IP $remote_addr; } }
サイトの有効化と反映
デフォルトのconfを無効化し、作ったconfを有効化。
NGINXで設定を再読み込み。
# rm /etc/nginx/sites-enabled/default # ln -s /etc/nginx/sites-available/discourse /etc/nginx/sites-enabled/discourse # systemctl reload nginx
これで動いた。NGINXを使うならこれで問題なさそう。
ApacheでProxy設定
NGINXの設定を見ると、Apacheではちょっとやり方が違っていた。
設定ファイルの作成
NGINXの設定をまねして作ってみる。
<VirtualHost *:80> ServerName temp.hogeserver.hogeddns.jp ServerAdmin webmaster@hogeserver.hogeddns.jp Redirect permanent / https://temp.hogeserver.hogeddns.jp/ </VirtualHost> <VirtualHost *:443> ServerName temp.hogeserver.hogeddns.jp ServerAdmin webmaster@hogeserver.hogeddns.jp ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined SSLProxyEngine on ProxyPreserveHost on ProtocolsHonorOrder on RequestHeader set Host "temp.hogeserver.hogeddns.jp" Protocols http/1.1 RemoteIPHeader X-Forwarded-For RequestHeader set X-Forwarded-Proto "https" RemoteIPHeader X-Real-IP ProxyPass / unix:/var/discourse/shared/standalone/nginx.http.sock|http://temp.hogeserver.hogeddns.jp/ SSLEngine on SSLCertificateFile /etc/ssl/private/temp.hogeserver.hogeddns.jp.crt SSLCertificateKeyFile /etc/ssl/private/temp.hogeserver.hogeddns.jp.key </VirtualHost>
サイトの有効化と反映
デフォルトのconfを無効化し、作ったconfを有効化。
必要なモジュールを追加してApacheを再起動。
# a2dissite 000-default.conf # a2ensite discourse.conf # a2enmod proxy proxy_http proxy_https ssl headers remoteip # systemctl restart apache2
これで、動き出した。
再起動したときにDiscourseを自動起動させる
再起動してみたらDiscourseが自動起動しなかった。
色々と設定を変えている中で何かが起きたのかもしれない。
Qiita / Dockerコンテナ単体で自動起動の設定と確認を行う
# docker update --restart=always app
これで再起動時にDiscourseが自動起動するようになった。
やったこと
unix domain socket
コンテナの外部にNGINXをインストールしてそれを使おうとするなら、どうもすぐにできそうな気配。
そのときには、こんな感じでProxyするみたい。
proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
unix:<ソケット名>: という表現が何を指しているのかよく分からず、探してみた。
Qiita / h2oとUnixドメインソケット
凄く早いらしい。
どうも、こんな感じで書くらしい。
stackoverflow / Apache: proxy to unix socket named in URL
RewriteEngine On RewriteRule /(.*)/(.*) http://%{HTTP_HOST}/$2 [P] ProxyPass / unix:/var/sockets/$1.sock|http://%{HTTP_HOST}/ ProxyPassReverse / unix:/var/sockets/$1.sock|http://%{HTTP_HOST}/
$0~$9はRewriteRule backreferencesで、ルールにおいて括弧でグループ化された部分を表す。$0はマッチした文字列全体を表し、$1は1つめ、$2は2つめを表す。
ちなみに%0~%9はRewriteCond backreferencesで、後は一緒。
この例だと、RewriteRuleの1つめの(.*)に一致するところが$1に置き換えられてソケットファイル名が確定、そこに今回だと… http://temp.hogeserver.hogeddns.jp/として渡されるっぽい。
Apacheのバージョン確認
インストール前にパッケージバージョンを確認。unix domain socketに対応しているのかどうかを確認したくなったから。
うまいぼうぶろぐ / apache 2.4.7 からProxyPassでunix domain socketを指定できるようになってた
# sudo apt show apache2
Package: apache2
Version: 2.4.29-1ubuntu4.13
Priority: optional
Section: web
Origin: Ubuntu
…
使えそう。
NGINXのヘッダー操作をまねる
どんな情報が渡せれば動くのだろうか…ということで、それぞれについて調べてみた。
proxy_set_header Host $http_host;
恐らく、ヘッダーに$http_hostが追加されるんだろうけど、$http_hostってなんだろ?
Qiita / proxy_set_header Hostで設定するNginxの変数一覧
リクエストヘッダにあるHTTP_HOSTの値、と書かれている。
Apacheでいうと、mods_headersのRequestHeaderディレクティブで、設定値はServerNameで指定した値を設定すれば良さそう。
proxy_http_version 1.1;
ここに書かれている。
hacknote / httpsにおけるhttpのバージョン選択(apache)
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
ここに書かれている。
とあるサーバエンジニアの備忘録 / Apacheアクセス制御をロードバランサー配下でも
proxy_set_header X-Real-IP $remote_addr;
ここで書かれている。
stackoverflow / Apache can't determine [REMOTE_ADDR]
proxy_set_header X-Forwarded-Proto https;
ここで書かれている。
Qiita / Apach, NginxをプロキシにしたRailsアプリでhttpsがリダイレクト時にhttpになる問題
unix domain socketの通信内容をダンプする
こうして調べて、多分これだろうというものを設定したけれども、CSRF問題を解消できない。この問題が発生する理由はヘッダーがちゃんと設定できていないからなんだけれども、どこが設定できていないのか分からない…。
通信内容をダンプしてみたいと思ったら、この記事を発見。
Qiita / UNIXドメインソケット通信の内容を見たい
プロセスにアタッチする必要があるようなので、プロセスIDを見てみる。
# ps aux | grep nginx
root 2624 0.0 0.0 2160 680 ? Ss 21:37 0:00 runsv nginx
root 2630 0.0 0.3 54024 7100 ? S 21:37 0:00 nginx: master process /usr/sbin/nginx
www-data 2711 0.0 0.2 55056 5176 ? S 21:37 0:00 nginx: worker process
www-data 2712 0.0 0.2 55068 5288 ? S 21:37 0:00 nginx: worker process
www-data 2713 0.0 0.1 54572 3840 ? S 21:37 0:00 nginx: cache manager process
root 9820 0.0 0.0 11332 1100 pts/0 D+ 22:49 0:00 grep --color=auto nginx
試してみたところ、1つめのworker processにアタッチすると通信内容が見えた。
色々な環境があるだろうから、一概には言えないけど。
# strace -s 1024 -f -p 2711
※プロセス番号は都度変わるので、そのとき調べた結果で置き換え。
で、ApacheとNGINXの違いを調べてみた。
■Apache recvfrom(13, "GET /login HTTP/1.1\r\nHost: temp.hogeserver.hogeddns.jp\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36\r\nSec-Fetch-Site: same-origin\r\nSec-Fetch-Mode: same-origin\r\nSec-Fetch-Dest: empty\r\nReferer: https://temp.hogeserver.hogeddns.jp/auth/failure?message=csrf_detected\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: ja,en-US;q=0.9,en;q=0.8\r\nX-Forwarded-Prot: https\r\nX-Forwarded-For: 192.168.33.33\r\nX-Forwarded-Host: temp.hogeserver.hogeddns.jp\r\nX-Forwarded-Server: temp.hogeserver.hogeddns.jp\r\nConnection: Keep-Alive\r\n\r\n", 1024, 0, NULL, NULL) = 732 ■NGINX recvfrom(13, "GET /session/csrf HTTP/1.1\r\nHost: temp.hogeserver.hogeddns.jp\r\nX-Forwarded-For: 192.168.33.33\r\nX-Forwarded-Proto: https\r\nX-Real-IP: 192.168.33.33\r\nConnection: close\r\ndiscourse-track-view: true\r\naccept: application/json, text/javascript, */*; q=0.01\r\ndiscourse-present: true\r\nx-csrf-token: undefined\r\nx-requested-with: XMLHttpRequest\r\nuser-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36\r\nsec-fetch-site: same-origin\r\nsec-fetch-mode: cors\r\nsec-fetch-dest: empty\r\nreferer: https://temp.hogeserver.hogeddns.jp/\r\naccept-encoding: gzip, deflate, br\r\naccept-language: ja,en-US;q=0.9,en;q=0.8\r\n\r\n", 1024, 0, NULL, NULL) = 646
ん!?スペルミス発見…俺は何をやっているんだ…。
これを修正したところ、動き出した。
さいごに
今まで苦手にしていて手を出さなかった領域。通信内容がどうなっていて、どこが問題になっているのか、というのをはじめてちゃんと見た気がする。
書いてあるとおりに設定しても動かない、というのは実はいつも間違いで、何か読み違えたり考え違いしたりしている。最終的に何がどうなっていれば良いのか、というのを見てみたかったのだが、今回のこれは見る範囲の狭さもあってちょうど良い題材だった。
でも…ますますマニアックな世界にはまり込んでいる気もする。
コメントはこちらから お気軽にどうぞ ~ 投稿に関するご意見・感想・他