NginxはHTTP serverとreverse proxyです。distribution packageやcontainer imageによってfile path・module・versionが異なるため、最初に実環境を確認します。
最頻出10項目
| 操作 | Command / directive |
|---|---|
| version | nginx -v |
| build option | nginx -V |
| 設定検査 | nginx -t |
| 設定全体表示 | nginx -T |
| reload | nginx -s reload |
| hostname受付 | server_name |
| path分岐 | location |
| 静的配信 | root、try_files |
| reverse proxy | proxy_pass |
| TLS | listen 443 ssl |
操作
nginx -v
nginx -V
sudo nginx -t
sudo nginx -T
sudo nginx -s reload
sudo nginx -s quit
systemd環境:
sudo systemctl status nginx
sudo systemctl reload nginx
sudo journalctl -u nginx
必ずnginx -tが成功してからreloadします。nginx -Tは設定全体を出すため、certificate path、internal hostnameなどを共有前に確認します。stopは即時停止、quitはgraceful shutdownです。
基本構造
user nginx;
worker_processes auto;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log warn;
sendfile on;
include /etc/nginx/conf.d/*.conf;
}
directiveを置けるcontextは決まっています。serverはhttp内、locationはserver内です。設定pathはnginx -Vの--conf-pathで確認します。
server
HTTPからHTTPSへredirect:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
HTTPS server:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /var/www/example;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
private keyのpermissionを制限し、repositoryへcommitしません。TLS protocol・cipherなどは固定snippetを古い記事からコピーせず、利用するNginx・OpenSSLとcertificate providerの現在のguideを確認します。
location matching
location = /health {
return 200 "ok";
}
location ^~ /assets/ {
root /var/www/example;
}
location /api/ {
proxy_pass http://backend;
}
location ~* \.(png|jpg|webp)$ {
expires 7d;
}
主なmodifier:
| Pattern | 意味 |
|---|---|
location = /path | 完全一致 |
location ^~ /path/ | prefix一致を優先 |
location /path/ | prefix一致 |
location ~ regex | 大文字小文字を区別するregex |
location ~* regex | 区別しないregex |
複雑なregex locationを増やす前にprefixで表現できないか検討します。
rootとalias
location /images/ {
root /var/www;
}
/images/logo.pngは/var/www/images/logo.pngを探します。
location /downloads/ {
alias /srv/files/;
}
/downloads/report.pdfは/srv/files/report.pdfを探します。rootとaliasではpathの組み立て方が違うため、末尾slashを含め実fileで確認します。
SPA
server {
listen 80;
server_name app.example.com;
root /var/www/app;
location / {
try_files $uri $uri/ /index.html;
}
}
存在しないassetまでindex.htmlへ返すとerrorを隠す場合があります。asset pathは別locationで=404にする構成も検討します。
Reverse proxy
upstream backend {
server 127.0.0.1:3000;
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Host $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_connect_timeout 5s;
proxy_read_timeout 60s;
}
}
proxy_pass末尾slashの有無でupstreamへ渡すURIが変わります。
location /api/ {
proxy_pass http://backend/;
}
この場合/api/usersはupstreamの/usersになります。変更前後をcurl -vとupstream logで確認します。
X-Forwarded-Forを認証判断へ使う場合はtrusted proxy境界を設定します。clientが自由に送ったheaderをそのまま信用しません。
WebSocket
httpcontext:
map $http_upgrade $connection_upgrade {
default upgrade;
"" close;
}
location:
location /socket/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
idle timeout、load balancer、application側のping/pongも確認します。
Request sizeとtimeout
server {
client_max_body_size 10m;
client_body_timeout 15s;
keepalive_timeout 65s;
}
limitを無条件に大きくせず、upload要件に合わせます。Nginxだけでなくapplication・platform側の上限もそろえます。
Security headerの最小例
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
Content Security PolicyやHSTSはsite仕様を確認せずcopyしません。HSTSはbrowserへ長期間HTTPSのみを要求するため、subdomainとrollbackを理解してから有効化します。
server versionをresponseへ出しにくくする:
server_tokens off;
これだけで脆弱性対策が完了するわけではありません。package updateと公開moduleの削減が必要です。
Log
log_format main '$remote_addr - $request '
'$status $body_bytes_sent '
'$request_time $upstream_response_time';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
tokenをquery stringに入れるとaccess logへ残ります。個人情報、authorization、cookieを不用意に記録しません。log rotationと保存期限も設定します。
確認例:
sudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/nginx/access.log
production logにはsecretがあり得るため、共有前にredactします。
よくあるerror
bind() failed: port使用中または権限不足host not found in upstream: DNS・container network・名前を確認connect() failed (111): upstreamがlistenしていないpermission denied: directory traversal権限、SELinuxも確認too many redirects: proxyとapplicationのHTTPS判定を確認413 Request Entity Too Large:client_max_body_size502 Bad Gateway: upstream process・socket・protocolを確認504 Gateway Timeout: upstream遅延とtimeoutを確認
curl -v http://127.0.0.1:3000/health
curl -v https://example.com/health
upstream直結とNginx経由を比べると境界を切り分けられます。
変更手順
- 対象設定fileを確認
- backupまたはversion管理された差分を用意
- stagingでrequestをtest
nginx -t- graceful reload
- error logとhealth checkを確認
- 問題時のrollbackを実行
cache、rate limit、load balancingの高度な運用はtraffic特性によって設定が変わります。短い汎用snippetをproductionへ貼らず、各moduleの公式documentと負荷testを利用してください。