nginx

nginxリバースプロキシ設定ガイド|Webアプリを安全に公開する

nginx リバースプロキシ サーバー

nginxリバースプロキシ設定ガイド
Webアプリを安全に公開する

nginxをリバースプロキシとして使い、Webアプリケーションを安全に公開する方法を解説します。SSL設定やロードバランシングまでカバーします。

こんな人向けの記事です

  • Webアプリをインターネットに公開したい
  • nginxの基本的な設定を学びたい
  • SSL証明書の設定方法を知りたい

Step 1リバースプロキシとは

リバースプロキシとは、クライアント(ブラウザ)とバックエンドサーバー(Django, Rails等)の間に立ち、クライアントからのリクエストを代理で受け取ってバックエンドに転送する仕組みです。

項目フォワードプロキシリバースプロキシ
配置場所クライアント側サーバー側
目的クライアントの匿名化・アクセス制御サーバーの保護・負荷分散
設定者クライアント管理者サーバー管理者
代表例Squid, 企業プロキシnginx, Apache, HAProxy

リバースプロキシのメリット

  • セキュリティ向上: バックエンドサーバーを直接公開しないため、攻撃対象を限定できる
  • SSL終端: SSL/TLSの処理をnginxに任せ、バックエンドの負荷を軽減
  • 負荷分散: 複数のバックエンドに処理を振り分けられる
  • キャッシュ: 静的コンテンツをキャッシュして応答速度を向上

Step 2nginxのインストールと基本設定

インストール

Ubuntu / Debian
sudo apt update
sudo apt install nginx -y

# バージョン確認
nginx -v

# サービスの起動・有効化
sudo systemctl start nginx
sudo systemctl enable nginx
CentOS / RHEL
sudo yum install epel-release -y
sudo yum install nginx -y

# サービスの起動・有効化
sudo systemctl start nginx
sudo systemctl enable nginx

ディレクトリ構成

パス役割
/etc/nginx/nginx.confメイン設定ファイル
/etc/nginx/conf.d/サイト別設定ファイル(推奨)
/etc/nginx/sites-available/利用可能なサイト設定(Debian系)
/etc/nginx/sites-enabled/有効なサイト設定(シンボリックリンク)
/var/log/nginx/アクセスログ・エラーログ

基本的なnginx.conf

/etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    # ログフォーマット
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent"';

    access_log /var/log/nginx/access.log main;
    error_log  /var/log/nginx/error.log warn;

    sendfile    on;
    tcp_nopush  on;
    keepalive_timeout 65;
    gzip on;

    # サイト別設定を読み込み
    include /etc/nginx/conf.d/*.conf;
}

設定変更後のテスト
設定を変更したら、必ず sudo nginx -t で構文チェックを行ってからリロードしましょう。構文エラーがあるままリロードすると、nginxが停止する可能性があります。

ターミナル
# 構文チェック
sudo nginx -t

# 設定のリロード(ダウンタイムなし)
sudo systemctl reload nginx

Step 3リバースプロキシの設定方法

ここでは、Djangoアプリ(Gunicorn)をバックエンドとして、nginxでリバースプロキシを設定する例を紹介します。

基本的なリバースプロキシ設定

/etc/nginx/conf.d/myapp.conf
server {
    listen 80;
    server_name example.com www.example.com;

    # 静的ファイル(Djangoのcollectstatic)
    location /static/ {
        alias /var/www/myapp/static/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # メディアファイル
    location /media/ {
        alias /var/www/myapp/media/;
        expires 7d;
    }

    # それ以外はGunicornに転送
    location / {
        proxy_pass http://127.0.0.1:8000;
        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 60s;
        proxy_send_timeout    60s;
        proxy_read_timeout    60s;
    }
}

重要なプロキシヘッダー

ヘッダー役割
Host元のリクエストのホスト名をバックエンドに伝える
X-Real-IPクライアントの実IPアドレスを伝える
X-Forwarded-Forプロキシチェーン全体のIPリストを伝える
X-Forwarded-Proto元のプロトコル(http/https)を伝える

Django側の設定
Djangoで X-Forwarded-Proto を認識させるには、settings.py に以下を追加します。

settings.py
# リバースプロキシ配下でHTTPSを正しく認識
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

# 許可するホスト
ALLOWED_HOSTS = ["example.com", "www.example.com"]

# 信頼するプロキシ(Django 4.0+)
CSRF_TRUSTED_ORIGINS = ["https://example.com"]

UNIXソケット接続(推奨)

TCP接続の代わりにUNIXソケットを使うと、オーバーヘッドが減りパフォーマンスが向上します。

/etc/nginx/conf.d/myapp.conf
upstream django_app {
    server unix:/run/gunicorn/myapp.sock;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://django_app;
        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;
    }
}

Step 4SSL/TLS終端(Let's Encrypt)

Let's Encryptを使って無料のSSL証明書を取得し、nginxでHTTPS通信を実現します。

Certbotのインストール

Ubuntu / Debian
# Certbotのインストール
sudo apt install certbot python3-certbot-nginx -y

# 証明書の取得(nginxプラグイン使用)
sudo certbot --nginx -d example.com -d www.example.com

# 自動更新のテスト
sudo certbot renew --dry-run

自動更新について
Certbotはインストール時に自動更新用のタイマー(systemdまたはcron)を設定します。証明書は90日間有効で、期限の30日前に自動更新されます。

SSL対応の完全な設定

/etc/nginx/conf.d/myapp.conf
# HTTPからHTTPSへリダイレクト
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

# HTTPS設定
server {
    listen 443 ssl;
    http2 on;
    server_name example.com www.example.com;

    # SSL証明書(Let's Encryptが自動配置)
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # SSL設定の最適化
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # OCSPステープリング
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;

    # セッションキャッシュ
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    # 静的ファイル
    location /static/ {
        alias /var/www/myapp/static/;
        expires 30d;
    }

    # リバースプロキシ
    location / {
        proxy_pass http://127.0.0.1:8000;
        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;
    }
}

TLS 1.0/1.1は無効にする
TLS 1.0と1.1には既知の脆弱性があります。ssl_protocols には TLSv1.2 TLSv1.3 のみを指定してください。古いブラウザとの互換性が必要な場合でも、TLS 1.2以上を推奨します。

Step 5ロードバランシング

複数のバックエンドサーバーにリクエストを分散することで、可用性とパフォーマンスを向上させます。

基本的なロードバランシング

/etc/nginx/conf.d/myapp.conf
# バックエンドサーバーグループの定義
upstream django_backends {
    server 127.0.0.1:8001;
    server 127.0.0.1:8002;
    server 127.0.0.1:8003;
}

server {
    listen 443 ssl;
    http2 on;
    server_name example.com;

    # SSL設定(省略)

    location / {
        proxy_pass http://django_backends;
        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;
    }
}

負荷分散アルゴリズム

アルゴリズム設定動作
ラウンドロビン(デフォルト)順番にリクエストを振り分ける
重み付けweight=Nサーバーの性能に応じて振り分け比率を設定
最少接続least_conn接続数が最も少ないサーバーに振り分ける
IPハッシュip_hash同じクライアントIPを同じサーバーに固定
重み付け + ヘルスチェックの例
upstream django_backends {
    least_conn;

    # 高性能サーバーに多くのリクエストを割り当て
    server 192.168.1.10:8000 weight=3;
    server 192.168.1.11:8000 weight=2;
    server 192.168.1.12:8000 weight=1;

    # 障害時のバックアップサーバー
    server 192.168.1.20:8000 backup;

    # ヘルスチェック: 3回失敗で30秒間除外
    server 192.168.1.10:8000 max_fails=3 fail_timeout=30s;
}

セッションの永続化
Djangoでセッションを使っている場合、ip_hash を指定するか、セッションストレージをRedis等の共有ストレージに変更することで、どのサーバーに接続しても同じセッションを参照できます。

Step 6セキュリティヘッダーの設定

HTTPレスポンスヘッダーを追加して、ブラウザ側のセキュリティ機能を有効にします。

/etc/nginx/conf.d/security-headers.conf
# XSS対策
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;

# HTTPS強制(HSTS)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# リファラーポリシー
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# コンテンツセキュリティポリシー(CSP)
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self';" always;

# Permissions Policy
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

各ヘッダーの役割

ヘッダー役割
X-Content-Type-OptionsMIMEタイプのスニッフィングを防止
X-Frame-Optionsiframe埋め込み(クリックジャッキング)を防止
Strict-Transport-SecurityブラウザにHTTPS接続を強制
Referrer-Policyリファラー情報の送信範囲を制御
Content-Security-Policy読み込み可能なリソースの提供元を制限
Permissions-PolicyブラウザAPI(カメラ・位置情報等)の使用を制限

CSPは段階的に導入する
Content-Security-Policyを厳しく設定しすぎると、サイトが正常に動作しなくなる場合があります。まず Content-Security-Policy-Report-Only ヘッダーで違反を検出し、問題がないことを確認してから本番適用しましょう。

追加のセキュリティ設定

/etc/nginx/conf.d/myapp.conf(serverブロック内)
# サーバーバージョンの非表示
server_tokens off;

# リクエストサイズの制限(ファイルアップロード対応)
client_max_body_size 10m;

# レート制限(DDoS対策)
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

location /api/ {
    limit_req zone=api burst=20 nodelay;
    proxy_pass http://127.0.0.1:8000;
}

# 不要なHTTPメソッドを拒否
if ($request_method !~ ^(GET|HEAD|POST|PUT|PATCH|DELETE)$) {
    return 405;
}

設定完了チェックリスト

  • nginxのインストールと起動を確認した
  • リバースプロキシの基本設定を行った
  • プロキシヘッダー(Host, X-Real-IP等)を設定した
  • SSL証明書を取得し、HTTPS通信を有効にした
  • HTTPからHTTPSへのリダイレクトを設定した
  • TLS 1.2/1.3のみを許可した
  • セキュリティヘッダーを追加した
  • server_tokensをoffにした
  • sudo nginx -t で設定の構文チェックを行った
  • ロードバランシングの必要性を検討した