ちょっと話題の記事

NginxでCloudFrontにリダイレクトしてカスタムオリジンで負荷分散する

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

既に運用中のWordPressなどのWebサイトを負荷分散/軽減させたい

既に運用中のWordPressなどのWebサイトに一切手を加えずに負荷分散や軽減をしたいと思いませんでしょうか。そんなとき、Nginxなどのリバースプロキシを入れてコンテンツの圧縮やキャッシュ設定をすることは前回ご紹介しました。今回は、さらに踏み込んで超大規模なアクセスがあったときにも負荷を分散&軽減できるようにCloudFrontというコンテンツ配信ネットワークサービスを用います。

CloudFront

CloudFrontは、AWSが提供しているコンテンツ配信サービスです。主に、S3のオリジンバケットをエッジサーバに配備して負荷分散を行います。まずは配信したいファイルをS3においてからCloudFrontに登録手続きをする必要があったのですが、カスタムオリジンといって既に動いているWebサイトそのものを指定できるようになりました。以下の図は今回何をどのような順番で実現しているか表したものです。1番目の図は、ブラウザからWordPressを閲覧した際に静的コンテンツは圧縮されておらず、キャッシュ設定や、別サーバによるコンテンツ配信もありません。2番目の図は、WordPressの前にリバースプロキシサーバとしてNginxを置いています。今回は同一のサーバにインストールしました。WordPressのサーバを8880ポートで起動して、Nginxを80番でリクエストを受け付けるようにしています。このNginxでは、Gzip圧縮やExpiresタグを付けています。3番目の図は、静的コンテンツをS3にアップロードしてWordPressからS3を参照するようにしています。別サーバからファイルを読み込みますので、サーバのディスクI/Oによる遅延を無くします。また、別ドメインのサーバに置く事でブラウザの読み込みも早くなります。4番目の図は、S3に置いた静的コンテンツをCloudFrontに配備しています。S3は長期保存用のストレージサービスですので、高速に読み込む事はできません。高速に配信するためにCloudFrontを使っています。最後の5番目の図は、CloudFrontのカスタムオリジン機能を使って、S3を使わずにダイレクトにNginxを通じたWordPressをCroudFrontに登録しています。

WordPressに一切手を加えない方法

WordPressに一切手を加えずに、静的コンテンツをコンテンツ配信サーバに置く方法ですが、答えはURLのリダイレクトにあります。Nginxにはリダイレクトを指定することができます。HTTPステータスコード301/302を指定することで実現できます。主に静的コンテンツをコンテンツ配信サーバに置きます。nginx.confの表記をご覧ください。rewriteの部分が肝です。www.akari7.netのドメインで各種静的ファイルであった場合、cdn.akari7.netにリダイレクトしています。ただし、このままでは正しく動きません。詳しくは後で説明します。

        location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico)$ {
            expires 1h;
            access_log off;
            rewrite ^ http://cdn.akari7.net$request_uri? last;
        }

CloudFrontのカスタムオリジン指定時にリダイレクト回避

CloudFrontはNginxのURLを指定することで自動で情報を収集してコンテンツ配信サーバに配備をします。その際、各種ヘッダ情報もコピーします。例えば、GzipやExpiresなどです。そして、301/302のリダイレクトもコピーしてしまいます。これは大きな問題です。なぜならば、コンテンツ配信サーバを見ると静的コンテンツの場所として自分自身にリダイレクトしてしまうからです。ここでハマりました。解決策はユーザエージェントです。ユーザがブラウザから閲覧する場合はCloudFrontにリダイレクトします。そして、CloudFrontがカスタムオリジンを登録する際はリダイレクトを指定しないようにします。CloudFrontのユーザエージェントは、"Amazon CloudFront"です。以下のように分岐をしました。

        location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico)$ {
            expires 1h;
            access_log off;
            if ($http_user_agent != "Amazon CloudFront"){
                rewrite ^ http://cdn.akari7.net$request_uri? last;
            }
        }

Nginxの設定最終版

Gzip、Expires、CloudFront対策を行ったNginxの設定が以下になります。ただし、モバイル対応とかクッキー対応はしていません。これについては別の機会にて。

user              nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

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

    sendfile        on;
    keepalive_timeout  65;
    server_tokens off;

    gzip on;
    gzip_http_version 1.1;
    gzip_types text/plain
               text/xml
               text/css
               application/xml
               application/xhtml+xml
               application/rss+xml
               application/javascript
               application/x-javascript;
    gzip_buffers 4 8k;
    gzip_min_length 1000;
    gzip_comp_level 1;
    gzip_proxied off;
    gzip_disable "MSIE [1-6]\."  "Mozilla/4";
    gzip_vary off;

    upstream backend {
        server localhost:8880;
    }

    server {
        listen 80;
        server_name www.akari7.net;
        root /var/www/html/;

        location / {
            proxy_pass http://backend;
        }
        location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico)$ {
            expires 1h;
            access_log off;
            if ($http_user_agent != "Amazon CloudFront"){
                rewrite ^ http://cdn.akari7.net$request_uri? last;
            }
        }
    }    
}

CloudFrontのカスタムオリジン登録

カスタムオリジン用にRoute 53でDNS設定

cdn.akari7.netというドメインをCNAME指定しましたので、Route 53にてCNAME登録します。

動作確認

全て設定が終わりましたので動作確認します。wwwからcdnへリダイレクトしている事が分かります。また、リダイレクトループせずに表示できていることも分かります。CloudFrontから配信されているデータには、Gzip、Expire、Cache-Controlなどのタグがついているのが見て分かります。

まとめ

今回は、既に動いているWordPressのコンテンツに一切手を加えることなく、Nginxによるリバースプロキシとリダイレクト、CloudFrontのカスタムオリジンによって、Webサイトの負荷分散を実現することができました。Nginxはロードバランサーとしても動作させることもできますので、かなり大規模なアクセスがあったとしても耐えることができそうですね。nginx.confを理解して負荷分散マエストロになりましょう!