nginxでwordpressをSSLサイト化しようとした話。

Linux

まだ途中ですが・・・とりあえず公開します。HTTPで運用中のWordpressをnginxでSSLサイトにするための方法です。まだ途中ですが。

やっと管理画面にSSLで入れるようになったので・・・ここまで公開します。nginxでhttpsでHTTP/2とか、旬を過ぎたためか、既にネットに公開されている方法が結構古い情報ばかりになっているので、このブログで適応した時のログです。一応、最新版対応。

nginx SSL with mod_pagespeed with ssl-ct

というわけで、全部盛りnginxを作る方法です。環境は以下。dockerのimageのオペレーションなどは割愛します。Dockerfileで作っても良かったのですが、とりあえず手で作る方法。

  • docker on CentOS 6
  • dockerの中身はCentOS 7(latest)
  • nginx 1.9.10 mainline
  • ngx_pagespeed
  • nginx-ct

Certificate Transparency(CT)は対応していない認証局もあるのですが、一応入れておきます。

まずはdockerの準備。volumeは当方固有の設定なので気にしないでください。

% docker run -it -h nginx.home --name nginx.home -v /share/www/html:/var/www/html -v /share/nginx.home/var/log:/var/log -v /share/socks:/socks -p 443:443 centos:centos7 /bin/bash

初期設定はこんな感じ。タイムゾーンって、こうやって設定しないとダメだよね。

ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
yum install -y git gcc-c++ make
yum install -y pcre-devel openssl-devel libxslt-devel gd-devel zlib-devel
yum install -y geoip-devel wget golfing unzip
useradd nginx

パッケージを入れていきます。まずは、ngx_pagespeedを収集。psol(PageSpeed Optimization Libraries)のダウンロードも必要なようで。

cd /tmp
git clone https://github.com/pagespeed/ngx_pagespeed.git
cd /tmp/ngx_pagespeed/
wget https://dl.google.com/dl/page-speed/psol/1.10.33.2.tar.gz
tar -xzvf 1.10.33.2.tar.gz

ssl-ctに対応させるために、openssl 1.0.2以上をダウンロード。これはngixコンパイルでソースツリーが見えれば良いだけなのでインストールは不要。

cd /tmp
wget https://www.openssl.org/source/openssl-1.0.2f.tar.gz
tar zxvf openssl-1.0.2f.tar.gz

ssl-ctをダウンロードして展開します。

cd /tmp
wget https://github.com/grahamedgecombe/nginx-ct/archive/master.zip
unzip master.zip

最後に、nginxダウンロード。

cd /tmp
wget http://nginx.org/download/nginx-1.9.10.tar.gz
tar zxvf nginx-1.9.10.tar.gz

ここまで揃ったところで、晴れてnginxをコンパイルします。コンパイルオプションですが、nginxをyumレポジトリから入れたときに入るバイナリのコンパイルオプション(nginx -Vで表示)を参考にします。ほぼそのままですが、2箇所だけ修正しています。

  • libaio対応を切っています。aio対応は、カーネルバージョンによる制限があり、docker環境だと、ベースとなっている環境によって通ったり通らなかったりします(CentOS6上のdockerだときっと通るけど、CoreOS上のdockerでは通らなかった)。
  • コンパイラオプションをシンプルにしています。これもコンパイル環境によるものかと思いますが、もともとのオプションだと「intのサイズが分からない」とか、訳の分からないエラーで止まったため、シンプルな最適化オプションだけを残しています。
cd /tmp/nginx-1.9.10

./configure --add-module=../ngx_pagespeed \
--add-module=../nginx-ct-master --with-openssl=../openssl-1.0.2f \
--prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module \
--with-http_realip_module --with-http_addition_module --with-http_sub_module \
--with-http_dav_module --with-http_flv_module --with-http_mp4_module \
--with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module \
--with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module \
--with-threads --with-stream --with-stream_ssl_module --with-http_slice_module --with-mail \
--with-mail_ssl_module --with-ipv6 --with-http_v2_module \
--with-cc-opt='-O2 -g -pipe -m64 -mtune=generic'

make 
make install

これで、nginxが、パッケージと同じファイルロケーションで出来上がります。/usr/localがお好きな方は、path周りのオプションを指定しないなどでもOKでしょう。問題は無いかと。

nginx起動時に、/var/cache/nginxとかアクセスできないって言われると思いますので、必要なフォルダを作成して、nginx:nginxでアクセスできるようにします。

SSL証明書はStartCom / StartSSL

SSL証明書をどこで作るか、ですが、みんな大好きStartSSLにしました。いやまぁLetsEnctyptが本当は良いのでしょうが、あまりにお手軽に見せるためにいろいろ至れりつくせり過ぎて、むしろ使いづらい印象があります。ただ、こちらはCertificate Transparencyも使えるようなので、オススメはオススメです。逆にStartSSLは無料だとCertificate Transparencyに(現時点では)対応していないようで。何かやり方あるのかなぁ・・・。

StartCom / StartSSL

StartSSLでのSSL証明書の取得方法とかは割愛します。ドメイン認証をpostmaster宛のメールで取って、個人証明書を払い、続いてドメインウィザードでWebサーバー向けSSL証明書を取得すればOK。LetsEnctyptでは自動化されてしまっているCSRの生成等は手でやる必要があります。

openssl genrsa 2048 > privkey.pem
openssl req -new -key privkey.pem -sha256 > blog.ayurina.net.csr

サブジェクトの中身はCommonName(=サイトFQDN)以外は適当でOKだと思います(保証はしません)。秘密鍵にパスワードかけたい人はよしなに。ただWebサーバー起動時にパスフレーズ入れなきゃいけなくなりますので。

こうして出来たCSRをStartSSLのページにアップロードすればOKです。ToolBoxのCertificate Listに個人証明書とともにサーバー証明書が追加され、ダウンロードが可能になります。

さて、ダウンロードすると、いくつか証明書ファイルがダウンロードされてきます。nginx用とおぼしきファイルを見ると、証明書チェーン含めたファイルになっているので、これをnginxに読ませればOKです。ちょっと驚いたのですが、URLはcnではなく、subjectAltNameに入ってきたこと。普通にCSRは作ってるんですがね。そんなことできるんだ、って感じ。subjectAltNameを使うと複数FQDNへの対応とかできるようで、比較的最近のブラウザ環境では対応している設定です。どうやらデファクトですね。

nginx SSLを設定する

やっと材料がそろったので、設定します。どうせやるなら、的な設定も追加しています。nginx.confの、SSLに関する部分を抜粋します。

    # HTTPS server
    server {
        listen       443 ssl http2;
        server_name  localhost;

        ssl_certificate      blog.ayurina.net.crt;
        ssl_certificate_key  privkey.pem;

        #ssl_ct on;
        #ssl_ct_static_scts /etc/nginx/scts;

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_ciphers  "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
        ssl_prefer_server_ciphers  on;

        ssl_dhparam /etc/nginx/dhparams_4096.pem;

        # Enable OCSP (Online Certificate Status Protocol) Stapling
        ssl_stapling on;
        ssl_trusted_certificate /etc/nginx/ca.crt;
        ssl_stapling_verify on;
        resolver 8.8.4.4 8.8.8.8 valid=300s;
        resolver_timeout 10s;

        root   /var/www/html/wordpress;
        index  index.html index.php;

        location ^~ /index.php/ {
            try_files $uri /index.php;
        }
        location / {
                proxy_redirect                          off;
                proxy_set_header Host                   $host;
                proxy_set_header X-Forwarded-Proto      https;
                proxy_set_header X-Forwarded-Server     $host;

                try_files $uri $uri/ /index.php;
        }
        location ~ \.php($|/) {
                include fastcgi_params;
                fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                fastcgi_pass   unix:/socks/php-fpm.sock;
                fastcgi_pass_header "X-Accel-Redirect";
                fastcgi_pass_header "X-Accel-Expires";
        }
        location ~ /\.ht {
            deny  all;
        }
    }

まず、プロトコルは「443 ssl http2」で、HTTP/2(SPDY)に対応させます。これをやりたくてここまで来たので。HTTP/2で繋がっているかどうかは、Chromeで「HTTP/2 and SPDY indicator」プラグインを追加してアクセスすると分かります。『青いイナズマ』になれば、HTTP/2で繋がってるってこと。青いイナズマ・・・SMAPだなぁ(苦笑)。

SSL CTは結局有効にしていません。StartSSLで払われた証明書が対応していないため。CT対応には幾つか方法があるようですが、ここはまだそんなに追求してないところです。

ssl_dhparamは、セッション鍵を交換するために利用するDH鍵ファイルを指定する。Cipherは明示的に候補を並べて、低い暗号強度のCipherが選ばれないようにする。個人的には、「!SHA」とかしちゃうところなんですが、それはそれであまり良くないらしいので。

OCSPについての設定はどこかのサイトの情報をコピー。ポイントはssl_trusted_certificate。この設定で指定するファイルには、サイト証明書の証明書チェインにあるroot CAからの公開鍵をすべて含めたファイルを指定する。StartSSLの場合、root+中間証明書の2つの証明書を列挙することで、OCSP validになる。

その下が概ねWordpress用の設定だけど、一個だけ、引っかかったポイントがあるので、注記。「try_files $uri $uri/ /index.php;」。これを間違えて「try_files $uri /index.php;」だけにすると、管理画面に入れなくなる。ポイントは、「/wp-admin/」を「/wp-admin/login.php」までリダイレクトで持ってくるところなんだけど、ここに「$uri/」つまり、ディレクトリ指定のときの挙動を書いておかないと、ハマる。私はこれで数時間悩んだ。デバッグ方法は「curl -I https://hostname/wp-admin/」。Locationヘッダで、/wp-admin/が返ってきたらアウト。login.phpにリダイレクトされるのが正解。きっとこんなところでハマるヤツは居ないと思いつつ、自分は刺さったので書いておきます。

というわけで、これでSSLサイトが動きます。

テストしてみよう。

最後に、QUALYS SSL Labsのテストをしてみる。

QUALYS SSL Labs / SSL Server Test

結果、A判定です。いい感じ。

スクリーンショット 2016-02-06 20.47.17

で、結局WordpressはSSL化していません。

という感じで、SSLサイトは準備したのですが、Wordpressについては、現状、管理画面のみ、SSL化しています。本当は常時SSLサイトにしたかったんですが、アフィリエイト関連含め、外部サイトのincludeがすべてSSLで通るか、確認が面倒だから・・・。Amazonはそのままでは通らないとか、なんだかSSL化するのは大変らしいです。とは言え、SSLサイトはできたので、一歩前進。まだメインサイト(http)はapacheなんですがね・・・。

いろいろ調査して、どっかで切り替えられたら嬉しいなぁ、と思いつつ。

コメント

  1. […] nginxでwordpressをSSLサイト化しようとした話。 […]

タイトルとURLをコピーしました