はじめに
nginx, Rails連携させている環境において、assets配下のファイルにアクセスできない場合があるので解決方法をメモしておきます。
原因
ケース1:productionモードでassets配下のアクセスをRailsへ転送している
ケース2:アクセス権が原因でnginxがassets配下のファイルにアクセスできない
ケース3:SELinuxが原因でnginxがassets配下のファイルにアクセスできない
環境
CentOS 7.3.1611
Rails 5.1.2
nginx 1.10.2
事前準備
Rails : 3000ポートでサーバ起動しておく
nginx : アクセスを3000ポートへ転送する
問題点
Railsへアクセスした際にcss, jsが読み込まれない
ケース1:productionモードでassets配下のアクセスをRailsへ転送している
調査
このケースではアクセス時にnginxのエラーログは出力されない
$ sudo tail /var/log/nginx/hello-app_error.log
Railsのログでcss, jsへのアクセス時にNo route matches
と出力される
tail -f log/production.log
F, [2017-07-30T05:39:40.310181 #4934] FATAL -- : [f8ec5376-7c17-4aa0-b46b-e3669b834c5e] ActionController::R
outingError (No route matches [GET] "/assets/application-35729bfbaf9967f119234595ed222f7ab14859f304ab0acc54
51afb387f637fa.css"):
F, [2017-07-30T05:39:40.439806 #4934] FATAL -- : [6bfdd3a1-fbae-4cf3-9566-c8865ee56988] ActionController::R
outingError (No route matches [GET] "/assets/application-a0c66820a1b25b7b91aab7fb553a37bc0728f9b1df860c3660
e590597bf9cafa.js"):
暫定対処/ローカル環境
config/environments/production.rb
でconfig.public_file_server.enabled
を有効にする
config.public_file_server.enabled = true
解決方法
nginxからassets配下のファイルへアクセスさせる
nginxの設定ファイルを編集
upstream hello-app {
server unix:/home/xxx/hello-app/tmp/sockets/puma.sock;
}
server {
listen 80;
server_name hello-app;
root /path/hello-app/public;
access_log /var/log/nginx/helllo-app_access.log;
error_log /var/log/nginx/hello-app_error.log;
# ==追記ここから===
location ~ ^/assets/ {
root /home/xxx/hello-app/public;
}
# ==追記ここまで===
location / {
client_max_body_size 0;
gzip off;
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Host $http_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 $scheme;
proxy_pass http://127.0.0.1:3000;
}
}
nginxに設定ファイルを再読込させる
# nginxを手動起動していた場合
$ sudo nginx -s reload
# nginxをサービス起動していた場合
$ sudo service nginx reload
アクセス確認
http://xxx.xxx.xxx.xxx
→ css, jsが読み込めたらOK
→ css, jsが404エラーとなる場合はpublicディレクトリへのパスを再確認
→ css, jsが403エラーとなる場合はケース2〜3も確認する
ケース2:アクセス権が原因でnginxがassets配下のファイルにアクセスできない
調査
このケースではアクセス時にnginxのエラーログにopen() "/home/xxx/hello-app/public/assets/xxx.css" failed (13: Permission denied)
と出力される
$ sudo tail /var/log/nginx/hello-app_error.log
2017/07/30 06:00:12 [error] 5175#0: *215 open() "/home/xxx/hello-app/public/assets/application-3572
9bfbaf9967f119234595ed222f7ab14859f304ab0acc5451afb387f637fa.css" failed (13: Permission denied), client: 1
xxx.xxx.xxx.xxx, server: hello-app, request: "GET /assets/application-35729bfbaf9967f119234595ed222f7ab14859
f304ab0acc5451afb387f637fa.css HTTP/1.1", host: "xxx.xxx.xxx.xxx", referrer: "http://xxx.xxx.xxx.xxx/"
解決方法
/
から/public
までのディレクトリにnginx実行ユーザへのアクセス権が付与されてるか確認する。付与されてないディレクトリにはアクセス権を付与する
# アクセス権を確認
$ ls -l /home/xxx
# アクセス権を付与
$ chmod 755 /home/xxx
アクセス確認
http://xxx.xxx.xxx.xxx
→ css, jsが読み込めたらOK
→ css, jsが403エラーとなる場合は3も確認する
ケース3:SELinuxが原因でnginxがassets配下のファイルにアクセスできない
調査
このケースでもアクセス時にnginxのエラーログにopen() "/home/xxx/hello-app/public/assets/xxx.css" failed (13: Permission denied)
と出力される
$ sudo tail /var/log/nginx/hello-app_error.log
2017/07/30 06:00:12 [error] 5175#0: *215 open() "/home/xxx/hello-app/public/assets/application-3572
9bfbaf9967f119234595ed222f7ab14859f304ab0acc5451afb387f637fa.css" failed (13: Permission denied), client: 1
xxx.xxx.xxx.xxx, server: hello-app, request: "GET /assets/application-35729bfbaf9967f119234595ed222f7ab14859
f304ab0acc5451afb387f637fa.css HTTP/1.1", host: "xxx.xxx.xxx.xxx", referrer: "http://xxx.xxx.xxx.xxx/"
解決方法
SELinuxのモジュールを追加・更新する
(過去にモジュールを追加していた場合でも下記コマンドの結果と設定済みモジュールに差分がないか確認する)
# ポリシー確認
$ sudo cat /var/log/audit/audit.log | grep nginx | audit2allow -m nginx
module nginx 1.0;
require {
type httpd_t;
type user_home_t;
type ntop_port_t;
class tcp_socket name_connect;
class file { open read };
}
#============= httpd_t ==============
#!!!! This avc is allowed in the current policy
allow httpd_t ntop_port_t:tcp_socket name_connect;
#!!!! This avc can be allowed using the boolean 'httpd_read_user_content'
allow httpd_t user_home_t:file read;
# モジュール作成
$ sudo cat /var/log/audit/audit.log | audit2allow -M nginx
# インストール
$ sudo semodule -i nginx.pp
アクセス確認
http://xxx.xxx.xxx.xxx
→ css, jsが読み込めたらOK
→ css, jsが403エラーとなる場合は再度ポリシー確認を実施する
補足:
作成されるポリシーの内容はaudit.logの内容によって変わる
SELinuxを無効にして解決する場合はモジュールの更新を実施する
今回は環境構築中に以下のように変化した
require {
type httpd_t;
type ntop_port_t;
class tcp_socket name_connect;
}
↓
require {
type httpd_t;
type user_home_t;
type ntop_port_t;
class tcp_socket name_connect;
class file { open read };
}
補足:
SELinuxセキュリティコンテキストはlsコマンドの-Z
オプションで確認できる
$ ls -Z
最終手段
SELinuxを一時的に無効にする
# SELinuxの無効化
$ sudo setenforce 0
# SELinuxの状態確認
$ sudo getenforce
Permissive
SELinuxの無効を永続化する
# 設定変更
$ sudo vi /etc/selinux/config
SELINUX=disabled
# 再起動
$ sudo reboot