NGINX 設定ティップス

NGINX設定ファイル

NGINXをリバースプロキシまたはウェブサーバとして使用するための設定ティップス。サーバセキュリティ、ロードバランサーとしての機能も併せ持つため、サーバ導入時には欠かせないオープンソースのサーバアプリです。

リバースプロキシ

ウェブサーバ

ロードバランサー

全機能を盛り込んだ設定ファイル

HTTPベーシック認証によるアクセス制限

Securing HTTP Traffic to Upstream Servers

Alphabetical index of variables

https://nginx.org/en/docs/varindex.html

try_files

以下の例では、ロケーションで指定したディレクトリ内で、URIで表示された文字列を、まず初めにファイルとして検索、そのファイルが存在しない場合にはフォルダとして検索します。結果が一致した時点でその内容を返し、共に一致しなければ404を返します。

location / {
    try_files $uri $uri/ $uri.html =404;
}

ファイル、フォルダ名共にURIと一致しない場合、以下のようにプロキシーサーバに飛ばすことも出来ます。

location / {
    try_files $uri $uri/ @backend;
}

location @backend {
    proxy_pass http://backend.example.com;
}

Regular Expression正規表現参考

NGINX uses Perl Compatible Regular Expressions (PCRE).


Understanding Nginx Server and Location Block Selection Algorithms

Location blocks generally take the following form:

location optional_modifier location_match {

    . . .

}

The location_match in the above defines what Nginx should check the request URI against. The existence or nonexistence of the modifier in the above example affects the way that the Nginx attempts to match the location block. The modifiers below will cause the associated location block to be interpreted as follows:

  • (none): If no modifiers are present, the location is interpreted as a prefix match. This means that the location given will be matched against the beginning of the request URI to determine a match.
  • =: If an equal sign is used, this block will be considered a match if the request URI exactly matches the location given.
  • ~: If a tilde modifier is present, this location will be interpreted as a case-sensitive regular expression match.
  • ~*: If a tilde and asterisk modifier is used, the location block will be interpreted as a case-insensitive regular expression match.
  • ^~: If a carat and tilde modifier is present, and if this block is selected as the best non-regular expression match, regular expression matching will not take place.

rootデレクティブとaliasディレクティブの違い

http://nginx.org/en/docs/http/ngx_http_core_module.html#alias

rootディレクティブ

location /static/ {
    root /var/www/app/;
    autoindex off;
}

rootで指定したディレクトリにlocationのディレクトリが追加されます。

/var/www/app/static

aliasディレクティブ

location /static/ {
    alias /var/www/app/static/;
    autoindex off;
}

locationのディレクトリがaliasのディレクトリを表します。

/var/www/app/static

FastCGI Params

/etc/nginx/fastcgi_params
ファイル内で以下設定項目を確認すること。特にphpスクリプトを実行する上で、以下の設定がポイントとなります。(404が返ってきた場合はここを見直します)

fastcgi_param   SCRIPT_FILENAME         $document_root$fastcgi_script_name;
fastcgi_param   QUERY_STRING            $query_string;
fastcgi_param   REQUEST_METHOD          $request_method;
fastcgi_param   CONTENT_TYPE            $content_type;
fastcgi_param   CONTENT_LENGTH          $content_length;

fastcgi_param   SCRIPT_FILENAME         $document_root$fastcgi_script_name;
fastcgi_param   SCRIPT_NAME             $fastcgi_script_name;
fastcgi_param   PATH_INFO               $fastcgi_path_info;
fastcgi_param   PATH_TRANSLATED         $document_root$fastcgi_path_info;
fastcgi_param   REQUEST_URI             $request_uri;
fastcgi_param   DOCUMENT_URI            $document_uri;
fastcgi_param   DOCUMENT_ROOT           $document_root;
fastcgi_param   SERVER_PROTOCOL         $server_protocol;

fastcgi_param   GATEWAY_INTERFACE       CGI/1.1;
fastcgi_param   SERVER_SOFTWARE         nginx/$nginx_version;

fastcgi_param   REMOTE_ADDR             $remote_addr;
fastcgi_param   REMOTE_PORT             $remote_port;
fastcgi_param   SERVER_ADDR             $server_addr;
fastcgi_param   SERVER_PORT             $server_port;
fastcgi_param   SERVER_NAME             $server_name;

fastcgi_param   HTTPS                   $https;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param   REDIRECT_STATUS         200;

fastcgi_paramの設定については以下も参考にして下さい。

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
or
fastcgi_param SCRIPT_FILENAME $request_filename;

Example

You get the request /info/ and have the following configuration:

fastcgi_index  index.php;
fastcgi_param  SCRIPT_FILENAME  /home/www/scripts/php$fastcgi_script_name;

SCRIPT_FILENAME would equal /home/www/scripts/php/info/index.php , but using $request_filename it would just be /home/www/scripts/php/info/ .

The configuration of fastcgi_split_path_info is important as well. See here for further help: Module ngx_http_fastcgi_module

ヘッダー読み取りエラー

デフォルトでNginxはアンダースコア"_"を含むヘッダーは読み込まない。
Nginxの設定ファイルに “underscores_in_headers on;” を追加。

underscores_in_headers
https://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers

Ex)
https://gist.github.com/zeroed/8554827

upstream foo_app {
  server 127.0.0.1:3000;
}

server {
   listen 80;
#  listen [::]:80 default_server ipv6only=on;

   root /home/user/foo/foo_web/public;

   server_name foo.it  www.foo.it;
   underscores_in_headers on;
   client_max_body_size 4g;

   location ~ ^/(assets)/ {
      gzip_static on;
      expires max;
      add_header Cache-Control public;
      }
   location / {
     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_connect_timeout 300;
     proxy_read_timeout 300;


     proxy_pass_request_headers on;
     proxy_pass http://foo_app;

     }
}

NginxにおけるApacheのgetallheaders()代替案

https://www.php.net/manual/en/function.getallheaders.php#84262

<?php
if (!function_exists('getallheaders'))
{
    function getallheaders()
    {
           $headers = [];
       foreach ($_SERVER as $name => $value)
       {
           if (substr($name, 0, 5) == 'HTTP_')
           {
               $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
           }
       }
       return $headers;
    }
}
?>

HTTP Digest Authentication

https://www.nginx.com/resources/wiki/modules/auth_digest/

標準モジュールではないため、別途インストールが必要。

Nginx: 413 – Request Entity Too Large

https://www.cyberciti.biz/faq/linux-unix-bsd-nginx-413-request-entity-too-large/

/etc/nginx/conf.d/dfault.conf内のlocationブロックで以下指定

client_max_body_size 20M;

Setting up SSL with nginx reverse proxy

server {
     listen 443 ssl default_server;
     listen [::]:443 ssl default_server;

     root /var/www/html;
     index index.php index.js index.html index.htm index.nginx-debian.html;
     server_name domain.com www.domain.com;
     ssl_certificate /ssl/domain.com.chained.crt;
     ssl_certificate_key /ssl/domain.com.key;

    location / {
        proxy_pass http://localhost:8000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

    location /wordpress {
        proxy_pass http://localhost:8090;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

mapモジュール

https://nginx.org/en/docs/http/ngx_http_map_module.html

例1) mapモジュールによるリダイレクト

map により /old.html/index.html に対応させ、それが真(1)の時にリダイレクト

. . .
# Default server configuration
#

# Old website redirect map
#
map $uri $new_uri {
    /old.html /index.html;
}

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    # Old website redirect
    if ($new_uri) {
        rewrite ^ $new_uri permanent;
    }
. . .

例2) mapによる国別のサイトへのアクセス制限

以下の設定ファイルを作成し、国データを指定。

/etc/nginx/conf.d/geoip.conf

https://nginx.org/en/docs/http/ngx_http_geoip_module.html

. . .
# GeoIP database path
#

geoip_country /usr/share/GeoIP/GeoIP.dat;

制限する国コードを指定(AFとAL)

. . .
# Default server configuration
#

# Allowed countries
#
map $geoip_country_code $allowed_country {
    default no;
    AF yes;
    AL yes;
}

# Old website redirect map
#
map $uri $new_uri {
    /old.html /index.html;
}

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    # Disallow access based on GeoIP
    if ($allowed_country = no) {
        return 444;
    }

    # Old website redirect
    if ($new_uri) {
        rewrite ^ $new_uri permanent;
    }
. . .

Location

サーバディレクトリ毎に設定を細かく指定する Location(Nginxコアモジュール) についてのメモ。

Nginxコアモジュール
https://nginx.org/en/docs/http/ngx_http_core_module.html

Location
https://nginx.org/en/docs/http/ngx_http_core_module.html#location

Syntax:	location [ = | ~ | ~* | ^~ ] uri { ... }
location @name { ... }
Default:	—
Context:	server, location
= 一致した場合
~ 大文字・小文字を区別(正規表現)
~* 大文字・小文字を区別しない(正規表現)
^~ 一致したら正規表現(~,~*)の条件を適用しない
@name 他の設定からのリダイレクト先を名前により指定する場合に使用

ディレクトリが / の場合、configuration Aを適用

location = / {
    [ configuration A ]
}

ディレクトリが / を含む場合、configuration Bを適用

location / {
    [ configuration B ]
}

ディレクトリが /documents/ を含む場合、configuration Cを適用

location /documents/ {
    [ configuration C ]
}

ディレクトリが /images/ を含む場合、configuration Dを適用

location ^~ /images/ {
    [ configuration D ]
}

ファイル名に gif.jpg,jpeg の拡張子を含む場合、configuration Eを適用

location ~* \.(gif|jpg|jpeg)$ {
    [ configuration E ]
}
# --------------------------------------------------------------------------------------------------------------------------------------------
# Search-Order       Modifier       Description                                                        Match-Type        Stops-search-on-match
# --------------------------------------------------------------------------------------------------------------------------------------------
#     1st               =           The URI must match the specified pattern exactly                  Simple-string              Yes
#     2nd               ^~          The URI must begin with the specified pattern                     Simple-string              Yes
#     3rd             (None)        The URI must begin with the specified pattern                     Simple-string               No
#     4th               ~           The URI must be a case-sensitive match to the specified Rx      Perl-Compatible-Rx      Yes (first match)                 
#     4th               ~*          The URI must be a case-insensitive match to the specified Rx    Perl-Compatible-Rx      Yes (first match)
#     N/A               @           Defines a named location block.                                   Simple-string              Yes
# --------------------------------------------------------------------------------------------------------------------------------------------

phpmyadminなどサブディレクトリを指定したページアクセスにファイルの絶対パス ( ex) /var/www/html) が追加されてしまうエラーについて。

location ディレクティブの内部で location ディレクティブを指定した場合、その両方に root または alias を指定すること。

root の場合

location /phpmyadmin {
        root /usr/share/;
        try_files $uri $uri/ /index.php;

        location ~ ^/phpmyadmin(.+\.php)$ {
            root /usr/share/;
            fastcgi_pass 127.0.0.1:9000;
            include fastcgi.conf;
            fastcgi_intercept_errors        on;
        }
    }

alias の場合

location /pma {
        alias /usr/share/phpmyadmin/;
        try_files $uri $uri/ /index.php;

        location ~ ^/pma(.+\.php)$ {
            alias /usr/share/phpmyadmin$1;
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_param SCRIPT_FILENAME /usr/share/phpmyadmin$1;
            include fastcgi_params;
            fastcgi_intercept_errors        on;
        }
    }

Embedded Variables

https://nginx.org/en/docs/http/ngx_http_core_module.html#variables

location / {
        try_files $uri /index.php$is_args$args;
    }

$args
arguments in the request line

$is_args

?” if a request line has arguments, or an empty string otherwise

try_files

https://nginx.org/en/docs/http/ngx_http_core_module.html#try_files

キャッシュ

Module ngx_http_proxy_module

https://nginx.org/en/docs/http/ngx_http_proxy_module.html

キャッシュ設定ファイル例(リバースプロキシ)

http {
    proxy_cache_path  /data/nginx/cache  levels=1:2    keys_zone=STATIC:10m
    inactive=24h  max_size=1g;
    server {
        location / {
            proxy_pass             http://1.2.3.4;
            proxy_set_header       Host $host;
            proxy_buffering        on;
            proxy_cache            STATIC;
            proxy_cache_valid      200  1d;
            proxy_cache_use_stale  error timeout invalid_header updating
                                   http_500 http_502 http_503 http_504;
        }
    }
}

以下 Nginx-V コマンドオプションでキャッシュディレクトリなどのコンパイル時の条件が確認できます。# nginx -V

DockerコンテナのNginx(Alpine)

# nginx -V
nginx version: nginx/1.19.6
built by gcc 9.3.0 (Alpine 9.3.0) 
built with OpenSSL 1.1.1g  21 Apr 2020 (running with OpenSSL 1.1.1i  8 Dec 2020)
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --with-perl_modules_path=/usr/lib/perl5/vendor_perl --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-Os -fomit-frame-pointer' --with-ld-opt=-Wl,--as-needed

proxy_cache_path

alpineベースのnginxコンテナでは、Nginxのドキュメントの中で例示されている /data/nginx/cache ディレクトリが存在しないため、 /var/cache/nginx を指定します。

How to Block IP Address in NGINX

以下 http, server, location 何れかのセクションにブロックするIPを指定

http{
   ...
   deny 45.43.23.21;
   ...
}

server{
    ...
    deny 45.43.23.21;
    ...
}


location / {
   deny 45.43.23.21;
}

または /etc/nginx/conf.d/blacklist_ips.conf を作成してブロックするIPを指定
/etc/nginx/conf.d/*.conf/etc/nginx/nginx.conf によりデフォルトで読み込まれるよう設定されています)
以下 amazonaws を悪用したサイトからのアクセス禁止した例

deny 34.208.0.0/12;
deny 35.160.0.0/13;
deny 54.184.0.0/13;
deny 54.200.0.0/15;
allow all;

iptables でも特定IPからのアクセスはブロックできます。

AWSの仮想サーバインスタンスに付与されるIP ( ec2-xx-xxx-xxx-xxx.us-west-2.compute.amazonaws.com etc…) からアクセス拒否する場合、AWSから提供されているIPアドレス範囲一覧から(排除する)IP範囲を特定します。

AWS提供IP範囲

IPリスト
https://ip-ranges.amazonaws.com/ip-ranges.json

JSONフォーマットによるデータで情報量が多いため、以下のアプリでフィルタリングして必要な情報を抜き出します。

jq
https://stedolan.github.io/jq/
各OSに対応しています。

Ubuntuでのインストール

$ sudo apt-get install jq

AWSのサービスとリージョンを指定したIP範囲の抽出
ダウンロードしたデータ ip-ranges.json から AWSのEC2でリージョンが us-west-2 のIPアドレス一覧を抽出します。

$ jq -r '.prefixes[] | select(.region=="us-west-2") | select(.service=="EC2") | .ip_prefix' < ip-ranges.json

142.4.160.56/29
15.220.252.0/22
54.148.0.0/15
99.77.130.0/24
99.150.56.0/21
15.193.7.0/24
18.236.0.0/15
161.188.148.0/23
54.200.0.0/15
64.252.72.0/24
3.4.3.0/24
52.94.249.64/28
161.188.156.0/23
15.181.253.0/24
70.224.192.0/18
54.245.0.0/16
99.77.152.0/24
35.160.0.0/13
54.68.0.0/14
54.212.0.0/15
142.4.160.64/29
52.95.230.0/24
99.77.253.0/24
3.4.6.0/24
35.80.0.0/12
52.12.0.0/15
52.75.0.0/16
54.218.0.0/16
3.5.76.0/22
15.181.0.0/20
54.244.0.0/16
44.224.0.0/11
64.252.73.0/24
52.95.255.112/28
100.20.0.0/14
15.220.0.0/20
15.220.16.0/20
161.188.134.0/23
54.214.0.0/16
34.208.0.0/12
35.71.64.0/22
52.36.0.0/14
15.220.226.0/24
54.202.0.0/15
15.181.128.0/20
15.181.245.0/24
52.95.247.0/24
50.112.0.0/16
15.181.64.0/20
142.4.160.16/29
52.94.116.0/22
15.181.248.0/24
15.253.0.0/16
15.181.252.0/24
52.46.180.0/22
15.181.16.0/20
162.222.148.0/22
52.24.0.0/14
64.252.65.0/24
18.246.0.0/16
3.5.80.0/21
161.188.138.0/23
52.88.0.0/15
142.4.160.104/29
161.188.152.0/23
15.177.80.0/24
15.254.0.0/16
52.40.0.0/14
64.252.70.0/24
52.32.0.0/14
54.184.0.0/13
142.4.160.96/29
15.181.251.0/24
142.4.160.32/29
161.188.160.0/23
64.252.71.0/24
35.155.0.0/16
52.10.0.0/15
3.4.4.0/24
15.181.116.0/22
15.220.224.0/23
15.181.250.0/24
52.94.248.96/28
99.77.186.0/24

上記IP範囲を参考にブロックするIP範囲を nginx の設定ファイルに書き込みます。

IP Calculator(Ubuntu)

コマンドラインによるIP計算機

ipcalc(IPv4)

$ ipcalc 34.208.0.0/12
Address:   34.208.0.0           00100010.1101 0000.00000000.00000000
Netmask:   255.240.0.0 = 12     11111111.1111 0000.00000000.00000000
Wildcard:  0.15.255.255         00000000.0000 1111.11111111.11111111
=>
Network:   34.208.0.0/12        00100010.1101 0000.00000000.00000000
HostMin:   34.208.0.1           00100010.1101 0000.00000000.00000001
HostMax:   34.223.255.254       00100010.1101 1111.11111111.11111110
Broadcast: 34.223.255.255       00100010.1101 1111.11111111.11111111
Hosts/Net: 1048574               Class A

sipcalc(IPv4, IPv6)

$ sipcalc 34.208.0.0/12
-[ipv4 : 34.208.0.0/12] - 0

[CIDR]
Host address		- 34.208.0.0
Host address (decimal)	- 584056832
Host address (hex)	- 22D00000
Network address		- 34.208.0.0
Network mask		- 255.240.0.0
Network mask (bits)	- 12
Network mask (hex)	- FFF00000
Broadcast address	- 34.223.255.255
Cisco wildcard		- 0.15.255.255
Addresses in network	- 1048576
Network range		- 34.208.0.0 - 34.223.255.255
Usable range		- 34.208.0.1 - 34.223.255.254

-

subnetcalc(IPv4, IPv6)

$ subnetcalc 34.208.0.0/12
Address       = 34.208.0.0
                   00100010 . 11010000 . 00000000 . 00000000
Network       = 34.208.0.0 / 12
Netmask       = 255.240.0.0
Broadcast     = 34.223.255.255
Wildcard Mask = 0.15.255.255
Hosts Bits    = 20
Max. Hosts    = 1048574   (2^20 - 2)
Host Range    = { 34.208.0.1 - 34.223.255.254 }
Properties    =
   - 34.208.0.0 is a NETWORK address
   - Class A
GeoIP Country = United States (US)
DNS Hostname  = ec2-34-208-0-0.us-west-2.compute.amazonaws.com

gzipモジュールによるパフォーマンスの改善

以下のコマンドでビルド時の条件を確認し --with-http_gzip_static_module があればgzipモジュールはインストールされています。

# nginx -V
nginx version: nginx/1.21.6
built by gcc 10.3.1 20211027 (Alpine 10.3.1_git20211027) 
built with OpenSSL 1.1.1l  24 Aug 2021
TLS SNI support enabled
configure arguments: ..................... --with-http_gzip_static_module ....................
....................

gzipを有効にし、必要な条件を追加します。
/etc/nginx/nginx.conf

gzip  on;
    gzip_disable "msie6";

    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    gzip_min_length 256;
    gzip_types
        application/atom+xml
        application/geo+json
        application/javascript
        application/x-javascript
        application/json
        application/ld+json
        application/manifest+json
        application/rdf+xml
        application/rss+xml
        application/xhtml+xml
        application/xml
        font/eot
        font/otf
        font/ttf
        image/svg+xml
        text/css
        text/javascript
        text/plain
        text/xml;

外部サーバへのリバースプロキシ設定

ドメイン名でのみでアクセス許可した外部 Nginx サーバ(バックエンド)へのプロキシ(フロントエンド)設定。

簡単に言うとフロントエンドで受けたドメイン名をバックエンドへ引継ぐための設定です。

リバースプロキシ側(フロントエンド)で、下記 proxy_set_header で指定したヘッダー情報を外部サーバ(バックエンド)へ受け渡します。

Note) ホスト名を明示 proxy_set_header Host test.example.com; しないとプロキシパスのアドレス(とポート)が受け渡されてしまいます。

/etc/nginx/conf.d/default.conf

server {
    server_name test.example.com;

    location / {
        proxy_pass http://12.34.56.78:8888;
        proxy_set_header Host test.example.com;
        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;

    }
.....

外部サーバでクライアントIPの引継ぎ

フロントエンドで受けたクライアントIPを外部サーバ(バックエンド)で引継ぐ場合は、下記バックエンドの Nginx の設定でフロントエンドサーバのIPアドレス(グローバルIP)を明示して下さい。

設定する上で、以下のモジュールが必要です。$ nginx -V コマンドでコンパイル条件を確認して下さい。

Module ngx_http_realip_module

https://nginx.org/en/docs/http/ngx_http_realip_module.html

/etc/nginx/nginx.conf

http {
....
    set_real_ip_from   xx.xx.xx.xx;   ← フロントエンドのIPアドレスを入力
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;
.....
}