【mod_proxy】Dynmapをhttpsで見る


やりたいこと

タイトル通り、Dynmapをhttpsで見たい。

前提

DynmapはMinecraftのサーバプラグインで、ゲームの内部状況をブラウザから確認できるようになる、人気のプラグインです。

【Dynmap】Overview

普通に実装するなら、ポート周りはこんな感じになります。

ソフトウェア ポート番号 通信プロトコル
Apache 80, 443 http, https
Minecraft server 25565 独自プロトコル
Dynmap 8123 http

大雑把な図ですが、おおよそこのような関係になります。ポート番号はデフォルト値です。

問題はDynmapです。Dynmapは内部にスタンドアローンなWebサーバを内蔵していますが、Apacheとの競合を防ぐため、8123番ポートを利用します。そのため、サーバは80, 443, 25565の他に8123番ポートも開放しなければなりません。

他のポートは開放する他ありませんが、Dynmapのポートは開放したくありません。
もっといえば、httpsで通信したいです。

さて、どうしましょう。

リバースプロキシ(Reverse Proxy)を使う

リバースプロキシを使うことで解決できます。
リバースプロキシとは、外部ネットワークの接続に対し、何らかの処理を行い、内部サーバに引き渡す、いわば中継機能を果たす機器のことです。

とても分かりやすい図があったので、お借りしました。


【ITSakura】プロキシサーバとリバースプロキシサーバの違い

リバースプロキシが外部の受付役となっていることが分かりますね。今回、ハード的にサーバは1つですが、やることは同じです。
Apacheに対するリクエストはApacheに、Dynmapに対するリクエストはDynmapにそれぞれ内部で振り分けることで、開放ポートを減らすことができます。

リバースプロキシ適用

リバースプロキシを使った図が以下になります。(8123番ポートはイメージです)

リバースプロキシはApacheに備わっている機能なので、リバースプロキシはApache内部にあります。
リバースプロキシが受け取ったリクエストのうち、Dynmapに関するものだけ8123番ポートに向けて、リクエストを送ります。
Dynmapの応答はリバースプロキシを通じて、外部に送信されます。

このように、リバースプロキシを使うと内部サーバを隠蔽し、無用なポート開放を防ぐことができます。

リバースプロキシの実装

Apacheであれば、mod_proxyを使って簡単に実装できます。
今回はhttpsの通信に対して実装するので、VirtualHostを使います。(https化はすでにされているものとします)

ssl.conf
...
# スラッシュ補完(後述)
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_URI} /dynmap$
RewriteRule /* %{REQUEST_URI}/ [R=301,L]
</IfModule>

# リバースプロキシ
<VirtualHost *:443>
ServerName sample.com:443
<IfModule mod_proxy.c>
  ProxyRequests Off
  ProxyPass /dynmap http://localhost:8123
</IfModule>
...
</VirtualHost>

ProxyRequestsはフォワードプロキシをオンにするかどうかの記述なので、今回はoffにします。

ProxyPassの使い方は、

ProxyPass <外部からのリクエスト> <内部サーバ先>

です。非常にシンプルですね。
sample.com:443/dynmapへのリクエストは内部のlocalhost:8123に投げるようにしています。
これで、https://sample.com/dynmapにアクセスすると、Dynmapの画面が表示されます。

これでポートを開放をせず、外部からhttpsを使ってDynmapにアクセスすることができました。

補足:スラッシュ補完

リバースプロキシの前にmod_rewriteモジュールを使ってスラッシュ補完を行っています。
つまり、
https://sample.com/dynmaphttps://sample.com/dynmap/
に書き換えるということです。

スラッシュ補完をしないと、真っ白な画面が表示されてしまいます。
一方、https://sample.com/dynmap/https://sample.com/dynmap/#であれば、正しく表示されます。

ではなぜ、スラッシュ/を保管しなければならないのか。
これは推測なのですが、DynmapのWebサーバのルートディレクトリを明示する必要があるのでは?と考えています。

通常、ドメイン名のみでアクセスするとき、ブラウザはスラッシュを補完してサーバにリクエストを投げます。
URLバーがhttps://sample.comであっても実際はhttps:/sample.com/としてリクエストを送っているということです。
最後のスラッシュがルートを示しています。

ですが、今回の場合リバースプロキシを経由しているので、スラッシュ補完が行われません。
ディレクトリを一切指定されなかったWebサーバは、困って真っ白な画面を返したのではないでしょうか。

何か詳細あれば、教えていただきたく思います。

Minecraftサーバのポートもリバースプロキシ経由にできないのか?

ごもっともだと思います。
ですが、Minecraftが扱っているプロトコルはゲーム独自のものです。
mod_proxyモジュールでは対応できないプロトコルなので、今回の例のようにはいきません。

ですので、Dynmapのみリバースプロキシを適用することにしました。

まとめ

どうでしたか?
他のマルチサーバをのぞくと、http://xxxxxx:8123でアクセスしているものがいくつかあったので、記事にしてみました。

ポートを閉じるためにも、httpsで通信するためにも、リバースプロキシを使ってみてはいかがでしょうか。

参考リンク