WordPress用nginxの設定 with SSL


WordPress + nginxの設定をしていて、VPS等で運用していた場合、お隣でtcpdumpとかしているとWordPressにログインした場合にパスワードがキャプチャされてしまいそうなので、管理者がログインするときは必ずHTTPSにリダイレクトし、HTTPSへの接続も制限するような設定にします。

前提環境のセットアップは『お名前.comのレンタルサーバ(KVM)上へwordpress3.9.xをインストールする』参照。

  • WordPressへのログインはHTTPSのみ認めるようにする
  • 自分用なので自己署名証明書を使う

まずは、HTTPSで通信する際には証明書がいるので、自己署名証明書を作成します。

sudo mkdir /etc/nginx/keys
sudo openssl genrsa -aes256 -out server.key 2048
sudo openssl req -new -key server.key -out server.csr
sudo openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

# サーバ起動のたびにパスフレーズを聞かれないようにパスフレーズを解除。
sudo cp server.key server.key.org
sudo openssl rsa -in server.key.org -out server.key

sudo chown root:root ./server*
chmod 0400 server.key

/etc/nginx/sites-available/defaultのバックアップと編集

sudo cp /etc/nginx/sites-available/default \
  /etc/nginx/sites-available/default.original

sudo vi /etc/nginx/sites-available/default

/etc/nginx/sites-available/defaultは下記のように編集★マークの部分は、編集の必要がある箇所です。環境に合わせて前後のコメントから修正してください。

server {
  listen 80;

  # IPv6は使わない。
  #listen [::]:80 default_server ipv6only=on;

  # ★サーバ公開時のルートディレクトリ
  root /usr/share/nginx/eco.senritu.net;
  index index.php;
  server_name eco.senritu.net;

  location / {
    try_files $uri $uri/ =404;
    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
      root /usr/share/nginx/html;
    }

    # /wp-admin/admin-ajax.php専用。
    location ~ /wp-admin/admin-ajax.php {
      try_files $uri =404;
      fastcgi_split_path_info ^(.+\.php)(/.+)$;
      fastcgi_pass unix:/var/run/php5-fpm.sock;
      fastcgi_index index.php;
      fastcgi_keep_conn on;
      include fastcgi_params;
    }

    # /wp-admin,/wp-loginへのアクセスを制限する
    # 管理者以外はログイン画面も表示させるべきではない。
    # SSLで同等の設定をしていて、IPアドレスによる制限もしていなければ、
    # ここは削除してしまっても良い
    location ~ ^/wp-(admin|login)  {
      # ログイン画面は信頼できるIP以外からのアクセスを拒否する。
      # レンジ指定可能なので/24とかでもOK。
      allow 192.168.3.33/32;  # ★ここ、信頼できるIPのレンジを指定する
      deny all;
      # 管理画面へのアクセスはHTTPSにリダイレクトする。
      rewrite ^(.*) https://eco.senritu.net$1 permanent;  # ★自分のドメインにする

      # SSL経由ではなく、HTTPで管理画面にアクセスする場合は、
      # 上記のrewriteをコメントアウトして、下記のコメントアウトを外す
#     location ~ \.php$ {
#       try_files $uri /wp-admin/index.php;
#       fastcgi_split_path_info ^(.+\.php)(/.+)$;
#       fastcgi_pass unix:/var/run/php5-fpm.sock;
#       fastcgi_index index.php;
#       include fastcgi_params;
#     }
   }

  # 一般コンテンツへのアクセス
  # nginxでのlocationの一致で優先される順序は完全一致>正規表現での一致を利用した。
  location ~ \.php$ {
    # 該当ファイルがあるかを事前チェックしている。
    # 事前に何かしらの手段でアップロードされたphpを実行されても嫌なので。
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
    fastcgi_keep_conn on;
    include fastcgi_params;
  }

  # favicon.ico
  location = /favicon.ico {
    log_not_found off;
    expires 30d;
    access_log off;
    try_files $uri /favicon.ico @empty;
  }

  # 検索エンジンからのrobotsへのリクエストはログに残さない
  location = /robots.txt {
    allow all;
    log_not_found off;
    access_log off;
  }

  # .ドットファイルは全部表示させない
  location ~ /\. {
    deny all;
  }

  location ~* /(?:uploads|files)/.*\.php$ {
    deny all;
  }

  # 静的ファイルのキャッシュは24時間有効にし、なかった場合にはログに残さない
  location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
    expires 24h;
    log_not_found off;
  }

  # パーマリンクで投稿名を選んだ場合、存在しないファイルに対してアクセスが来る。
  # その場合には、index.phpを実行するように設定している。
    location ~* {
      try_files $uri $uri/ /index.php;
    }
  }

  location @empty {
    expires 30d;
    empty_gif;
  }
}

# HTTPS server
#
server {
  listen 443;
  server_name eco.senritu.net;  # ★自分のドメインにする
  root /usr/share/nginx/eco.senritu.net;  # ★ルートディレクトリ書き換える
  index index.php;

  ssl on;
  ssl_certificate /etc/nginx/keys/cert.crt;
  ssl_certificate_key /etc/nginx/keys/cert.key;
  ssl_session_timeout 5m;
  ssl_protocols TLSv1.2;
  ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
  ssl_prefer_server_ciphers on;

  # /wp-admin,/wp-loginへのアクセスを制限する
  # 管理者以外はログイン画面も表示させるべきではない。
  location / {
    allow 192.168.3.33/32;
    deny all;
    location ~ (\.php|=true)$ {
      try_files $uri /wp-admin/index.php;
      fastcgi_split_path_info ^(.+\.php)(/.+)$;
      fastcgi_pass unix:/var/run/php5-fpm.sock;
      fastcgi_index index.php;
      include fastcgi_params;
      include conf.d/replace;
    }
    location ~* {
      try_files $uri $uri/ /index.php;
    }
  }
}

# サーバのURLが変更になった場合に、リターンコード301で変更を通知する場合。
# server {
#   listen 80;
#   root /usr/share/nginx/html;
#   server_name beforesite.senritu.net;
#   rewrite ^.* http://eco.senritu.net/ permanent;
#   # URLをそのまま再現する場合。MT等他種のBlogからの引っ越しの場合には、
#   # TOPページに飛ばせば良しと割り切って、上記のルールもあり。その辺は臨機応変に。
#   # rewrite ^(.*) http://eco.senritu.net$1 permanent;
#}

大体こんな感じで良いと思います。

追記

本投稿を書いた後に、一部不正確な内容があったので修正しました。修正個所は/wp-admin/admin-ajax.phpをIPアドレスで跳ねてしまっていると、ログに/wp-admin/admin-ajax.phpにアクセスしようとしてタイムアウトしたと言うエラーが出るために、/wp-admin/admin-ajax.phpのみ、特定IP以外からでもアクセス可能にしました。

なお、locationで固定IPのみ許可しているwp-adminとwp-loginですが、その前に/wp-admin/admin-ajax.php専用の定義を追加しました。これは、nginxのlocation定義が複数あった場合の優先順位が下記の通りだった理由に寄ります(マスタリングNginxを参考にしました)。先に、/wp-admin/admin-ajax.phpのみ、何処からでもアクセス可能にすれば、その後のwp-adminとwp-loginでIPアドレス制限をしても大丈夫と言う設定です。

  1. 正規表現の含まれていない文字列のlocationに対しては、文字列先頭からの最長一致でマッチするロケーションの確認が行われ、これは定義準とは無関係。
  2. 正規表現が含まれるロケーションは定義された順に確認される。正規表現のチェックは最初にマッチしたロケーションで終了。
  3. 正規表現のチェックでもマッチするlocationが無かった場合には、最長一致でマッチしたロケーションが使われる。

参考にしたサイト、書籍

 

タグ付けされた , , . ブックマークする へのパーマリンク.

コメントを残す

メールアドレスが公開されることはありません。