リバースプロキシでサーバ移行。


あるWEBアプリケーションのサーバ移行を行うことになったので、長時間サーバを停止せずに移行を行う方法を考えていました。


通常サーバ移行を行う場合は、ネームサーバのZoneのAレコードを書きかえることになるのですが、

example.com A 111.111.111.111(移行前のサーバAのIPアドレス

example.com A 222.222.222.222(移行後のサーバBのIPアドレス
この設定が世界中に存在するDNSサーバ全てに浸透するまでには、結構な時間がかかります。(Zoneで設定しているTTLによります。)
つまり浸透するまでの間は、サーバAとサーバBのどちらに飛ぶかはクライアントが参照しているDNSサーバ次第で、データベースの同期やメールの受信が上手く行かない場合があるということです。


そこで何とかならないか考えた結果、データベースの同期については以下の3つを思いつきました。


1.データベースのリモート接続
あるタイミングで一瞬旧サーバデータベースを止めて、新サーバのデータベースと同期させます。
その後、旧サーバからデータベース接続する時は新サーバのデータベースへ接続するようにして、DNSを変更します。
条件
・両方のデータベースサーバアプリケーションがSSL通信に対応している事。
・WEBアプリケーション部分の改変は無く、ただ丸丸移行する場合に有効。
・データベース以外で同期を図らなければならないものが無い場合。(ローカルファイルをカウンタに使用している場合等)


2.www付き、www無しのURIのどちらか普段使用していない方を新サーバへ向ける。
WEBサイトでは(普通?)www付き、www無しどちらかを正式なURIとしていて、どちらかはあまり使われていません。
そこでexample.comをサーバA、www.example.comをサーバBとします。

example.com A 111.111.111.111
www A 222.222.222.222(もともとはwww CNAME example.comとなっていると思います)
こうしてwwwのDNSが浸透するのを待ちます。
そして移行時に一瞬旧サーバのデータベースを停止し、新サーバのデータベースと同期をさせて、
旧サーバに来たアクセスをすべて新サーバ(www付きのURI)へリダイレクトさせます。

旧サーバの.htaccess等:
RewriteEngine On
Redirect / []http://www.example.com[]
後はwww無しのDNSが完全に浸透したのを見計らって、旧サーバを閉鎖し、新サーバにwww付きで来たアクセスをwww無しにリライトするよう設定しましょう。

新サーバの.htaccess等:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.example\.com
RewriteRule (.*) []http://example.com/$1[] [R=301,L]
条件
・www付き、www無しどちらかのURIが使用されていないこと。
SSLを使用していないこと。⇒どちらか一方のURIしか有効で無いから。


3.Apacheのリバースプロキシを使用


リバースプロキシは通常プロキシサーバへのアクセスをバックエンドの内部サーバに受け流す用途に使われるApacheなどのWEBサーバアプリケーションの拡張機能です。
今回はこれを使用して、旧サーバへのアクセスを新サーバに受け流すことでサーバ移行を実現したいと思います。


まず2と同じように移行時に一瞬旧サーバのデータベースを停止し、新サーバのデータベースと同期をさせます。
次に旧サーバにリバースプロキシの設定を行います。(ディストリビューションUbuntuです)

// 内部的にDNSを新サーバに向ける
$ sudo vim /etc/hosts
222.222.222.222 example.com

// リバースプロキシの設定
$ sudo vim /etc/apache2/sites-available/example

ServerName example.com
ServerAlias www.example.com
ProxyPass / []http://example.com/[]
ProxyPassReverse / []http://example.com/[]


ServerName example.com:443
ServerAlias www.example.com:443
SSLProxyEngine on
ProxyPass / []https://example.com/[]
ProxyPassReverse / []https://example.com/[]

(以下SSL設定のディレクティブ)

// プロキシサーバへのアクセス元ホスト制限を解除
$ sudo vim /etc/apache2/mods-available/proxy.conf

#AddDefaultCharset off
#Order deny,allow
Deny from all
#Allow from .example.com
↓のように変更
Allow from all

// mod_proxyを有効にする
$ sudo a2enmod proxy proxy_http

// example設定情報を有効にする
$ sudo a2ensite example

// Apache再起動
$ sudo apache2ctl graceful

これで、旧サーバにexample.comでアクセスが来た時は、新サーバへと受け流す事が可能です。
一つ注意したいのが、ProxyPass, ProxyPassReverseディレクティブに記述するURIの末尾にスラッシュ(/)を必ずつけることです。これを行わないと画像などコンテンツファイルで502 Proxy Errorが発生します。
また、移行前のサーバと移行先のサーバとの間にファイアーウォールがある場合はProxyPassディレクティブにkeepaliveオプションを付けて、

ProxyPass / []https://example.com/[] keepalive=On
としなければならない場合があります。
条件もmod_proxyさえ使用できればOKで他の方法に比べ縛りが無いので、最初に書いたサーバ移行についてはこの方法を使用する事にしました。


そしてPOP/SMTPの移行方法ですが、2通り考えました。
一つ目は新サーバに旧サーバと同じアカウントを用意し、使用者に移行完了までは両方ともメールクライアントに登録してもらうという(ごく一般的な?)方法。
二つ目は以下のような流れになります。

                                                                                                        • -

旧サーバ   新サーバ

                                                                                                        • -


xx@example.com → xx@example2.com
転送
↓転送

xx@example.com

                                                                                                        • -

つまり新サーバ内ではhosts等で設定した結果、間違いなくexample.comは自サーバを向いているという性質を利用したものです。
移行が完了した時点で、使用者にサーバ名(IPアドレス)・パスワードを送信します。


ただexample.comで使用していたアドレスが多くなればなるほど設定が大変になりますので、前者の方法の方がシンプルで良いと思います。
この方法はメール受信駆動で動くスクリプト用のアカウントなどに使用すると良いかもしれません。


他にもサーバ移行について良い方法があれば是非教えて下さい。


○参考
http://httpd.apache.org/docs/2.2/ja/mod/mod_proxy.html