開発室ブログ

apache nginx

nginxをリバースプロキシサーバとして使う[nginx + apache]

久しぶりのブログ更新です・・・

私、弊社の「コーポレートサイトリニューアル」のバックエンド構築に関わりましたので、その辺りで気づいたことをPostしようかと考えておりましたが、今回は、、、枯れた技術の集積で構築と相成りまして。まぁ、コーポレートサイトは会社の顔ですから、攻めた仕様にする必然性も必要性も全く無い訳です。

このコーポレートサイト、驚きの設定/構成はございませんが、細部に拘りを持って設計・制作されております!
「聞きたい」と仰られるのであれば、是非ご説明したいとも思いますが、これから細部のアップデートも予定されておりますし、秘匿すべき点も多々(?)ございますので、控えさせていただきます(笑)。

というわけで、マクラとは全然関係ないネタでは御座いますが・・・

nginxをリバースプロキシサーバとして使う

要は「Apacheを捨て切れない・・・」という事と同義になります。
Apacheと言いますか、狭義で言えば.htaccessが使えるか使えないか、に終始します。

社内でも「バックエンド」と「フロントエンド」は別なチームで…というパターンが増えて参りまして、そんな開発の現場に於いてドキュメントルート以下は「フロントエンドチームの守備範囲」という事になることが主流だと思います。
そういった場面で「.htaccessが使えない」というのは、可成りの確立で「論争」になりますね。

「チーム開発」 を円滑に進めるために、妥協・・・と言いますか、ヘンなこだわりは持たない事も必要、否、、、最重要だと私は思うのです()。

そこで、折衷案。という訳では無いのでしょうが「双方を利用する」と言ったパターンが多いのかな~と思っておりましたが、そうでも無いようで・・・
設定方法やパフォーマンスに与える影響を詳しく解説したサイトやブログが余り無いように思います。

nginxを単体で(WEBサーバーとして)使用した場合、のメリットについては、

  • nginxの方がApacheより速い
  • nginxの方が、処理が軽く、大量のリクエストを処理するのに向いている
  • nginxの方が、設定ファイルがApacheと比較してもより直感的で柔軟に設定を行うことが可能

Apacheとnginxどちらを採用すべきかメリット・デメリット比較 – Qiita

等と盛んに言われたりしておりますが、リバースプロキシとしてだけで使用した場合って、如何なものなのでしょうかね~
(今回はパフォーマンスの比較は行いませんし、その辺りにも言及しません。それはまたの機会ということで・・・)

設定方法

今回も「CentOS 7.x」前提で書き進めます(ホスト名は「foobar.com」と仮定しております)。

当然ですが、Apacheもnginxも両方インストールします。
まず、epelリポジトリをインストールするところから。

# yum install epel-release

nginxをインストール

# yum install nginx

/etc/nginx/conf.dserver.confを作成

# echo "include /etc/nginx/vhosts.conf.d/*.conf" > ./server.conf

同じ階層にvhosts.conf.dディレクトリを作成し、vhost毎の設定ファイルを置く。

# mkdir /etc/nginx/vhosts.conf.d
# cd /etc/nginx/vhosts.conf.d
# vi foobar.com.conf

WEBルートディレクトリを作成しておく

# cd /var/www
# mkdir vhosts
# cd vhosts
# mkdir foobar.com
# cd foobar.com
# mkdir httpdocs logs

/etc/nginx/conf.dssl.confを設置

# vi ssl.conf

で、

ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

↑中身はこれだけ

Apacheのインストール

# yum install httpd mod_ssl

proxy用に待受ポートを設定
/etc/httpd/conf/httpd.conf

#Listen 80
Listen 7080 

/etc/httpd/conf.d/ssl.conf

#Listen 443 https
Listen 7443

/etc/httpd/conf.dvhosts.confを作成

# echo "IncludeOptional '/etc/httpd/conf.d/vhosts.conf.d/*.conf'" > ./vhosts.conf

同ディレクトリにvhosts.conf.dディレクトリを作成し、vhost毎の設定ファイルを置く。

# mkdir /etc/httpd/conf.d/vhosts.conf.d
# cd /etc/httpd/conf.d/vhosts.conf.d
# vi foobar.com.conf

ディレクトリ、.confファイルをどのように構成するか、どの位置に置くかはお好みで。また、proxyのTCPポート(例ではhttp->7080, https->7443)もサーバ内ローカルでしか使われませんので、ある程度ご自由に。

.confの書き方

(ホスト名は「foobar.com」と仮定しております)

nginx

server {
    listen 443 ssl;

    server_name foobar.com;
    server_name www.foobar.com;

    ssl on;
    ssl_certificate "/etc/pki/vhosts/foobar.com/cert.crt";
    ssl_certificate_key "/etc/pki/vhosts/foobar.com/private.key";

    client_max_body_size 128m;

    root "/var/www/vhosts/foobar.com/httpdocs";
    access_log "/var/www/vhosts/foobar.com/logs/proxy_access_ssl_log";
    error_log "/var/www/vhosts/foobar.com/logs/proxy_error_ssl_log";

    index index.html index.htm index.php;

    location / {
            proxy_pass https://127.0.0.1:7443;
            proxy_set_header Host             $host;
            proxy_set_header X-Real-IP        $remote_addr;
            proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;
            proxy_set_header X-Accel-Internal /internal-nginx-static-location;
            access_log off;
    }
}

server {
    listen 80;

    server_name foobar.com;
    server_name www.foobar.com;

    client_max_body_size 128m;

    root "/var/www/vhosts/foobar.com/httpdocs";
    access_log "/var/www/vhosts/foobar.com/logs/proxy_access_log";
    error_log "/var/www/vhosts/foobar.com/logs/proxy_error_log";

    index index.html index.htm index.php;

    location / {
        proxy_pass http://127.0.0.1:7080;
        proxy_set_header Host             $host;
        proxy_set_header X-Real-IP        $remote_addr;
        proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_set_header X-Accel-Internal /internal-nginx-static-location;
        access_log off;
    }
}

因みに「logファイルの書き出し場所がヘン」等の苦情は受け付けません。

Apache

<IfModule mod_ssl.c>
    <VirtualHost 127.0.0.1:7081>
        ServerName "foobar.com"
        ServerAlias "www.foobar.com"
        UseCanonicalName Off

        DocumentRoot "/var/www/vhosts/foobar.com/httpdocs"
        LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined
        CustomLog /var/www/vhosts/foobar.com/logs/access_ssl_log combined-remote-ip
        ErrorLog "/var/www/vhosts/foobar.com/logs/error_ssl_log"

        SSLEngine on
        SSLVerifyClient none
        SSLCertificateFile /etc/pki/vhosts/foobar.com/cert.crt
        SSLCertificateKeyFile /etc/pki/vhosts/foobar.com/private.key
        SSLCertificateChainFile /etc/pki/vhosts/foobar.com/chain.pem

        <Directory /var/www/vhosts/foobar.com/httpdocs>
            AllowOverride All
            SSLRequireSSL
            Options -Includes +ExecCGI
        </Directory>

        DirectoryIndex "index.html" "index.htm" "index.php"

        <Directory /var/www/vhosts/foobar.com>
            AllowOverride AuthConfig FileInfo Indexes Limit Options=Indexes,SymLinksIfOwnerMatch,MultiViews,FollowSymLinks,ExecCGI,Includes,IncludesNOEXEC
        </Directory>
    </VirtualHost>
</IfModule>

<VirtualHost 127.0.0.1:7080>
    ServerName "foobar.com"
    ServerAlias "www.foobar.com"
    UseCanonicalName Off

    DocumentRoot "/var/www/vhosts/foobar.com/httpdocs"
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined
    CustomLog /var/www/vhosts/foobar.com/logs/access_log combined
    ErrorLog "/var/www/vhosts/foobar.com/logs/error_log"

    <IfModule mod_ssl.c>
        SSLEngine off
    </IfModule>

    <Directory /var/www/vhosts/foobar.com/httpdocs>
        AllowOverride All
        Options -Includes +ExecCGI
    </Directory>

   DirectoryIndex "index.html" "index.htm" "index.php"

    <Directory /var/www/vhosts/foobar.com>
        AllowOverride AuthConfig FileInfo Indexes Limit Options=Indexes,SymLinksIfOwnerMatch,MultiViews,FollowSymLinks,ExecCGI,Includes,IncludesNOEXEC
    </Directory>
</VirtualHost>

実際に動作させてみた設定ファイルからはちょっと端折ってますが、概ねこのような感じです。

リバースプロキシでリモートIPアドレスが正しく取得できない

今回はPHPの設定に関しては言及しておりませんが、どうせ利用するんだから・・・って事で、注意点を1つ。
nginx->Apacheのリバースプロキシ構成の場合、この状態でphpinfo()をチェックすると$_SERVER['REMOTE_ADDR']にproxyのIPが表示されます。

「別に良いのでは?」

と、仰るかもしれませんが、これではPHPでIP制限等を利用したソリューションが不可能になってしまいます。
よく見たら、ログもproxyのIP(127.0.0.1)で記録されてたりします・・・

$ cd /etc/httpd/conf.d
$ echo "RemoteIPHeader X-Forwarded-For" > remoteip.conf

と1行書けば、まずは$_SERVER['REMOTE_ADDR']が正しくリモートのIPを返すようになります。

次に、Apacheのログですが、 host毎の.confファイルのCustomLog部分を、

LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined-remote-ip
CustomLog /var/www/vhosts/foobar.com/logs/****_log combined-remote-ip

等としておけばOKです。

Apacheのログの表示形式を設定する方法 〜調べてみた編〜 – Qiita

(↑こちらを参考にさせていただきました)

最後に

Apache、nginxの起動(と有効化)を行って、エラーが出なければ・・・
設定完了です。

よくあるエラーに

nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
or
nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)

的なものが有りますが、此れは「80(443)ポートが先に使われちゃてるよ~」という事で、Apache単独からnginxを介したリバースプロキシ構成に変更する際等に良く起こります。
Apacheの各種モジュールを有効化する際に、

Listen 80
or
Listen 443 ssl

が、http.confssl.confじゃなく、思いもよらない場所に書いてあったりしますので、注意が必要です。

折角nginxを採用したので、矢張りパフォーマンスやチューニング方面のネタも提供したいのですが、、、まだ自信を持って書けるほどの実績を持ち合わせておりませんので、追々Postしたいと思います。

RecentPost