[squid] 1つのGlobal IPで複数のWebサーバを公開する方法 [debian]

Pocket

自鯖やってますか! 仮想化やってますか! サーバを公開してますか!

ゲッソー
ゲッソー

突然ですけど、最近、RedMineとか使い始めました。家の中で。でも、これが困ったことに、外でも使いたくなるんですよね。

しかし、まぁ、残念ながら我が家は Global IP が一つしかないので、Webサーバを既に 1台公開している状態では、他に立ててしまった WebサーバのRedMineを公開することができないのです。
まぁ、FireWallで、ポート番号を変えてアクセスさせれば、それはそれで対応できるんですが、Webサーバ毎にポートを割り当てるのはナンセンスですし、家の中からの場合と、外からの場合とでアクセスURLが変わってしまうのはちょっと残念です。

さて、どうすれば良いのか、とここ数日で達成しえた内容をレポートします。

目次

1.現状認識

まず、現状を認識しましょう。その上で、どのようにすべきかを考えます。
現在の状態も分からずに対処することほど、おこがましいことはありません。さぁ、我が家の Webサーバ周りはどうなっているでしょうか。

BEFORE:Webサーバの構成
BEFORE:Webサーバの構成
[I]Private IPアドレスは説明ように別のものを割り当てています
こんな感じです。

よくよく考えたら、munin や zabbixも別のサーバとして構成していたので、外からはアクセスできない状況でした。これはいかん。
仮想化が簡単に利用できるようになればなるほど、こうやって、サーバーノードは増えていく傾向にありますね。

現状の構成をまとめると、次のようになっています。

  • FireWallにてNATをかけて、1台のApache Webサーバのみを公開している
  • Apache では仮想ホスト(vhost)を利用している
  • munin,zabbix,RedMineは異なるサーバで実行されている
  • 外部向けGlobal IPアドレスは一つしか無い

2.なにを実現したいか

次、これらをどうしたいか。です。
要求事項を列挙してみましょう。

  • 現状のApache Webサーバと同じように、munin、zabbix、RedMineへ仮想ホスト名を与えて、その仮想ホスト名で Internet(外側)からもアクセスしたい
  • Internet/Intranet(My Home)いずれも、同じURLでアクセスしたい

単純明確です。

3.どのように実現するか

では、どのように実装すれば良いのでしょうか。
FireWall では Layer-4までの Filteringしかできないものを使っていますので、ここに頼ることはできません。
そのため、Webサーバの前に Reverse PROXYをおく方法が妥当と判断しました。これは、LVS などで LoadBalancer を置くことでも対処できるでしょう。
なぜ、今回 PROXYを採用したかというと、1)キャッシュ 2)アクセス制御、への対応が柔軟・簡単だと判断しました。PROXY は元々キャッシングのためにあるようなものですから、キャッシング機能は十分です。
アクセス制御機能に関しても、URL など Layer7での制御可能なものを考えると、PROXYサーバのほうが柔軟・お手軽ではないでしょうか。
とは言え、まずはキャッシュやアクセス制御のことも忘れて、Reverse PROXY にて実装する方向で考えます。

3-1.Reverse PROXY構成を考える

Reverse PROXYは”squid : Optimising Web Delivery“さんを採用します。
Apache の mod-proxy なども採用実績は高いですが、仮想ホストが沢山増えてきた場合に、いちいち構成しないといけなさそうだった mod-proxy がちょっとめんどうに見えたので、squid さんを採用することにしました。負荷分散や、外部の機能連携などもあり、認証機能との連携豊富さにも悶えましたし。

では、squid を挟んでみると、どのような構成になるでしょうか。
こうなりました。

AFTER : SQUID+Webサーバの構成
AFTER : SQUID+Webサーバの構成

各Webサーバは、Internetからのアクセスの際に、必ず squid を経由するルートを通るようにしました。
Transparent Proxy + Reverse と言う構成にもちょっと悶えたのですが、ネットワークセグメントの作り直しなどがめんどうだったので、同じセグメントにsquidを配置する方法としました。
セキュリティも考慮すると、squid を専用の DMZ(今時言わないか)のセグメントにおいて、他のサーバは、一段後ろへ持っていくことが常套でしょう。ゆくゆくはそうしていきたいです。

対応は大きく三つ

  1. squid:Reverse PROXYサーバを準備する
  2. Internet/Intranet(My Home)の端末とでは、同じドメイン名で異なるIPアドレスを返すようにする
  3. FireWall:NATの宛先をWebサーバから、squidへ変更する

3-2.squid:Reverse PROXY構成

squid での実現方法について説明します。
今回は、いつものように debian wheezy で、squid3 (squid 3.1.20) を利用します。

まずはsquidをインストールしましょう。aptitude にお任せです。

1
# sudo aptitude install squid3

次に、/etc/squid3/squid.conf を修正します。今回の構成での変更点は次のようになります。

3-2-1. acl の設定

aclを追加しましょう。
各サーバへのドメイン名の定義になります。

1
2
3
4
acl oshiire_server dstdomain oshiire.to
acl redmine_server dstdomain redmine.oshiire.to xxxx.oshiire.to
acl zabbix_server dstdomain zabbix.oshiire.to xxxx.oshiire.to
acl munin_server dstdomain munin.oshiire.to xxxx.oshiire.to
oshiire_server
元々 apache webサーバとして、全体に公開していたものです。標準のドメイン名となる “oshiire.to” が与えられています。
redmine_server
redmineサーバのドメインを指定しています。一応、localで割り当てている個別のホスト名も追加して入れていますが、なくても平気のはずです。
※ xxxx は固有のホスト名になっています
zabbix_server
同じく zabbixサーバのドメインを指定しています。
munin_server
これも同じです。構成が同じであれば、特にここでの設定は、他のサーバと変わりはありません

3-2-2. Reverse PROXYの構成にする

アクセスされるポート番号と、Reverse PROXY である構成を実現します。

1
2
http_access allow all
http_port 80 accel vhost
http_access allow all
http_access deny all の前に置くことが精神的にも良いとされています。
どこからのアクセスでも、許可する設定です。これがないと、Internet からのアクセスは全て denyされます。
http_port 80 accel vhost
Reverse PROXY であることなどを宣言するのが、この行です。
80 … tcp port:80 で起動することを宣言しています。NATをかけるので、80でなくても好きなもので良いのですが、今回、FireWall での宛先だけを変更して、ルールを追加せずに対応するために 80にしておきました。好きなポートを使ってください。
accel … アクセラレータモードをONです。vhost を利用するために必要です。
vhost … 仮想ホストを利用してアクセスさせることを宣言しています。背後の Apacheで仮想ホストを利用している場合には必須となります。

まだあります。
ホスト名とサーバの割当と、ドメイン名の割当です。

1
2
3
4
5
6
7
8
9
cache_peer 172.16.10.14 parent 80 0 no-query originserver name=redmine_server login=PASS
cache_peer 172.16.10.13 parent 80 0 no-query originserver name=zabbix_server login=PASS
cache_peer 172.16.10.12 parent 80 0 no-query originserver name=munin_server login=PASS
cache_peer 172.16.10.11 parent 80 0 no-query originserver name=oshiire_server login=PASS
 
cache_peer_domain redmine_server redmine.oshiire.to xxxx.oshiire.to
cache_peer_domain zabbix_server zabbix.oshiire.to xxxx.oshiire.to
cache_peer_domain munin_server munin.oshiire.to xxxx.oshiire.to
cache_peer_domain oshiire_server .oshiire.to
cache_peer hostname type http-port icp-port [options]
背後のサーバを指定します。
hostname … 対象となるサーバのアドレス(ホスト名)を指定します。
type … ‘parent’は、対象が「親」であることを示しています。宛先の役割を示します。主従関係を示すわけです。
http-port … 宛先のポート番号です。今回はすべてのWebサーバがポートを変えていないので、全て80です
icp-port … 宛先で ICPがサポートされていない場合は ‘0’ です。’0’=disable らしいです。おまじないだと思ってつけておいてください。
[options] … Reverse PROXYとして重要な成分が、ここに集約されています。今回設定しているものをご紹介します

  • no-query : ICPクエリを発行しないよ、と言う宣言です。これもおまじない扱いで良いです。
  • originserver : これも Reverse PROXY構成ではおまじないですが、Parent 指定しているとき、相手先が Webサーバですよ、と言う宣言です。これぞ、Reverse PROXYの宣言
  • name= : ここにaclを指定します。どのホストへの宛先か、と言うのをここで割り当てます
  • login=PASS : Authorization ヘッダ利用時にはこれが必要です。認証情報をそのまま引き継ぐよという指定みたいですが、今回、RedMine ではiPhoneアプリからのアクセスをさせたく、その場合に REST APIを利用するのですが、その場合には、このオプションが必須です。これがないと、REST 使えません
    ※ 参考 : “Azure | myownwords
cache_peer_domain cache-host domain [domain …]
指定したドメインのアクセスを制御します
cache_peer と対になって利用する形になります。俄然、よく分かってません
cache-host … cache_peer で指定した相手先を指定するのですが、name=の先のaclを指定するようです。
domain … その相手先にアクセス可能なドメイン名を指定します。”.oshiire.to” とすると、サブドメインも全て含む、と言う設定になります。従って、redmine.oshiire.to=>redmine_server、munin.oshiire.to=>munin_server となり、その他の yyyy.oshiire.to や、zzzz.oshiire.to などは oshiire_server へと割り当てられるようです

3-2-3.Internet/Intranet(My Home)の端末とでは、同じドメイン名で異なるIPアドレスを返すようにする

例えばこのような感じにします。

名前解決の結果
名前解決の結果

今回、squid では宛先をIPアドレスで指定していますが、ホスト名にしておくと、もっと優雅に設定できそうです。

bind であれば、viewを利用すれば良いですし、nsd を使う場合は、外部用と内部用の 2つのサーバを動かす必要があります。

そもそも、このようなタイプではなく、”My Home”内のホスト名は、すべて squid宛として “172.16.10.10”を返すようにして、内部のアクセスも PROXY経由にすることができそうです。
今回は、外部のアクセスのみを squidのアクセスへ記録できるように、分離ができると考えてこのような構成にしています。

3-2-4.FireWall:NATの宛先をWebサーバから、squidへ変更する

最後に、FireWallの NAT宛先を squid宛へ変更したら完成です。
ここは各自でお持ちのマニュアルを参考にしましょう。

4.おまけ

Reverse PROXY化によって、影響のあるものへの対処をいくつか。

4-1.WordPress のIP取得

Reverse PROXY背後になるコトによって、各Webサーバの access.logでは、アクセス元が全て squidサーバのアドレスになります。
WordPress も例外ではなく、ここでなにもしないと、アクセス解析系が全滅です。

そこで、/etc/squid3/squid.conf と [wordpress directory]/wp-config.php に次の行を追加しましょう。

/etc/squid3/squid.conf

1
follow_x_forwarded_for allow all

[wordpress directory]/wp-config.php

1
2
$_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];

※ 参考 : “リバースプロキシ配下のWordPress » ねころくぶろぐ

4-2.munin で監視する

squid もめでたく、munin 様で監視できます。

次のコマンドを実行しましょう。

1
# sudo ln -s /usr/share/munin/plugins/squid_* /etc/munin/plugins/

次のような symbolic link ができてれば成功です。

1
2
3
4
5
/etc/munin/plugins/squid_cache -> /usr/share/munin/plugins/squid_cache
/etc/munin/plugins/squid_icp -> /usr/share/munin/plugins/squid_icp
/etc/munin/plugins/squid_objectsize -> /usr/share/munin/plugins/squid_objectsize
/etc/munin/plugins/squid_requests -> /usr/share/munin/plugins/squid_requests
/etc/munin/plugins/squid_traffic -> /usr/share/munin/plugins/squid_traffic

munin-node の構成ファイルの修正も必要になるかも知れません。

次のファイルに、以下の行を追加して、必要な項目のみ有効化しましょう。サンプルですので、今回の構成であれば、”env.squidport 80″ のみでいけます。
/etc/munin/plugin-conf.d/munin-node

1
2
3
4
5
6
7
8
9
[squid_*]
# squidhost   - host (default "localhost")
# squidport   - port (default "3128")
# squiduser   - username (default "")
# squidpasswd - password (default "")
env.squidhost localhost
env.squidport 80
env.squiduser admin
env.squidpasswd p@ssw0rd

4-3.muninに認証をつけよう

muninやzabbixなどが、外からアクセスできるようになってしまいますので、認証をつけておきましょう。
zabbixやredmineはユーザ認証機能を持っているので、そのままでもある意味問題ありませんが、munin は URLばれると、アクセスし放題です。見られ放題です。ドMならそのままで、多少なりとも恥じらいとセキュリティの意識があれば、少なくともBASIC認証程度はつけておきましょう。

muninの鯖で設定が必要です。

debian Wheezyの場合です。次のコマンドでパスワードを作りましょう。usernameはお好みで好きなものでどうぞ。

1
# sudo htpasswd -c /etc/munin/munin-htpasswd username

次は、apache の munin用設定ファイルの修正です。
/etc/apache2/conf.d/munin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<directory /var/cache/munin/www>
        Order allow,deny
        Allow from localhost xxx.xxx.xxx.0/24
        Options None
 
        # This file can be used as a .htaccess file, or a part of your apache
        # config file.
        #
        # For the .htaccess file option to work the munin www directory
        # (/var/cache/munin/www) must have "AllowOverride all" or something
        # close to that set.
        #
 
        AuthUserFile /etc/munin/munin-htpasswd
        AuthName "Munin"
        AuthType Basic
        require valid-user
 
        # This next part requires mod_expires to be enabled.
        #
 
        # Set the default expiration time for files to 5 minutes 10 seconds from
        # their creation (modification) time.  There are probably new files by
        # that time.
        #
 
    <ifModule mod_expires.c>
        ExpiresActive On
        ExpiresDefault M310
    </ifModule>
 
</directory>

どこよ(‘A`)という感じなので、ココです。この 4行を有効化してください。

1
2
3
4
        AuthUserFile /etc/munin/munin-htpasswd
        AuthName "Munin"
        AuthType Basic
        require valid-user

ついてる ‘#’ を外せってことですね。さぁ、あとは次のコマンドで、apache2 再起動でどうぞ。

1
# sudo service apache2 restart

[tmkm-amazon]1849513902[/tmkm-amazon]

References

References
I Private IPアドレスは説明ように別のものを割り当てています

“[squid] 1つのGlobal IPで複数のWebサーバを公開する方法 [debian]” への3件の返信

  1. 内部では論理的に別のIPアドレスで、複数のWEBサーバを立ち上げているので、それらへ振り分けるためです。

    1台の WEBサーバ上に、複数ドメインを共有するのであれば、VirtualHost も勿論使えますし、実際に我が家でも使っています。
    ただ、今回は WEBサーバを分けざるをえない状況になったため、このような方式をとっています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください