Docker Compose 入門:Flask + Redis サンプルを本番でも安心して使えるようにハードニングするでは、Docker Compose をはじめよう | Docker ドキュメントのハードニングを行いました。
この記事では、上記構成にさらにNGINXを追加して外部公開窓口を一本化します。
NGINXとは
NGINX(エンジンエックス) は、軽量かつ高速に動作する Webサーバー/リバースプロキシサーバー ソフトウェアです。
2004年に公開されて以来、世界中の大規模サイトやクラウド環境で広く利用されています。
NGINXの役割
- Webサーバー
- 静的コンテンツ(HTML, CSS, JavaScript, 画像など)を直接配信。
- Apache HTTP Server の代替として利用されることも多い。
- リバースプロキシ
- クライアントからのリクエストを受け取り、バックエンドのアプリケーション(Flask, Node.js, PHP など)に転送。
- 複数のアプリケーションに振り分ける ロードバランサー としても機能。
- TLS(SSL)終端
- HTTPS 通信の暗号化・復号を NGINX 側で処理し、バックエンドは平文 HTTP で通信できる。
- キャッシュ・圧縮
- 静的リソースのキャッシュや gzip 圧縮で高速化。
- セキュリティ機能
- レート制限(DoS攻撃対策)
- アクセス制御(IP制限など)
- セキュリティヘッダの追加(クリックジャッキング対策など)
ハードニング+NGINX 追加構成
Docker Compose をはじめよう | Docker ドキュメントの元構成とハードニング+NGINX 追加構成の比較

NGINX 追加作業
Docker Compose 入門:Flask + Redis サンプルを本番でも安心して使えるようにハードニングするの構成のdocker-compose.ymlを変更し、nginx.conf(NGINX の設定ファイル)を追加する。
docker-compose.ymlの変更
#docker-compose.yml(NGINX追加版)
services:
nginx:
image: nginx:1.27-alpine
depends_on:
web:
condition: service_healthy
ports:
- "8080:8080"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
read_only: true
tmpfs:
- /var/cache/nginx:rw,size=16m,mode=1777
- /var/run:rw,size=4m,mode=755
- /tmp:rw,size=4m,mode=1777
user: "101:101"
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
web:
build: .
environment:
REDIS_HOST: redis
REDIS_PORT: "6379"
REDIS_PASSWORD: ${REDIS_PASSWORD:?set_in_.env}
depends_on:
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "python", "-c",
"import urllib.request,sys; sys.exit(0) if urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=3).getcode()==200 else sys.exit(1)"]
interval: 30s
retries: 3
read_only: true
tmpfs:
- /tmp:size=16m,mode=1777
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
redis:
image: redis:7.4-alpine
command: ["redis-server","--requirepass","${REDIS_PASSWORD:?set_in_.env}"]
expose:
- "6379"
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "PING"]
interval: 30s
retries: 5
read_only: true
tmpfs:
- /data:size=64m,mode=700
nginx.confの追加
nginxディレクトリを作成し、下記のnginx.conf を保存する。
#nginx.conf(最小設定)
pid /tmp/nginx.pid;
worker_processes auto;
events {
worker_connections 1024;
}
http {
sendfile on;
include /etc/nginx/mime.types;
upstream app_upstream {
server web:8000;
keepalive 32;
}
server {
listen 8080;
# セキュリティヘッダ
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
location / {
proxy_pass http://app_upstream;
}
location /health {
proxy_pass http://app_upstream/health;
access_log off;
}
}
}
pid /tmp/nginx.pid;
NGINX の マスタープロセスのプロセスID(PID)を/tmp/nginx.pidに書き込むように指定
(本来は /var/run/nginx.pid に書き込むが、非rootユーザー (user: "101:101") で動かしているため /var/run に書き込めないため)
worker_processes auto;
NGINX のワーカープロセス数を自動設定。
worker_connections 1024;
1 ワーカープロセスが同時に扱える接続数の上限を設定。
server web:8000;
Docker Compose のサービス名 web の 8000 番ポートへ転送。
keepalive 32;
同時に再利用可能な接続数を 32 に設定
listen 8080;
NGINX が待ち受けるポートを指定。
X-Content-Type-Options: nosniff
ブラウザに MIME タイプを勝手に推測させない(XSS 対策)。
X-Frame-Options: DENY
iframe 埋め込みを禁止(クリックジャッキング対策)。
location / {proxy_pass http://app_upstream;}
クライアントが http://<host>:8080/ にアクセスしたとき、バックエンド(Flask/Gunicorn, web:8000)に転送する。
location /health {proxy_pass http://app_upstream/health; access_log off;}
この nginx.conf は、以下の役割を持ちます。
- 外部 8080 ポートでリクエストを受ける
- 内部 web:8000(Flask+Gunicorn)へ転送
- セキュリティヘッダを追加して脆弱性を減らす
- /health 用ルートを定義して、ログ負荷を減らす
動作確認
http://localhost:8080/
http://localhost:8080/health
まとめ
今回の作業で、外部公開は NGINX のみ、Flask(Gunicorn)と Redis は 内部ネットワーク専用になりました。


