この記事の内容
Dockerでnginxを使用する際に気をつけたポイントについて書いてみた。
他コンテナとの連携方法や、nginxの設定などについて触れる。
サンプルコード
本記事で解説したコードを公開しています。
https://github.com/fukky21/nginx-sample
全体の構成
環境構築
version: '3.9'
services:
proxy:
image: nginx:1.21.0
container_name: nginx-sample_proxy
volumes:
- ./proxy/nginx.conf:/etc/nginx/nginx.conf
- ./proxy/html:/etc/nginx/html
- ./proxy/log:/var/log/nginx
ports:
- '80:80'
depends_on:
- api
- web
api:
build:
context: ./api
dockerfile: Dockerfile
container_name: nginx-sample_api
command: yarn dev
volumes:
- ./api:/app
tty: true
web:
build:
context: ./web
dockerfile: Dockerfile
container_name: nginx-sample_web
command: yarn dev
volumes:
- ./web:/app
tty: true
environment:
PORT: 3000
HOST: 0.0.0.0
いくつかポイントがあるので解説する。
Dockerfileの内容については、サンプルコードをご覧ください。
proxyの起動を最後にする
depends_on
でwebとapiを指定することで、proxyよりも先にその2つが起動する。
nginx.conf
で、プロキシの転送先にnginx-sample_api
とnginx-sample_web
を指定するので、最後に起動する必要がある。
webとapiのポートをホスト側に公開しない
webとapiにはports
を指定しない。こうすることで、ホストから直接webとapiにアクセスすることはできず、必ずproxyを経由することになる。
webの環境変数にPORTとHOSTを指定する
webのenvironment
でPORT
とHOST
を指定している。
これを指定しないと502 Bad Gateway
と表示され、Webサイト(Nuxt.js)に接続できない。
原因に関しては、この記事に分かりやすくまとめられている。
https://qiita.com/amuyikam/items/01a8c16e3ddbcc734a46
container_nameを指定する
後ほど紹介するnginx.conf
で、ここで指定したcontainer_name
を使用する。
nginxの設定
worker_processes auto;
events {
worker_connections 16;
}
http {
server {
listen 80 default_server;
server_name _;
return 444;
}
server {
listen 80;
server_name localhost;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Connection '';
error_page 404 /404.html;
location = /404.html {
root /etc/nginx/html;
internal;
}
location /app/ {
allow 172.24.0.1;
deny all;
proxy_pass http://nginx-sample_web:3000;
}
location /api/ {
proxy_pass http://nginx-sample_api:3080;
}
}
}
worker_processesとworker_connections
こちらの記事によると、
nginxにおける同時クライアントの最大数は、worker_processes × worker_connectionsの数で決まる。
ということらしい。
worker_processes auto
とすると、ワーカープロセス数はCPUのコア数と同じになる。
Macの場合、CPUコア数は下のコマンドで確認できる。
$ system_profiler SPHardwareDataType | awk '/Total Number of Cores/ { print $NF }'
worker_connections
の値を色々いじってみると、接続できるクライアント数が変わることを確認できる。
IPの直打ちアクセスを弾く
server {
listen 80 default_server;
server_name _;
return 444;
}
http://127.0.0.1/app のように、IPアドレスを直打ちしてアクセスしてきた場合に接続を切ることで、攻撃を防ぐことができる。
444
は、接続を閉じるためのnginxの特別な標準外コードで、詳しくはこちらを参照。
ヘッダーを書き換える
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Connection '';
ヘッダーの書き換えを行わない場合、webやapi側にはプロキシからリクエストが来たことしか伝わらない。ヘッダー情報を、プロキシにアクセスしてきたクライアントの情報に書き換えることで、webやapi側でもクライアントの情報を扱えるようになる。
エラーページをカスタマイズする
error_page 404 /404.html;
location = /404.html {
root /etc/nginx/html;
internal;
}
デフォルトのエラーページでは以下のように表示される。
nginxを使用していることがクライアントにバレてしまうのが嫌な場合は、エラーページを独自に設定すると良い。
今回の例では、404(Not Found)
のときだけオリジナルのエラーページが表示されるようにしてあるが、403(Forbidden)
や500(Internal Server Error)
のときも個別に指定できる。
internal
を指定することで、内部からのリクエストのためだけに使用されることになり、外部からは直接アクセスできなくなる。
IPアドレス制限をかける
allow 172.24.0.1;
deny all;
管理者サイトなど、特定のIPアドレスからのアクセスのみ許可したい場合はallow
で指定する。その後ろにdeny all
を記述することで、allow
で指定したIPアドレス以外のアクセスを弾くことができる。