Nginx + Unicorn on CentOS 8 with SELinux

前のエントリで 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.

はぁ、長かった。

カテゴリー: CentOS, Ruby パーマリンク

コメントを残す

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

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください