前のエントリで web アプリを Unicorn で動かすことに成功したので、今度は Nginx と連携する。
その前に unicorn.conf をちょっと修正して、ポートじゃなくて UNIX ソケットを利用するようにする。
#listen "9000"
listen "/run/lcstorage/unicorn.sock"
worker_processes 2
working_directory "/home/lcstorage/lcstorage"
pid "/home/lcstorage/lcstorage/unicorn.pid"
stdout_path "/home/lcstorage/lcstorage/unicorn.log"
stderr_path "/home/lcstorage/lcstorage/unicorn.log"
preload_app true
そしてソケットファイルを置くディレクトリを作る。
[lcstorage@rollo lcstorage]$ sudo mkdir /run/lcstorage
[lcstorage@rollo lcstorage]$ sudo chown lcstorage:lcstorage /run/lcstorage
Unicorn の準備はこれで終わり。起動しておく。
[lcstorage@rollo lcstorage]$ bundle exec unicorn -c unicorn.conf -E production
さて、つぎは Nginx の設定だ。storage1 というホスト名でアクセスできるよう、/etc/nginx/conf.d の下に storage1.conf という名前で設定ファイルを作る。
upstream lcstorage {
server unix:/run/lcstorage/unicorn.sock;
#server 127.0.0.1:9000;
}
server {
# port
listen 80;
# server name
server_name storage1;
# document root
#root /home/lcstorage/lcstorage;
# index
#index index.php index.html index.htm;
client_max_body_size 4G;
# log files
access_log /var/log/nginx/storage1/access.log main;
error_log /var/log/nginx/storage1/error.log warn;
keepalive_timeout 60;
proxy_connect_timeout 60;
proxy_read_timeout 60;
proxy_send_timeout 60;
location / {
#root /home/lcstorage/lcstorage;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://lcstorage;
}
}
ログを書き込むディレクトリを忘れずに作っておく。
これで準備はできたはずだ。Nginx を再起動しよう。
[takatoh@rollo conf.d]$ sudo systemctl restart nginx
で、別マシンから http://storage1/ にアクセスしてみると、結果はこうだった。
502 Bad Gateway
あー、これはあれだ、SELinux のせいだ。試しに SELinux を Permissive モードにしてみる。
[takatoh@rollo ~]$ sudo setenforce 0
[takatoh@rollo ~]$ getenforce
Permissive
この状態でもう一度アクセスしていると、ちゃんと File not found. と表示された。なんどもいうけど、返すファイルがないのでこれが正しい動作だ。
つまり、SELinux をどうにかしてやらないといけないわけだ。だけどググってみると、解決策として出てくるのは SELinux を無効にしろ、っていうのばっかり。ちゃんと使い方を説明しているページはほとんど無い。そんな中で参考になったのが以下のページ。
cf. 【ゼロから始める】初期設定のみのLinuxサーバーに既存のRailsアプリとWebサーバーを導入する – Takeshi’s Blog
と、そこからリンクされているページ。
cf. RedmineをCentOS 7上で動かすーUnicornとNginx編 – ソフトウェアエンジニアリング
Nginx のエラーログを調べると:
2019/11/23 11:33:23 [crit] 2526#0: *1 connect() to unix:/run/lcstorage/unicorn.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.1.11, server: storage1, request: "GET / HTTP/1.1", upstream: "http://unix:/run/lcstorage/unicorn.sock:/", host: "storage1"
となっていて、ソケットファイルにアクセスできないようだ。じゃあ、ソケットファイルのパーミッションはどうなってるかというと:
[takatoh@rollo ~]$ ls -lZ /run/lcstorage
合計 0
srwxrwxrwx. 1 lcstorage lcstorage unconfined_u:object_r:var_run_t:s0 0 11月 23 11:42 unicorn.sock
Z は SELinux のアクセス権限を表示するオプション。うん、よくわからん。SELinux が原因かどうかは /var/log/audit/audit.log を調べるとわかるらしい。再度 SELinux を有効にしてアクセスしてみてから:
[takatoh@rollo ~]$ sudo cat /var/log/audit/audit.log | grep nginx | tail
type=SERVICE_STOP msg=audit(1574476367.153:1276): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=nginx comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'UID="root" AUID="unset"
type=SERVICE_START msg=audit(1574476367.207:1277): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=nginx comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'UID="root" AUID="unset"
type=AVC msg=audit(1574476403.391:1281): avc: denied { connectto } for pid=2526 comm="nginx" path="/run/lcstorage/unicorn.sock" scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket permissive=0
type=SYSCALL msg=audit(1574476403.391:1281): arch=c000003e syscall=42 success=no exit=-13 a0=e a1=561f05479e28 a2=6e a3=7ffe9aa20e0c items=0 ppid=2522 pid=2526 auid=4294967295 uid=977 gid=975 euid=977 suid=977 fsuid=977 egid=975 sgid=975 fsgid=975 tty=(none) ses=4294967295 comm="nginx" exe="/usr/sbin/nginx" subj=system_u:system_r:httpd_t:s0 key=(null)ARCH=x86_64 SYSCALL=connect AUID="unset" UID="nginx" GID="nginx" EUID="nginx" SUID="nginx" FSUID="nginx" EGID="nginx" SGID="nginx" FSGID="nginx"
type=AVC msg=audit(1574476651.650:1290): avc: denied { connectto } for pid=2526 comm="nginx" path="/run/lcstorage/unicorn.sock" scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket permissive=1
type=SYSCALL msg=audit(1574476651.650:1290): arch=c000003e syscall=42 success=yes exit=0 a0=e a1=561f05479e28 a2=6e a3=7ffe9aa20e0c items=0 ppid=2522 pid=2526 auid=4294967295 uid=977 gid=975 euid=977 suid=977 fsuid=977 egid=975 sgid=975 fsgid=975 tty=(none) ses=4294967295 comm="nginx" exe="/usr/sbin/nginx" subj=system_u:system_r:httpd_t:s0 key=(null)ARCH=x86_64 SYSCALL=connect AUID="unset" UID="nginx" GID="nginx" EUID="nginx" SUID="nginx" FSUID="nginx" EGID="nginx" SGID="nginx" FSGID="nginx"
type=AVC msg=audit(1574477463.658:1309): avc: denied { connectto } for pid=2526 comm="nginx" path="/run/lcstorage/unicorn.sock" scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket permissive=1
type=SYSCALL msg=audit(1574477463.658:1309): arch=c000003e syscall=42 success=yes exit=0 a0=e a1=561f05479e28 a2=6e a3=7ffe9aa20e0c items=0 ppid=2522 pid=2526 auid=4294967295 uid=977 gid=975 euid=977 suid=977 fsuid=977 egid=975 sgid=975 fsgid=975 tty=(none) ses=4294967295 comm="nginx" exe="/usr/sbin/nginx" subj=system_u:system_r:httpd_t:s0 key=(null)ARCH=x86_64 SYSCALL=connect AUID="unset" UID="nginx" GID="nginx" EUID="nginx" SUID="nginx" FSUID="nginx" EGID="nginx" SGID="nginx" FSGID="nginx"
type=AVC msg=audit(1574477957.417:1347): avc: denied { connectto } for pid=2526 comm="nginx" path="/run/lcstorage/unicorn.sock" scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket permissive=0
type=SYSCALL msg=audit(1574477957.417:1347): arch=c000003e syscall=42 success=no exit=-13 a0=e a1=561f05479e28 a2=6e a3=7ffe9aa20e0c items=0 ppid=2522 pid=2526 auid=4294967295 uid=977 gid=975 euid=977 suid=977 fsuid=977 egid=975 sgid=975 fsgid=975 tty=(none) ses=4294967295 comm="nginx" exe="/usr/sbin/nginx" subj=system_u:system_r:httpd_t:s0 key=(null)ARCH=x86_64 SYSCALL=connect AUID="unset" UID="nginx" GID="nginx" EUID="nginx" SUID="nginx" FSUID="nginx" EGID="nginx" SGID="nginx" FSGID="nginx"
さぱーりわからん。けど、どうやら↓ここらしい。
type=AVC msg=audit(1574477957.417:1347): avc: denied { connectto } for pid=2526 comm="nginx" path="/run/lcstorage/unicorn.sock" scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket permissive=0
nginx が /run/lcstorage/unicorn.sock にアクセスしようとして denied になってるようだ。つまりここを何とかすればいいわけ。
SELinux の上のアクセスを許可する設定は、/var/log/audit/audit.log ファイルから audit2allow コマンドで作れるようだ。まず確認。
[takatoh@rollo ~]$ sudo grep nginx /var/log/audit/audit.log | audit2allow
#============= httpd_t ==============
#!!!! This avc can be allowed using the boolean 'httpd_can_network_connect'
allow httpd_t glance_port_t:tcp_socket name_connect;
#!!!! This avc can be allowed using one of the these booleans:
# httpd_can_network_connect, httpd_graceful_shutdown, httpd_can_network_relay, nis_enabled
allow httpd_t http_port_t:tcp_socket name_connect;
allow httpd_t unconfined_t:unix_stream_socket connectto;
設定用のファイルを作るにはこうする。
[takatoh@rollo ~]$ sudo grep nginx /var/log/audit/audit.log | audit2allow -M nginx
[sudo] takatoh のパスワード:
******************* 重要 ********************
このポリシーパッケージを有効にするには、以下を実行して下さい:
semodule -i nginx.pp
指示にあるようにして、SELinux に設定する。
[takatoh@rollo ~]$ sudo semodule -i nginx.pp
さてこれでどうだろう。はたして、別のマシンからブラウザでアクセスしてみると、ちゃんと File not found. って表示された。なんどもいうけどこれが(ry。
つぎは web アプリをサービスとして登録する。/etc/systemd/system ディレクトリの下に lcstorage.service ファイルを作る。
[Unit]
Description=LatherCraft storage service
After=network.target
[Service]
Type=forking
PIDFile=/home/lcstorage/lcstorage/unicorn.pid
ExecStart=/usr/local/bin/bundle exec unicorn -c unicorn.conf -E production -D
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -QUIT $MAINPID
WorkingDirectory=/home/lcstorage/lcstorage
User=lcstorage
Group=lcstorage
[Install]
WantedBy=multi-user.target
これで起動してみる。
[takatoh@rollo system]$ sudo systemctl start lcstorage
あれ?おかしい。プロンプトが戻ってこない。ほかのターミナルからステータスを見てみると:
[lcstorage@rollo lcstorage]$ systemctl status lcstorage
● lcstorage.service - LatherCraft storage service
Loaded: loaded (/etc/systemd/system/lcstorage.service; disabled; vendor pres>
Active: activating (start) since Sat 2019-11-23 12:57:57 JST; 1min 14s ago
Process: 3931 ExecStart=/usr/local/bin/bundle exec unicorn -c unicorn.conf -E production -D (code=exited, status=0/SUCCESS)
Tasks: 6 (limit: 26213)
Memory: 31.4M
CGroup: /system.slice/lcstorage.service
├─3936 unicorn master -c unicorn.conf -E production -D production -D
├─3939 unicorn worker[0] -c unicorn.conf -E production -D productio>
└─3942 unicorn worker[1] -c unicorn.conf -E production -D productio>
11月 23 12:57:57 rollo systemd[1]: Starting LatherCraft storage service…
11月 23 12:57:58 rollo systemd[1]: lcstorage.service: Can't convert PID files /home/lcstorage/lcstorage/unicorn.pid O_PATH file descriptor to proper file descriptor: Permission denied
11月 23 12:57:58 rollo systemd[1]: lcstorage.service: Can't convert PID files /home/lcstorage/lcstorage/unicorn.pid O_PATH file descriptor to proper file descriptor: Permission denied
pid ファイルにアクセスできないっぽい?じゃあ、場所を変えてみようか。/home/lcstorage/lcstorage/unicorn.conf と /etc/systemd/system/lcstorage.service の両方で pid ファイルを作る場所を /run に変えてみた。
でもまだダメ。もとに戻す。もう一度やってみてもこうなる。
[takatoh@rollo system]$ sudo systemctl start lcstorage
Job for lcstorage.service failed because a timeout was exceeded.
See "systemctl status lcstorage.service" and "journalctl -xe" for details.
で、SELinux を無効にしてやってみた。
[takatoh@rollo system]$ sudo setenforce 0
[takatoh@rollo system]$ getenforce
Permissive
[takatoh@rollo system]$ sudo systemctl start lcstorage
あ、これだとすんなりいく。ブラウザからアクセスしてもうまくいった。またお前か、SELinux!
さっきとおなじように /var/log/audit/audit.log を調べてみるとこうなってた。
type=AVC msg=audit(1574483152.115:1720): avc: denied { open } for pid=1 comm="systemd" path="/home/lcstorage/lcstorage/unicorn.pid" dev="dm-2" ino=24382 scontext=system_u:system_r:init_t:s0 tcontext=system_u:object_r:user_home_t:s0 tclass=file permissive=1
やっぱり pid ファイルにアクセスできないみたいだ。ポリシーを作ってやる。
[takatoh@rollo ~]$ sudo grep unicorn /var/log/audit/audit.log | audit2allow -M unicorn
[takatoh@rollo ~]$ sudo semodule -i unicorn.pp
これでどうだろう。
[takatoh@rollo ~]$ sudo setenforce 1
[takatoh@rollo ~]$ getenforce
Enforcing
[takatoh@rollo ~]$ sudo systemctl start lcstorage
お、うまくいったっぽい。ブラウザからアクセスしても大丈夫だった。
最後に。マシンを起動した時に自動起動するようにする。
[takatoh@rollo ~]$ sudo systemctl enable lcstorage
Created symlink /etc/systemd/system/multi-user.target.wants/lcstorage.service → /etc/systemd/system/lcstorage.service.
はぁ、長かった。