Nginx の SSL/TLS 設定
『Nginx』のSSL設定は、証明書の指定・使用するTLSプロトコルバージョン・暗号スイートの選択・HSTSヘッダーの付与など、複数のディレクティブを組み合わせて構成します。TLS 1.2 と TLS 1.3 を両対応させつつ、古い TLS 1.0 / 1.1 を無効化することが現在のセキュリティベストプラクティスです。SSL Labs(ssllabs.com/ssltest/)の評価でA+を取得するには、HSTS・OCSPステープリング・Forward Secrecyに対応した暗号スイートの設定が欠かせません。
構文
# -----------------------------------------------
# 証明書と秘密鍵の指定
# -----------------------------------------------
# ssl_certificate {証明書ファイルのパス}
# → サーバー証明書(PEM形式)のパスを指定します
# → 中間証明書を含むフルチェーン証明書を指定してください
# 例: ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
# ssl_certificate_key {秘密鍵ファイルのパス}
# → 証明書に対応する秘密鍵(PEM形式)のパスを指定します
# 例: ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# -----------------------------------------------
# TLSプロトコルバージョンの指定
# -----------------------------------------------
# ssl_protocols {プロトコル名 ...}
# → 使用を許可するTLSプロトコルのバージョンを指定します
# → TLSv1.0 と TLSv1.1 は脆弱性があるため無効化してください
# → TLSv1.2 と TLSv1.3 の両対応が現在のベストプラクティスです
# 例: ssl_protocols TLSv1.2 TLSv1.3;
# -----------------------------------------------
# 暗号スイートの指定
# -----------------------------------------------
# ssl_ciphers {暗号スイートのリスト}
# → 使用を許可する暗号スイートをコロン区切りで指定します
# → Forward Secrecy に対応した ECDHE / DHE 系を優先します
# → RC4・3DES・NULL・EXPORT などの脆弱な暗号は除外してください
# 例: ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
# ssl_prefer_server_ciphers {on|off}
# → on にするとクライアントの希望よりサーバーの暗号優先順位を優先します
# → TLSv1.3 ではこの設定は無視されます
# 例: ssl_prefer_server_ciphers on;
# -----------------------------------------------
# HSTSヘッダーの付与
# -----------------------------------------------
# add_header Strict-Transport-Security {値} always;
# → HTTPS接続を強制するレスポンスヘッダーを付与します
# → max-age: ブラウザがHTTPS強制を記憶する秒数(31536000 = 1年)
# → includeSubDomains: サブドメインにも適用します
# → preload: Chrome等のHSTSプリロードリストへの登録に必要です
# 例: add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# -----------------------------------------------
# SSLセッションキャッシュ・タイムアウト
# -----------------------------------------------
# ssl_session_cache {種別:サイズ}
# → SSLセッションのキャッシュ方式とサイズを指定します
# → shared:SSL:10m で全ワーカープロセス共有の10MBキャッシュになります
# → 約4000セッション/MBを格納できます
# 例: ssl_session_cache shared:SSL:10m;
# ssl_session_timeout {時間}
# → キャッシュしたSSLセッションの有効期限を指定します
# → デフォルトは5分。10m(10分)程度が一般的です
# 例: ssl_session_timeout 10m;
# -----------------------------------------------
# OCSPステープリング
# -----------------------------------------------
# ssl_stapling {on|off}
# → OCSPステープリングを有効化します
# → サーバーが証明書の失効情報(OCSPレスポンス)を事前取得し、
# TLSハンドシェイク時にクライアントへ渡します
# → クライアントがCAに直接問い合わせる手間を省き、接続を高速化します
# 例: ssl_stapling on;
# ssl_stapling_verify {on|off}
# → サーバーが取得したOCSPレスポンスの署名検証を有効化します
# → ssl_stapling on と合わせて使用してください
# 例: ssl_stapling_verify on;
# resolver {DNSサーバーIP} valid={キャッシュ秒数}
# → OCSPステープリングでCAのOCSPサーバーを名前解決するDNSを指定します
# 例: resolver 8.8.8.8 8.8.4.4 valid=300s;
# -----------------------------------------------
# DHパラメータファイルの指定(TLSv1.2向け)
# -----------------------------------------------
# ssl_dhparam {DHパラメータファイルのパス}
# → DHE暗号スイートで使用するDiffie-Hellmanパラメータファイルを指定します
# → 2048ビット以上を推奨します
# → 生成: sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048
# 例: ssl_dhparam /etc/nginx/dhparam.pem;
構文一覧
| ディレクティブ | 説明 |
|---|---|
ssl_certificate | サーバー証明書(PEM形式)のパスを指定します。中間証明書を含むフルチェーン証明書を指定してください。 |
ssl_certificate_key | 証明書に対応する秘密鍵(PEM形式)のパスを指定します。ファイルのパーミッションを 600 に設定してください。 |
ssl_protocols | 使用を許可するTLSプロトコルのバージョンを指定します。TLSv1.2 TLSv1.3 の指定が現在のベストプラクティスです。 |
ssl_ciphers | 使用を許可する暗号スイートをコロン区切りで指定します。Forward Secrecy に対応した ECDHE / DHE 系を優先してください。 |
ssl_prefer_server_ciphers | on にするとクライアントの希望よりサーバーの暗号優先順位を優先します。TLSv1.3 では無視されます。 |
add_header Strict-Transport-Security | HSTSヘッダーを付与してHTTPS接続を強制します。max-age・includeSubDomains・preload を組み合わせて設定します。 |
ssl_session_cache | SSLセッションのキャッシュ方式とサイズを指定します。shared:SSL:10m で全ワーカープロセス共有の10MBキャッシュになります。 |
ssl_session_timeout | キャッシュしたSSLセッションの有効期限を指定します。10m(10分)程度が一般的です。 |
ssl_stapling | OCSPステープリングを有効化します。サーバーが証明書失効情報を事前取得してクライアントに渡すため、TLSハンドシェイクが高速化されます。 |
ssl_stapling_verify | サーバーが取得したOCSPレスポンスの署名検証を有効化します。ssl_stapling on と合わせて使用してください。 |
resolver | OCSPステープリングでCAのOCSPサーバーを名前解決するDNSサーバーのIPアドレスを指定します。 |
ssl_dhparam | DHE暗号スイートで使用するDiffie-Hellmanパラメータファイルのパスを指定します。2048ビット以上を推奨します。 |
使用例
/etc/nginx/sites-available/akane-ssl.conf
# -----------------------------------------------
# HTTP → HTTPS リダイレクト
# -----------------------------------------------
# 常守朱のサイト(akane.example.com)へのHTTPアクセスを
# すべてHTTPSへ301リダイレクトします
# -----------------------------------------------
server {
listen 80;
listen [::]:80;
server_name akane.example.com;
# HTTPアクセスはすべてHTTPSへ永続リダイレクトします
return 301 https://$host$request_uri;
}
# -----------------------------------------------
# HTTPS サーバーブロック(TLS 1.2 / 1.3 対応)
# -----------------------------------------------
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name akane.example.com;
# -----------------------------------------------
# ドキュメントルートとインデックスファイル
# -----------------------------------------------
root /var/www/akane.example.com/html;
index index.php index.html;
# -----------------------------------------------
# 証明書と秘密鍵の指定
# Let's Encrypt で取得したフルチェーン証明書を使用します
# -----------------------------------------------
ssl_certificate /etc/letsencrypt/live/akane.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/akane.example.com/privkey.pem;
# -----------------------------------------------
# TLSプロトコルバージョンの指定
# TLSv1.0 / TLSv1.1 は脆弱性があるため無効化します
# -----------------------------------------------
ssl_protocols TLSv1.2 TLSv1.3;
# -----------------------------------------------
# 暗号スイートの指定
# Forward Secrecy に対応した ECDHE / DHE 系を優先します
# RC4・3DES・EXPORT などの脆弱な暗号スイートは含めません
# -----------------------------------------------
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
# サーバー側の暗号優先順位を優先します(TLSv1.3では無視されます)
ssl_prefer_server_ciphers on;
# -----------------------------------------------
# DHパラメータファイル(TLSv1.2のDHE暗号スイート向け)
# 生成: sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048
# -----------------------------------------------
ssl_dhparam /etc/nginx/dhparam.pem;
# -----------------------------------------------
# SSLセッションキャッシュ
# 全ワーカープロセス共有で10MBのセッションキャッシュを確保します
# 約40000セッションを格納できます
# -----------------------------------------------
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# -----------------------------------------------
# OCSPステープリング
# 証明書の失効情報をサーバーが事前取得し、
# TLSハンドシェイク時にクライアントへ渡します
# -----------------------------------------------
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# -----------------------------------------------
# セキュリティヘッダーの付与
# -----------------------------------------------
# HSTS: 1年間(31536000秒)HTTPSを強制します
# includeSubDomains でサブドメインにも適用します
# preload はHSTSプリロードリスト登録時に必要です
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# クリックジャッキング対策
add_header X-Frame-Options "SAMEORIGIN" always;
# MIMEタイプスニッフィング対策
add_header X-Content-Type-Options "nosniff" always;
# XSS対策(モダンブラウザ向け)
add_header X-XSS-Protection "1; mode=block" always;
# -----------------------------------------------
# PHP-FPM との連携設定
# -----------------------------------------------
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param HTTPS on;
}
# -----------------------------------------------
# Let's Encrypt の更新用ディレクトリ
# -----------------------------------------------
location ~ /.well-known/acme-challenge/ {
allow all;
root /var/www/html;
}
}
実行するコマンドは次の通りです。
$ sudo nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful $ sudo systemctl reload nginx $ curl -I https://akane.example.com HTTP/2 200 strict-transport-security: max-age=31536000; includeSubDomains; preload x-frame-options: SAMEORIGIN x-content-type-options: nosniff x-xss-protection: 1; mode=block
DHパラメータファイルの生成とSSL Labs評価の確認
# ----------------------------------------------- # DHパラメータファイルの生成(初回のみ) # 2048ビットの生成には数分かかることがあります # ----------------------------------------------- # DHE暗号スイート用のパラメータファイルを生成します sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048 # ファイルが生成されたことを確認します ls -lh /etc/nginx/dhparam.pem # ----------------------------------------------- # 設定の構文チェックとリロード # ----------------------------------------------- # 設定ファイルの構文エラーがないか確認します sudo nginx -t # 構文チェックが通ったら設定をリロードします(接続を切断しません) sudo systemctl reload nginx # ----------------------------------------------- # SSL Labs によるオンラインテスト # https://www.ssllabs.com/ssltest/analyze.html?d=akane.example.com # 上記URLにアクセスしてA+評価を確認します # ----------------------------------------------- # TLS接続情報を openssl コマンドで確認します openssl s_client -connect akane.example.com:443 -tls1_2 < /dev/null 2>&1 | grep "Protocol\|Cipher" openssl s_client -connect akane.example.com:443 -tls1_3 < /dev/null 2>&1 | grep "Protocol\|Cipher"
実行するコマンドは次の通りです。
$ ls -lh /etc/nginx/dhparam.pem
-rw-r--r-- 1 root root 424 Mar 25 12:00 /etc/nginx/dhparam.pem
$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ sudo systemctl reload nginx
$ openssl s_client -connect akane.example.com:443 -tls1_3 < /dev/null 2>&1 | grep "Protocol\|Cipher"
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
概要
『NginxのSSL設定』は、ssl_protocols でTLSバージョンを制限し、ssl_ciphers で安全な暗号スイートのみを許可することが基本です。TLSv1.0・TLSv1.1は2018年以降、主要ブラウザで非推奨となっており、TLSv1.2 TLSv1.3 の組み合わせが現在の標準的な構成です。HSTSヘッダー(Strict-Transport-Security)を付与することでブラウザに1年間のHTTPS接続を記憶させられ、プロトコルダウングレード攻撃を防げます。OCSPステープリングを有効化すると、クライアントがCAに直接問い合わせる必要がなくなり、TLSハンドシェイクの高速化とプライバシー向上が期待できます。証明書の取得には Let's Encrypt / Certbot を使うと無料で自動更新まで対応できます。Nginx全般の設定については Nginxの概要 を、パフォーマンスチューニングについては Nginxのパフォーマンス設定 を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。