Apache VirtualHostの効率的な管理方法

ってどうするのが良いのでしょうか。今回の条件は下記として...

  • 開発環境。
  • 複数サービスのVirtualHostを立てたい。
  • 開発環境なのでSSLはとりあえずオレオレ証明書を使いまわす。

とりあえず最近は、開発環境向けにこんな感じで設定している。
設定が変わるたびにいろいろな箇所を修正するのが大変なので、可能な限り共通部分は別ファイルに切りだしてIncludeするように。

conf/
  httpd.conf
conf.d/
  vhost/
    example.com.conf
    _example.com.conf
    _ssl.conf
  • サーバ全体に対する設定はhttpd.confとconf.d/*.confに記述。
  • httpd.confの末尾で、VirtualHostの設定ファイルをInclude。
  • conf.d/vhost 以下に example.com.conf のようなドメイン別ファイルを用意。
  • 80番,443番で共通の設定は _example.com.confのようにドメイン内の共通ファイルを作成し、ドメイン別ファイルからIncludeする。
  • SSLでの共通設定はドメインを超えて _ssl.conf に記述し、各ドメイン別ファイルからIncludeする。

いろいろ端折ってるけどファイルの中身はこんな感じ。

conf/httpd.conf

# ...上部でサーバ全体向けの設定
NameVirtualHost *:80
NameVirtualHost *:443
Include conf.d/vhost/example.com

conf.d/vhost/example.com.conf

<VirtualHost *:80>
    Include conf.d/vhost/_example.com.conf
</VirtualHost>
<VirtualHost *:443>
    Include conf.d/vhost/_example.com.conf
    Include conf.d/vhost/_ssl.conf
</VirtualHost>

conf.d/vhost/_example.com.conf

ServerName example.com
ServerAlias www.example.com

DirectoryIndex index.php
DocumentRoot "/path/to/example.com/www"
<Directory "/path/to/example.com/www">
    AllowOverride All
    Allow from All
</Directory>

CustomLog logs/example.com/access_log combined
ErrorLog logs/example.com/error_log

conf.d/vhost/_ssl.conf

SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
SetEnvIf User-Agent ".*MSIE.*" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0    

で、サービスのVirtualHostを追加するごとに、example.com.conf, _example.com.confが増えていく感じ。

mod_rewriteでリダイレクトあれこれ

ドメインの正規化

wwwあり・なしをどちらか片方に寄せたい場合。
今回はwww.example.comなど、example.com以外でアクセスされたらexample.comにリダイレクトする設定。

<VirtualHost *:80>
    # (1)
    ServerName  example.com
    ServerAlias www.example.com

    RewriteEngine On
    # (2)
    RewriteCond %{HTTP_HOST} !^example\.com
    # (3)
    RewriteRule .* http://example.com$0 [QSA,NE,R=301,L]
</VirtualHost>

(1)で、どちらのホスト名でもVirtualHostが動くようにする。

(2)は正規表現の末尾に$を付けないようにする。Hostリクエストヘッダは

Host = "Host" ":" host [ ":" port ] ; Section 3.2.2

http://www.studyinghttp.net/header#Host

と定義されているように、host名の後に「:ポート番号」が付与される形式がある。

例えば http://www.example.com:80/ にアクセスした場合に

Host: www.example.com:80

と送ってくるクライアントに対応できないので、前方一致で比較する。

(3)で

にアクセスした場合

にリダイレクトする。


リダイレクト時の各オプションは、

QSA

QueryString append。QSAを付与しないとQueryStringを上書いてします。詳しくは後述。

NE

No escape。URLエンコードを抑制する。NEを付与しないと、

にアクセスした場合に「%」が2重にエンコードされ

にリダイレクトされてしまう。

R=301

Moved Permanently

L

ここでルールの適用を終了する。


QSAはこの場合不要だけど、定義変更時に忘れがちなので付けておく。

HTTPSを強制

HTTPでアクセスされたらHTTPSにリダイレクトする。

RewriteEngine On
# (1)
RewriteCond %{HTTPS} !=on
RewriteRule .* https://example.com$0 [QSA,NE,R=301,L]

(1) SSL接続時にmod_ssl環境変数HTTPSにonをセットするのでそれで判断する。

DoCoMo機種の場合、強制的にguid=ONを付与

強制するのはどうなの?って感じですが。

RewriteEngine On
# (1)
RewriteCond %{HTTP_USER_AGENT} ^DoCoMo [NC]
# (2)
RewriteCond %{QUERY_STRING} !^(.*&)?guid=ON(&.*)?$ [NC]
# (3)
RewriteCond %{HTTPS} !=on
# (4)
RewriteRule .* http://example.com$0?guid=ON [QSA,NE,R=302,L]

(1) UserAgentがDoCoMoから始まるもの かつ
(2) QueryStringにguid=ONが含まれていない場合 かつ
(3) HTTPS接続で無い場合
(4) guid=ONを付与してリダイレクトする

ただし、アクセスする度にguid=ON付きURLにリダイレクトしたり、POSTのリクエストがリダイレクトされても困るので、
別途、アプリケーション側で内部リンクに自動的にguid=ONを付与するような仕組みを設けること。

(4)でR=302な理由は、DoCoMo端末のみのリダイレクト(!= Moved Permanently)であるのと、
301リダイレクトだと「サイトが移動しました(301)」のメッセージがでるので302を返すように。

(4)で「QSA」がついていないと、

にアクセスした場合に、Query Stringが書き換えられ

になってしまう。「QSA」が付与されていると

となる。

参考にさせていただいたリンク