「Nginx」の版間の差分
Kusanaginoturugi (トーク | 投稿記録) (→設定の確認: 英語版に差し替え) |
Kusanaginoturugi (トーク | 投稿記録) (→トラブルシューティング: 英語版に差し替え) |
||
715行目: | 715行目: | ||
}} |
}} |
||
+ | === Error: The page you are looking for is temporarily unavailable. Please try again later. (502 Bad Gateway) === |
||
− | === Error: 404 (Pathinfo error) === |
||
+ | This is because the FastCGI server has not been started, or the socket used has wrong permissions. |
||
− | いくつかのフレームワーク (thinkphp、cakephp など)や CMS では pathinfo が必要です。 |
||
+ | Try [https://stackoverflow.com/questions/4252368/nginx-502-bad-gateway/16497957#16497957 out this answer] to fix the 502 error. |
||
− | 1. {{ic|/etc/php/php.ini}} ファイルを開き、次のように付け加えます |
||
− | cgi.fix_pathinfo=1 |
||
− | 2. {{ic|/etc/nginx/nginx.conf}} を開き、次の部分をコメントアウトします |
||
+ | In Arch Linux, the configuration file mentioned in above link is {{ic|/etc/php/php-fpm.conf}}. |
||
− | location ~ \.php$ { |
||
− | ... |
||
− | } |
||
+ | === Error: No input file specified === |
||
− | を |
||
+ | 1. Verify that variable {{ic|open_basedir}} in {{ic|/etc/php/php.ini}} contains the correct path specified as {{ic|root}} argument in {{ic|nginx.conf}} (usually {{ic|/usr/share/nginx/}}). When using [https://php-fpm.org/ PHP-FPM] as FastCGI server for PHP, you may add {{ic|<nowiki>fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/:/tmp/:/proc/"</nowiki>;}} in the {{ic|location}} block which aims for processing php file in {{ic|nginx.conf}}. |
||
− | #location ~ \.php$ { |
||
− | #... |
||
− | #} |
||
+ | 2. Another occasion is that, wrong {{ic|root}} argument in the {{ic|location ~ \.php$}} section in {{ic|nginx.conf}}. Make sure the {{ic|root}} points to the same directory as it in {{ic|location /}} in the same server. Or you may just set root as global, do not define it in any location section. |
||
− | そして以下を加えます |
||
− | location ~ ^(.+\.php)(.*)$ { |
||
− | root /srv/http/nginx; |
||
− | fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; |
||
− | #fastcgi_pass 127.0.0.1:9000; #Un-comment this and comment "fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;" if you are not using php-fpm. |
||
− | fastcgi_index index.php; |
||
− | set $document_root2 $document_root; |
||
− | if ($document_root2 ~ "^(.*\\\\).*?[\\\\|\/]\.\.\/(.*)$") { set $document_root2 $1$2; } |
||
− | if ($document_root2 ~ "^(.*\\\\).*?[\\\\|\/]\.\.\/(.*)$") { set $document_root2 $1$2; } |
||
− | if ($document_root2 ~ "^(.*\\\\).*?[\\\\|\/]\.\.\/(.*)$") { set $document_root2 $1$2; } |
||
− | if ($document_root2 ~ "^(.*\\\\).*?[\\\\|\/]\.\.\/(.*)$") { set $document_root2 $1$2; } |
||
− | if ($document_root2 ~ "^(.*\\\\).*?[\\\\|\/]\.\.\/(.*)$") { set $document_root2 $1$2; } |
||
− | fastcgi_split_path_info ^(.+\.php)(.*)$; |
||
− | fastcgi_param SCRIPT_FILENAME $document_root2$fastcgi_script_name; |
||
− | fastcgi_param PATH_INFO $fastcgi_path_info; |
||
− | fastcgi_param PATH_TRANSLATED $document_root2$fastcgi_path_info; |
||
− | include fastcgi_params; |
||
− | fastcgi_param DOCUMENT_ROOT $document_root2; |
||
− | } |
||
+ | 3. Check permissions: e.g. {{ic|http}} for user/group, {{ic|755}} for directories and {{ic|644}} for files. Remember the entire path to the {{ic|html}} directory should have the correct permissions. See [[ファイルのパーミッションと属性#Bulk chmod]] to bulk modify a directory tree. |
||
− | try_files を使う方法もあります: |
||
− | server { |
||
− | .. |
||
− | root /usr/share/nginx/html; |
||
− | index index.php; |
||
− | location / { |
||
− | try_files $uri $uri/ /index.php?$args; |
||
− | } |
||
− | } |
||
+ | 4. おそらくスクリプトのフルパスを含んだ SCRIPT_FILENAME がありません。 |
||
− | === Error: The page you are looking for is temporarily unavailable. Please try again later. === |
||
− | |||
− | FastCGI サーバーが動作していないか、ソケットが間違ったパーミッションに設定されています。 |
||
− | |||
− | === Error: No input file specified === |
||
− | |||
− | おそらくスクリプトのフルパスを含んだ SCRIPT_FILENAME がありません。 |
||
nginx の設定 (fastcgi_param SCRIPT_FILENAME) が完全でも、このエラーは php が requestd スクリプトをロードできないことを意味しています。これは単純にパーミッションの問題であることが普通で、root で php-cgi を実行するか |
nginx の設定 (fastcgi_param SCRIPT_FILENAME) が完全でも、このエラーは php が requestd スクリプトをロードできないことを意味しています。これは単純にパーミッションの問題であることが普通で、root で php-cgi を実行するか |
||
# spawn-fcgi -a 127.0.0.1 -p 9000 -f /usr/bin/php-cgi |
# spawn-fcgi -a 127.0.0.1 -p 9000 -f /usr/bin/php-cgi |
||
779行目: | 741行目: | ||
# spawn-fcgi -a 127.0.0.1 -p 9000 -u www -g www -f /usr/bin/php-cgi |
# spawn-fcgi -a 127.0.0.1 -p 9000 -u www -g www -f /usr/bin/php-cgi |
||
+ | 5. If you are running php-fpm with chrooted nginx ensure {{ic|chroot}} is set correctly within {{ic|/etc/php-fpm/php-fpm.d/www.conf}} (or {{ic|/etc/php-fpm/php-fpm.conf}} if working on older version) |
||
− | 他の可能性としては、{{ic|nginx.conf}} 内の "location ~ \.php$" セクションの "root" 引数が間違っていることがありえます。"root" が同じサーバーの "location /" と同じディレクトリを示しているか確認してください。もしくは root をグローバルに設定するには、location セクションで定義しないでください。 |
||
+ | |||
+ | === Warning: Could not build optimal types_hash === |
||
+ | When starting the {{ic|nginx.service}}, the process might log the message: |
||
− | Also keep in mind that your php script path was defined as {{ic|/srv/http}} by default using the variable "open_basedir" in {{ic|/etc/php/php.ini}}; you can change them if you need. |
||
+ | [warn] 18872#18872: could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size |
||
− | Also notice that not only php script should have read permission, but also the entire directory structure should have execute permission so that PHP user can traverse the path. |
||
+ | To fix this warning, increase the values for these keys inside the {{ic|http}} block [https://nginx.org/en/docs/http/ngx_http_core_module.html#types_hash_max_size] [https://nginx.org/en/docs/http/server_names.html]: |
||
− | === Error: FastCGI で空のページが表示される === |
||
+ | {{hc|/etc/nginx/nginx.conf| |
||
− | access.log にエラーが表示されず、コード200が返されるのに以下のような空のページが表示される場合: |
||
+ | http { |
||
+ | types_hash_max_size 4096; |
||
+ | server_names_hash_bucket_size 128; |
||
+ | ... |
||
+ | } |
||
+ | }} |
||
+ | === Cannot assign requested address === |
||
− | <html> |
||
− | <head></head> |
||
− | <body></body> |
||
− | </html> |
||
+ | The full error from {{ic|nginx.service}} [[unit status]] is |
||
− | [http://beutelevision.com/blog2/2013/08/26/nginx-with-php-fpm-generating-blank-page/ Thomas Beutel のブログ] に書かれた解決方法: |
||
+ | [emerg] 460#460: bind() to A.B.C.D:443 failed (99: Cannot assign requested address) |
||
− | {{ic|/etc/nginx/nginx.conf}} を編集して php の {{ic|location}} セクションに {{ic|fastcgi_param}} という行を追加: |
||
+ | Even, if your nginx unit-file is configured to run after {{ic|network.target}} with systemd, nginx may attempt to listen at an address that is configured but not added to any interface yet. Verify that this the case by manually running [[start]] for nginx (thereby showing the IP address is configured properly). Configuring nginx to listen to any address will resolve this issue. Now if your use case requires listening to a specific address, one possible solution is to reconfigure systemd. |
||
− | location ~ \.php$ { |
||
− | ... |
||
− | include fastcgi_params; |
||
− | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; |
||
− | ... |
||
− | } |
||
+ | To start nginx after all configured network devices are up and assigned an IP address, append {{ic|network-online.target}} to {{ic|After<nowiki>=</nowiki>}} within {{ic|nginx.service}} and [[start/enable]] {{ic|systemd-networkd-wait-online.service}}. |
||
− | php_fpm では PHP ファイルのパスを認識するために以上のように設定する必要があります。 |
||
== 参照 == |
== 参照 == |
2022年10月10日 (月) 09:35時点における版
nginx ("エンジンエックス"と発音します)は2005年から Igor Sysoev(ロシア)によって開発されている、フリーでオープンソースかつハイパフォーマンスな HTTP サーバーかつリバースプロクシで、IMAP/POP3 プロクシサーバーとしても機能します。Nginx は主に、その安定性・多機能・単純な設定・低リソース消費によって知られています。
この記事ではnginxの設定方法と、#FastCGIを使ってPHPと統合する方法を説明します。
インストール
公式リポジトリから nginx-mainline (メインラインブランチ: 最新の機能・アップデート・修正) か nginx (安定ブランチ: 重要な修正のみを適応) のどちらかをインストールできます。
Ruby on Rails のためにインストールするには、Ruby on Rails#Rails パーフェクトセットアップを参照してください。
セキュリティを向上させるために chroot によるインストールをするには、#chroot でインストール を参照してください。
サービスの開始
Nginx サービスを走らせるには:
# systemctl start nginx
スタートアップ時に Nginx サービスを起動するには:
# systemctl enable nginx
http://127.0.0.1 にデフォルトで表示されるページは:
/usr/share/nginx/html/index.html
設定
nginx における最初の手順は 公式のビギナーズガイド で説明されています。/etc/nginx/
にあるファイルを編集することで Nginx の設定ができます。メインの設定ファイルは /etc/nginx/nginx.conf
です。
より詳しい解説は、公式の ドキュメント にある Nginx Configuration Examples にあります。
以下の例は、最も一般的な使用例をカバーしています。ここでは、ドキュメントのデフォルトの場所 (/usr/share/nginx/html
) を使用することを想定しています。そうでない場合は、代わりにあなたのパスを指定してください。
設定例
/etc/nginx/nginx.conf
user http; worker_processes auto; worker_cpu_affinity auto; events { multi_accept on; worker_connections 1024; } http { charset utf-8; sendfile on; tcp_nopush on; tcp_nodelay on; server_tokens off; log_not_found off; types_hash_max_size 4096; client_max_body_size 16M; # MIME include mime.types; default_type application/octet-stream; # logging access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log warn; # load configs include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; }
一般設定
プロセス数とコネクション数
worker_processes
の適当な値を探って下さい。この設定は最終的に nginx が受け入れる接続の数と利用できるプロセスの数を定義します。通常、システムのハードウェアのスレッド数にすると良いでしょう。また、バージョン 1.3.8 と 1.2.5 から worker_processes
には auto
と設定することができ、最適な値を自動的に検出します (ソース)。
nginx が受け入れる最大接続数は max_clients = worker_processes * worker_connections
で計算できます。
別のユーザーで実行する
デフォルトでは、nginx はマスタープロセスを root
で、ワーカープロセスを http
ユーザで実行します。ワーカープロセスを別のユーザで実行するには、nginx.conf
の user
ディレクティブを変更します。
/etc/nginx/nginx.conf
user user [group];
group が省略された場合は、user と同じ名前のグループが使用されます。
サーバーブロック
server
ブロックを使うことで複数のドメインを利用することができます。"バーチャルホスト"とも呼ばれますが、これは Apache の用語です。server
ブロックの利用方法は Apache とは異なっています。
以下の例では2つのドメインの接続をサーバーが待機します: domainname1.dom
と domainname2.dom
:
/etc/nginx/nginx.conf
... server { listen 80; server_name domainname1.dom; root /usr/share/nginx/domainname1.dom/html; location / { index index.php index.html index.htm; } } server { listen 80; server_name domainname2.dom; root /usr/share/nginx/domainname2.dom/html; ... } ... }
nginx.service
を再起動して変更を適用します。
クライアントからの接続時にこれらのドメイン名を解決するには、BIND や dnsmasq などのDNSサーバーを設定する必要があります。
ローカルマシンでバーチャルホストをテストするには、/etc/hosts
ファイルにバーチャルネームを追加してください:
127.0.0.1 domainname1.dom 127.0.0.1 domainname2.dom
サーバーエントリの管理
異なる server
ブロックを異なるファイルに配置することができます。これにより、特定のサイトを簡単に有効または無効にできます。
次のディレクトリを作成します。
# mkdir /etc/nginx/sites-available # mkdir /etc/nginx/sites-enabled
sites-available
ディレクトリに、一つ以上のサーバーブロックを含むファイルを作成します。
/etc/nginx/sites-available/example.conf
server { listen 443 ssl http2; listen [::]:443 ssl http2; ... }
http
ブロックの最後に、include sites-enabled/*;
を追加します。
/etc/nginx/nginx.conf
http { ... include sites-enabled/*; }
サイトを有効にするには、シンボリックリンクを作成するだけです。
# ln -s /etc/nginx/sites-available/example.conf /etc/nginx/sites-enabled/example.conf
サイトを無効にするには、アクティブなシンボリックリンクのリンクを解除します。
# unlink /etc/nginx/sites-enabled/example.conf
nginx.service
を リロード/リスタート して、サイト設定の変更を有効にします。
TLS/SSL
SSL を使用するには、openssl をインストールする必要があります。
自己署名証明書を作成してください (キーのサイズや効力の日数は変更できます):
# mkdir /etc/nginx/ssl # cd /etc/nginx/ssl # openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out cert.key # chmod 600 cert.key # openssl req -new -key cert.key -out cert.csr # openssl x509 -req -days 365 -in cert.csr -signkey cert.key -out cert.crt
TLS/SSL を用いる場合の nginx.conf
設定サンプル:
/etc/nginx/nginx.conf
http { ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"; add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; ssl_session_tickets off; ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8 8.8.4.4 valid=300s; # Google DNS Servers resolver_timeout 5s; } server { #listen 80; # Uncomment to also listen for HTTP requests listen 443 ssl; server_name localhost; ssl_certificate ssl/server.crt; ssl_certificate_key ssl/server.key; root /usr/share/nginx/html; location / { index index.html index.htm; } }
nginx.service
を再起動して変更を適用します。
FastCGI
FastCGI、または FCGI はウェブサーバーでインタラクティブなプログラムを動作させるためのプロトコルです。FastCGI は Common Gateway Interface (CGI) の変種で、ウェブサーバーと CGI プログラムのオーバーヘッドを減らすよう設計されていて、サーバーはより多くのウェブページのリクエストを一度に捌くことができます。
Nginx には FastCGI が組み込まれており多くの外部ツールが動きます、例えば Perl、PHP、Python など。これらを使うためにはまず FastCGI サーバーを動かす必要があります。
PHP を動かす
PHP のために FastCGI サーバーを動かす方法は複数あります。ここでは推奨方法として php-fpm を使う方法を記載しています。
手順1: PHP の設定
php をインストールしてください。/etc/php/php.ini
の中にある open_basedir
に PHP ファイルが含まれているベースディレクトリを (/srv/http/
や /usr/share/webapps/
のような感じで)指定しなくてはなりません:
open_basedir = /usr/share/webapps/:/srv/http/:/home/:/tmp/:/usr/share/pear/
そうしたら必要なモジュールを設定しましょう。例えば sqlite3 を使うなら php-sqlite をインストールして、/etc/php/php.ini
の次の行をアンコメントして有効にします:
extension=sqlite3.so
MariaDB
MariaDB で説明されているようにして MySQL/MariaDB を設定してください。
/etc/php/php.ini
の以下の行の 少なくともどれか一つ をアンコメント:
extension=pdo_mysql.so extension=mysqli.so
ウェブスクリプトのために最小権限の MySQL ユーザーを追加することができます。また、/etc/mysql/my.cnf
を編集して skip-networking
行をアンコメントすると MySQL サーバーはローカルホストからしかアクセスできなくなります。変更を適用するには MySQL を再起動する必要があります。
手順2: php-fpm
php-fpm をインストールします:
# pacman -S php-fpm
設定ファイルは /etc/php/php-fpm.conf
です。
サービスを動かします:
# systemctl start php-fpm
php-fpm
をスタートアップ時に有効にします:
# systemctl enable php-fpm.service
手順3: Nginx の設定
それぞれの server
ブロックの中の location
ブロックに PHP アプリケーションを次のように記述します:
location ~ \.php$ { fastcgi_pass unix:/run/php-fpm/php-fpm.sock; fastcgi_index index.php; include fastcgi.conf; }
/etc/nginx/php.conf
を作って設定をそこに書く場合、このファイルを server
ブロックに入れて下さい。
server = { ... include php.conf; ... }
.html や .htm ファイルを PHP として処理したい場合は、以下のようにしてください:
location ~ \.(php|html|htm)$ { fastcgi_pass unix:/run/php-fpm/php-fpm.sock; fastcgi_index index.php; include fastcgi.conf; }
拡張子が .php でないファイルを php-fpm で動かすことを /etc/php/php-fpm.conf
で有効にする必要があります:
security.limit_extensions = .php .html .htm
設定を変えた後は php-fpm デーモンを再起動してください。
# systemctl restart php-fpm
Nginx のための FastCGI 設定がある fastcgi.conf
か fastcgi_params
が含まれていますが、後者は使われなくなりました。これらのファイルは Nginx をインストールしたときに作られます。
最後に、Nginx が動作している場合は再起動してください:
# systemctl restart nginx
FastCGI をテストしたい場合は、/usr/share/nginx/html/index.php
を次の内容で作成して
<?php phpinfo(); ?>
ブラウザで http://127.0.0.1/index.php を開いて下さい。
以下は実際の設定例です。例の中では root
パスは server
の下に直接指定されており (デフォルト設定のように) location
の中には置いていません。
server { listen 80; server_name localhost; root /usr/share/nginx/html; location / { index index.html index.htm index.php; } location ~ \.php$ { #fastcgi_pass 127.0.0.1:9000; (depending on your php-fpm socket configuration) fastcgi_pass unix:/run/php-fpm/php-fpm.sock; fastcgi_index index.php; include fastcgi.conf; } }
CGI を動かす
この実装は CGI アプリケーションに必要です。
手順1: fcgiwrap
fcgiwrap をインストールしてください。
設定ファイルは /usr/lib/systemd/system/fcgiwrap.socket
です。
systemd の fcgiwrap.socket を有効化・起動します。
この systemd ユニットファイルは現在 ArchLinux のタスクページで議論されています。思い通りに動くか確認するためにユニットファイルを自分で検査すると良いでしょう。
マルチワーカースレッド
複数のワーカースレッドを生成したい場合は、multiwatchAUR を使用するのが推奨されています。これはクラッシュした子スレッドの再起動の面倒をみてくれます。multiwatch は systemd が作成したソケットを管理できないため、unix ソケットを作成するには spawn-fcgi
を使う必要がありますが、ユニットファイルから直接実行した場合は fcgiwrap には問題が生じません。
/usr/lib/systemd/system/fcgiwrap.service
から /etc/systemd/system/fcgiwrap.service
にユニットファイルをコピーして (存在する場合は fcgiwrap.socket
ユニットも)、ExecStart
行を必要に応じて修正してください。以下は multiwatchAUR を使用するユニットファイルです。fcgiwrap.socket
が実行中だったり有効になっていないことを確認してください、このユニットと衝突してしまうからです:
/etc/systemd/system/fcgiwrap.service
[Unit] Description=Simple CGI Server After=nss-user-lookup.target [Service] ExecStartPre=/bin/rm -f /run/fcgiwrap.socket ExecStart=/usr/bin/spawn-fcgi -u http -g http -s /run/fcgiwrap.sock -n -- /usr/bin/multiwatch -f 10 -- /usr/sbin/fcgiwrap ExecStartPost=/usr/bin/chmod 660 /run/fcgiwrap.sock PrivateTmp=true Restart=on-failure [Install] WantedBy=multi-user.target
-f 10
は生成する子スレッドの数に変更してください。
手順2: Nginx の設定
CGI ウェブアプリケーションを置くそれぞれの server
ブロックには以下のような location
ブロックを記述します:
location ~ \.cgi$ { root /path/to/server/cgi-bin; fastcgi_pass unix:/run/fcgiwrap.sock; include fastcgi.conf; }
fcgiwrap
のデフォルト (Unix) ソケットは /run/fcgiwrap.sock です。
chroot でインストール
chroot に Nginx をインストールすることでセキュリティレイヤーを追加することができます。セキュリティを最大限に高めるために、Nginx サーバーを動かすのに必要なファイルだけを入れて、全てのファイルは出来る限り最小限の権限にします。例えば、なるべく root が所有するようにして、/usr/bin
などのディレクトリは読み書きできないようにするなど。
Arch はデフォルトでサーバーを実行するための http
ユーザーとグループが設定されています。chroot は /srv/http
で動作させます。
この牢獄を作るための perl スクリプトが jail.pl gist にあります。このスクリプトを使用するか、またはこの記事の指示に従って作成するか選ぶことができます。スクリプトは root で実行してください。変更を適用する前に行をアンコメントする必要があります。
必要なデバイスを作成
Nginx には /dev/null
, /dev/random
, /dev/urandom
が必要です。これらを chroot にインストールするために /dev/
フォルダを作成してデバイスを mknod で追加します。chroot が危険になったときでも、攻撃者が /dev/sda1
などの重要なデバイスにアクセスするには chroot から脱出しなくてはならないようにするために、/dev/
を全てマウントはしません。
# export JAIL=/srv/http # mkdir $JAIL/dev # mknod -m 0666 $JAIL/dev/null c 1 3 # mknod -m 0666 $JAIL/dev/random c 1 8 # mknod -m 0444 $JAIL/dev/urandom c 1 9
必要なフォルダを作成
Nginx を適切に実行するためにはたくさんのファイルが必要になります。それらをコピーする前に、ファイルを保存するためのフォルダを作成してください。ここでは Nginx のドキュメントルートが /srv/http/www
であると仮定します。
# mkdir -p $JAIL/etc/nginx/logs # mkdir -p $JAIL/usr/{lib,bin} # mkdir -p $JAIL/usr/share/nginx # mkdir -p $JAIL/var/{log,lib}/nginx # mkdir -p $JAIL/www/cgi-bin # mkdir -p $JAIL/{run,tmp} # cd $JAIL; ln -s usr/lib lib
そして $JAIL/tmp
と $JAIL/run
を tmpfs でマウントします。攻撃者が RAM を全て喰いつくせないようにサイズを制限すると良いでしょう。
# mount -t tmpfs none $JAIL/run -o 'noexec,size=1M' # mount -t tmpfs none $JAIL/tmp -o 'noexec,size=100M'
再起動してもマウントが維持されるように、以下のエントリを /etc/fstab
に追加します:
/etc/fstab
tmpfs /srv/http/run tmpfs rw,noexec,relatime,size=1024k 0 0 tmpfs /srv/http/tmp tmpfs rw,noexec,relatime,size=102400k 0 0
chroot に移住
まず平易なファイルをコピーします。
# cp -r /usr/share/nginx/* $JAIL/usr/share/nginx # cp -r /usr/share/nginx/html/* $JAIL/www # cp /usr/bin/nginx $JAIL/usr/bin/ # cp -r /var/lib/nginx $JAIL/var/lib/nginx
そして必要なライブラリをコピーします。ldd を使ってライブラリを確認して適当な場所にコピーして下さい。ハードリンクよりはコピーが推奨されます。攻撃者が書き込み権限を得たときに本当のシステムファイルが破壊されたり改変される可能性があるためです。
$ ldd /usr/bin/nginx
linux-vdso.so.1 (0x00007fffc41fe000) libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f57ec3e8000) libcrypt.so.1 => /usr/lib/libcrypt.so.1 (0x00007f57ec1b1000) libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f57ebead000) libm.so.6 => /usr/lib/libm.so.6 (0x00007f57ebbaf000) libpcre.so.1 => /usr/lib/libpcre.so.1 (0x00007f57eb94c000) libssl.so.1.0.0 => /usr/lib/libssl.so.1.0.0 (0x00007f57eb6e0000) libcrypto.so.1.0.0 => /usr/lib/libcrypto.so.1.0.0 (0x00007f57eb2d6000) libdl.so.2 => /usr/lib/libdl.so.2 (0x00007f57eb0d2000) libz.so.1 => /usr/lib/libz.so.1 (0x00007f57eaebc000) libGeoIP.so.1 => /usr/lib/libGeoIP.so.1 (0x00007f57eac8d000) libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f57eaa77000) libc.so.6 => /usr/lib/libc.so.6 (0x00007f57ea6ca000) /lib64/ld-linux-x86-64.so.2 (0x00007f57ec604000)
# cp /lib64/ld-linux-x86-64.so.2 $JAIL/lib
/usr/lib
の中にあるファイルについては次のワンライナーが使えます:
# cp $(ldd /usr/bin/nginx | grep /usr/lib | sed -sre 's/(.+)(\/usr\/lib\/\S+).+/\2/g') $JAIL/usr/lib
必要なライブラリとシステムファイル以外のファイルをコピーします。
# cp /usr/lib/libnss_* $JAIL/usr/lib # cp -rfvL /etc/{services,localtime,nsswitch.conf,nscd.conf,protocols,hosts,ld.so.cache,ld.so.conf,resolv.conf,host.conf,nginx} $JAIL/etc
chroot のために制限を付けたユーザー・グループファイルを作成します。これにより chroot にアクセスするのに必要なシステムユーザー・グループが攻撃者に漏洩しなくなります。
$JAIL/etc/group
http:x:33: nobody:x:99:
$JAIL/etc/passwd
http:x:33:33:http:/:/bin/false nobody:x:99:99:nobody:/:/bin/false
$JAIL/etc/shadow
http:x:14871:::::: nobody:x:14871::::::
$JAIL/etc/gshadow
http::: nobody:::
# touch $JAIL/etc/shells # touch $JAIL/run/nginx.pid
最後にパーミッションをできるだけ制限的に設定してください。できるかぎり所有者を root にして書き込み不可にします。
# chown -R root:root $JAIL/ # chown -R http:http $JAIL/www # chown -R http:http $JAIL/etc/nginx # chown -R http:http $JAIL/var/{log,lib}/nginx # chown http:http $JAIL/run/nginx.pid # find $JAIL/ -gid 0 -uid 0 -type d -print | xargs sudo chmod -rw # find $JAIL/ -gid 0 -uid 0 -type d -print | xargs sudo chmod +x # find $JAIL/etc -gid 0 -uid 0 -type f -print | xargs sudo chmod -x # find $JAIL/usr/bin -type f -print | xargs sudo chmod ug+rx # find $JAIL/ -group http -user http -print | xargs sudo chmod o-rwx # chmod +rw $JAIL/tmp # chmod +rw $JAIL/run
サーバーがポート 80 (あるいは 0-1024 のどれかのポート) で待機する場合、chroot した実行ファイルに root 権限がなくてもポートを使えるように権限を与えてください:
# setcap 'cap_net_bind_service=+ep' $JAIL/usr/bin/nginx
nginx.service を変更して chroot を起動
nginx.service
ユニットファイルを編集する前に、ユニットファイルを /etc/systemd/system/
にコピーして /usr/lib/systemd/system/
のファイルよりも優先されるようにすると良いでしょう。nginx をアップグレードしたときにカスタムした .service ファイルが変更されなくなります。
# cp /usr/lib/systemd/system/nginx.service /etc/systemd/system/nginx.service
chroot で nginx を起動するために systemd ユニットを変更して、pid ファイルを chroot に保存します。
/etc/systemd/system/nginx.service
[Unit] Description=A high performance web server and a reverse proxy server After=syslog.target network.target [Service] Type=forking PIDFile=/srv/http/run/nginx.pid ExecStartPre=/usr/bin/chroot --userspec=http:http /srv/http /usr/bin/nginx -t -q -g 'pid /run/nginx.pid; daemon on; master_process on;' ExecStart=/usr/bin/chroot --userspec=http:http /srv/http /usr/bin/nginx -g 'pid /run/nginx.pid; daemon on; master_process on;' ExecReload=/usr/bin/chroot --userspec=http:http /srv/http /usr/bin/nginx -g 'pid /run/nginx.pid; daemon on; master_process on;' -s reload ExecStop=/usr/bin/chroot --userspec=http:http /srv/http /usr/bin/nginx -g 'pid /run/nginx.pid;' -s quit [Install] WantedBy=multi-user.target
chroot されていない nginx 環境は取り除いてもかまいません:
# pacman -Rsc nginx
chroot されていない nginx 環境を削除しない場合、実行中の nginx プロセスが chroot されているプロセスかどうか確認したくなるときがあるかもしれません。/proc/PID/root
シンボリックリンクを確認することでチェックできます。
# ps -C nginx | awk '{print $1}' | sed 1d | while read -r PID; do ls -l /proc/$PID/root; done
ヒントとテクニック
systemd を使って非特権で動作させる
nginx.service
のドロップインファイルを使用して、[Service]
の下の User
と任意で Group
を設定します。
/etc/systemd/system/nginx.service.d/user.conf
[Service] User=user Group=group
権限昇格に対してサービスを防御することができます:
/etc/systemd/system/nginx.service.d/user.conf
[Service] ... NoNewPrivileges=yes
それから user
が必要なファイルやポートにアクセスできるようにしてください。以下の項目に従って、nginx を起動します。
ポート
Linux はデフォルトでは root
以外が 1024 以下のポートを使うことができないようになっています。1024 よりも上のポートは使うことができます:
/etc/nginx/nginx.conf
server { listen 8080; }
/etc/systemd/system/nginx.service.d/user.conf
[Service] ... CapabilityBoundingSet= CapabilityBoundingSet=CAP_NET_BIND_SERVICE AmbientCapabilities= AmbientCapabilities=CAP_NET_BIND_SERVICE
PID ファイル
nginx はデフォルトでは /run/nginx.pid
を使います。user が書き込み可能なディレクトリを作成して PID ファイルをそこに配置します。systemd-tmpfiles を使用する例:
/etc/tmpfiles.d/nginx.conf
d /run/nginx 0775 root group - -
設定を実行:
# systemd-tmpfiles --create
元の nginx.service
に合わせて PID の値を編集:
/etc/systemd/system/nginx.service.d/user.conf
[Service] ... PIDFile=/run/nginx/nginx.pid ExecStart= ExecStart=/usr/bin/nginx -g 'pid /run/nginx/nginx.pid; error_log stderr;' ExecReload= ExecReload=/usr/bin/nginx -s reload -g 'pid /run/nginx/nginx.pid;'
/var/lib/nginx/*
/var/lib/nginx
の一部のディレクトリは root
として nginx でブートストラップする必要があります。サーバー全体を起動する必要はありません。nginx は設定テストでブートストラップを実行します。一回実行すればそれで十分です。
ログファイル & ディレクトリのパーミッション
設定テストの実行時に root
によって所有される壊れたログが作成されます。/var/log/nginx
のログを削除して新しく起動してください。
nginx サービスのユーザーから /var/log/nginx
に書き込む権限が必要です。パーミッションを変更するかディレクトリの所有者を変更してください。
systemd の別のスクリプト
On pure systemd you can get advantages of chroot + systemd. [1] Based on set user group an pid on:
/etc/nginx/nginx.conf
user http; pid /run/nginx.pid;
the absolute path of file is /srv/http/etc/nginx/nginx.conf
.
/etc/systemd/system/nginx.service
[Unit] Description=nginx (Chroot) After=syslog.target network.target [Service] Type=forking PIDFile=/srv/http/run/nginx.pid RootDirectory=/srv/http ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf ExecReload=/usr/sbin/nginx -c /etc/nginx/nginx.conf -s reload ExecStop=/usr/sbin/nginx -c /etc/nginx/nginx.conf -s stop [Install] WantedBy=multi-user.target
It is not necesary to set the default location, nginx loads at default -c /etc/nginx/nginx.conf
, but it is a good idea though.
Alternatively you can run only ExecStart
as chroot with parameter RootDirectoryStartOnly
set as yes
man systemd service or start it before mount point as effective or a systemd path is available.
/etc/systemd/system/nginx.path
[Unit] Description=nginx (Chroot) path [Path] PathExists=/srv/http/site/Public_html [Install] WantedBy=default.target
作成した nginx.path
を有効化して、/etc/systemd/system/nginx.service
の WantedBy=default.target
を WantedBy=nginx.path
に変更してください。
The PIDFile
in unit file allows systemd to monitor process (absolute path required). If it is undesired, you can change to default one-shot type, and delete the reference from the unit file.
Nginx Beautifier
nginxbeautifierAUR は nginx の設定ファイルを整形することができるコマンドラインツールです。
より良いヘッダー管理
Nginx のヘッダー管理システムはあまり直感的とは言えません。ヘッダーは特定のコンテキストでしか定義できず、他のヘッダーは無視されます。headers-more-nginx モジュールをインストールすることでこの挙動を変更できます。
nginx-mod-headers-more パッケージをインストールしてください。モジュールは /usr/lib/nginx/modules
ディレクトリにインストールされます。
モジュールをロードするには以下をメインの nginx の設定ファイルに追加してください:
/etc/nginx/nginx.conf
load_module "/usr/lib/nginx/modules/ngx_http_headers_more_filter_module.so"; ...
トラブルシューティング
設定の確認
# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
This is because the FastCGI server has not been started, or the socket used has wrong permissions.
Try out this answer to fix the 502 error.
In Arch Linux, the configuration file mentioned in above link is /etc/php/php-fpm.conf
.
Error: No input file specified
1. Verify that variable open_basedir
in /etc/php/php.ini
contains the correct path specified as root
argument in nginx.conf
(usually /usr/share/nginx/
). When using PHP-FPM as FastCGI server for PHP, you may add fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/:/tmp/:/proc/";
in the location
block which aims for processing php file in nginx.conf
.
2. Another occasion is that, wrong root
argument in the location ~ \.php$
section in nginx.conf
. Make sure the root
points to the same directory as it in location /
in the same server. Or you may just set root as global, do not define it in any location section.
3. Check permissions: e.g. http
for user/group, 755
for directories and 644
for files. Remember the entire path to the html
directory should have the correct permissions. See ファイルのパーミッションと属性#Bulk chmod to bulk modify a directory tree.
4. おそらくスクリプトのフルパスを含んだ SCRIPT_FILENAME がありません。 nginx の設定 (fastcgi_param SCRIPT_FILENAME) が完全でも、このエラーは php が requestd スクリプトをロードできないことを意味しています。これは単純にパーミッションの問題であることが普通で、root で php-cgi を実行するか
# spawn-fcgi -a 127.0.0.1 -p 9000 -f /usr/bin/php-cgi
php-cgi を起動するグループとユーザーを作成する必要があります。例えば:
# groupadd www # useradd -g www www # chmod +w /srv/www/nginx/html # chown -R www:www /srv/www/nginx/html # spawn-fcgi -a 127.0.0.1 -p 9000 -u www -g www -f /usr/bin/php-cgi
5. If you are running php-fpm with chrooted nginx ensure chroot
is set correctly within /etc/php-fpm/php-fpm.d/www.conf
(or /etc/php-fpm/php-fpm.conf
if working on older version)
Warning: Could not build optimal types_hash
When starting the nginx.service
, the process might log the message:
[warn] 18872#18872: could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size
To fix this warning, increase the values for these keys inside the http
block [2] [3]:
/etc/nginx/nginx.conf
http { types_hash_max_size 4096; server_names_hash_bucket_size 128; ... }
Cannot assign requested address
The full error from nginx.service
unit status is
[emerg] 460#460: bind() to A.B.C.D:443 failed (99: Cannot assign requested address)
Even, if your nginx unit-file is configured to run after network.target
with systemd, nginx may attempt to listen at an address that is configured but not added to any interface yet. Verify that this the case by manually running start for nginx (thereby showing the IP address is configured properly). Configuring nginx to listen to any address will resolve this issue. Now if your use case requires listening to a specific address, one possible solution is to reconfigure systemd.
To start nginx after all configured network devices are up and assigned an IP address, append network-online.target
to After=
within nginx.service
and start/enable systemd-networkd-wait-online.service
.