NginxでWordPressのSSL化をすると無限ループに陥るのを回避するには

そもそものSSL化の方法についてはこちらのページをご参照ください。

必要な作業時間5分程度

WordPressをまるごとSSL化したり、管理画面のみをSSL化したりと、ニーズはあると思うのですが無限ループに陥るという場合があります。

「Nginx & WordPressの組み合わせ」で無限ループに陥るという場合と、

「Nginx & WordPress & CloudFlare」の組み合わせで無限ループに陥るという場合があります。

以下では、サイトまるごとSSL化する場合という前提でconfファイルを書きます。まるごとSSL化する場合は、httpでのアクセスをhttpsにリダイレクトする必要があるのですが、その為の設定です。何故そうする必要があるかというと、転送せずにhttpでのキャッシュが残ってしまうと、次にhttpsでのアクセスが有った場合にhttpのキャッシュを返すみたいな事が発生するからです(画像やjsが読み込まれず、変な画面になります)。

「Nginx & WordPressの組み合わせ」で無限ループに陥る

wp-config.phpの冒頭 < ?php の次の行に以下のコードを加えてください。

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
  $_SERVER['HTTP_X_FORWARDED_PROTO'] === "https") {
  $_SERVER['HTTPS'] = 'on';
}

define('FORCE_SSL_LOGIN', true);
define('FORCE_SSL_ADMIN', true);

次に、nginxのconfファイルを以下の様に書き換えます。</p>

server {
listen 80;
server_name 設定したいドメイン(例:yourdomain.com);
    return 301 https://yourdomain.com$request_uri;
}

server {
listen 443 ssl;
    # example.com、example.com/wordpress、wp.example.comなどを指定する。
    server_name yourdomain.com;
    # ドキュメントルートの設定
    root        /var/www/html/yourdomain.com;
    index       index.html index.htm;
    charset     utf-8;

#SSL用設定ブロックここから
    ssl_certificate_key /etc/nginx/ssl/秘密鍵.key;# 秘密鍵 (cert. key)
    ssl_certificate  /etc/nginx/ssl/合体証明書.crt;# 合体証明書
    ssl_protocols           TLSv1 TLSv1.1 TLSV1.2;
    ssl_ciphers             HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
#SSL用設定ブロックここまで

    access_log  /var/log/nginx/$host.access.log  main;
    error_log   /var/log/nginx/$host.error.log;

    # アクセスログ、Not Foundログを無効にするための設定を読み込みます
    include     /etc/nginx/conf.d/common/drop.conf;

    rewrite /wp-admin$ $scheme://$host$uri/ permanent;

    # 変数の初期化
    set $mobile '';
    # 携帯やスマートフォンを別々にキャッシュしたい場合は先頭の#を外す
    #include /etc/nginx/conf.d/common/mobile-cache.conf;

    location ~* ^/wp-(content|admin|includes) {
        index   index.php index.html index.htm;
        if ($request_filename ~ .*\.php) {
            break;
            proxy_pass http://backend;
        }
        # expiresヘッダー用の設定を読み込みます。
        include /etc/nginx/conf.d/common/expires.conf;
    }

    location / {
        # PHPファイルへのアクセスの場合バックエンドに処理が投げられる。
        if ($request_filename ~ .*\.php) {
            break;
            proxy_pass http://backend;
        }
        # expiresヘッダー用の設定を読み込みます。
        include /etc/nginx/conf.d/common/expires.conf;

        # デフォルトではキャッシュするように変数に0をセットする。
        set $do_not_cache 0;
        # WordPressにログインしている場合はキャッシュしないように変数に1をセットする。
        if ($http_cookie ~* "comment_author_|wordpress_(?!test_cookie)|wp-postpass_" ) {
            set $do_not_cache 1;
        }
        # POSTアクセスの場合もキャッシュしないように変数に1をセットする。
        if ($request_method = POST) {
            set $do_not_cache 1;
        }
        proxy_no_cache     $do_not_cache;
        proxy_cache_bypass $do_not_cache;

        proxy_redirect     off;
        proxy_cache        czone;
        proxy_cache_key    "$scheme://$host$request_uri$mobile";
        proxy_cache_valid  200 0m;

        # do_not_cacheの値が1の場合バックエンドに処理が投げられる。
        proxy_pass http://backend;
    }

#SSL用設定ブロックここから
        proxy_set_header Host                   $host;
        proxy_set_header X-Forwarded-Proto      https;
        proxy_set_header X-Forwarded-Server     $host;
        proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;
#SSL用設定ブロックここまで

    # 50x系のページ設定/usr/share/nginx/htmlにあるファイルが使用される
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

書いてしまえばこんな感じです。
yourdomain.comを自分のドメインに変更。
rootも適切に設定してください。
keyとcrtも適切に。
#SSL用設定ブロックと書いた部分は通常のhttp接続の場合にはなくても大丈夫な部分だと思いますので追記してください。
追記後nginxを再起動すればOK。

service nginx restart

「Nginx & WordPress & CloudFlare」の組み合わせで無限ループに陥る

ずっと上手くいかなくて悩んでいたのですが、こちらも解決したので書いとく。
CloudFlareを使っていると適切に設定してないと無限ループになる。
Nginxのconfファイルは全然違わないのに、ドメインAは大丈夫でドメインBが上手く行かない…という事があって、原因がなんだか分からなかったのですが、どうやらCloudFlareの設定であると。

若干のconfファイルの修正と、CloudFlareの設定変更が必要です。

CloudFlareのSSL設定

こちらの設定がFullになっていることを確認してください。

full

これに加えて、Nginxのconfファイルの編集

server {
listen 80;
server_name 設定したいドメイン(例:yourdomain.com);
location / {
  if ($http_x_forwarded_proto = "http") {
    return 301 https://yourdomain.com$request_uri;
        }
    }
}

この変更を加えてNginxを再起動すればリダイレクトループから抜け出せると思います。

オススメNginx本

nginx実践入門 (WEB+DB PRESS plus) 単行本(ソフトカバー) – 2016/1/16

nginxを現場で活用するための知識を、実践的なノウハウを交えて解説した書籍です。nginxのインストール方法や基本的な設定方法からはじめ、nginxを利用した「静的コンテンツ配信サーバ」「HTTPSサーバ」「Webアプリケーションサーバ」「大規模コンテンツ配信システム」の構築方法をそれぞれ詳しく紹介しています。後半ではnginxサーバのモニタリングやログの収集、そして軽量スクリプト言語Luaでnginxを拡張する方法について解説しているので、nginxをこれから使う方はもちろん、さらに活用したい方にもお勧めです。

公開日: