2017/05/25(Thu)外部公開しているサーバに対して、LAN内からドメイン指定でアクセスする様々な方法

自宅ネットワークにおいて、インターネット接続を共有する形でサーバを公開すると、自分だけハマる問題がある。それは「LAN内からサーバへのドメインアクセスができない」ことだ。
内部から自宅サーバのドメインに設定したグローバルアドレスでアクセスすると、ルータを経由するところでルータが「自身についてるアドレスが宛先だな」と判断し、そのままルータの管理画面が開いてしまうという現象が起こる。

既にいろんなサイトで現象や対策法が紹介されており、このような現象が起こらないルータもあるが、そういった機器交換を行うのだけでなく、いくつかやりようがあると思ったので、順に紹介してみる。

hostsに定義する

設定自体で一番単純なのがコレ。自分のLANだけの問題なので、殆どのOSが持っているであろうローカルHOSTSファイルに自ドメインとローカルアドレスとの対応付けを書いてしまう、というやり方。
Unix系ならば/etc/hosts、WindowsならばC:\Windows\System32\drivers\etc\hostsあたりに
192.168.11.10     aaaa.kerosoft.com aaaa
192.168.11.20     bbbb.kerosoft.com bbbb
のように書く。ホスト名の部分はスペース区切りでいくつでも記載できるので、FQDN(完全修飾ドメイン名)とホスト名の両方を書いておくと便利。

メリット

  • 設定が簡単

デメリット

  • LAN内の機器が多いと時間がかかる
  • 自宅サーバのLAN内アドレスが変わったとき、新しいドメインが増えたとき、新しくOSをインストールした時など、各システムに対して修正する必要がある
  • 管理者権限が必要(PCなら問題無いことが多いが、root権限が制限されているスマートフォン・タブレット端末や、他人が管理するPCがあると困る)
  • 設定した端末を、LAN外に持ち出すとアクセスできない(例えばノートPCを出先に持って行く状況)

内部向けDNSサーバを構築する

次点でお手軽なのがコレ。自分のLAN向けにローカルアドレスを返すDNSサーバを立ててしまうこと。
既に動いている自宅サーバ上でパッケージを追加するだけでよく、後はLAN内で使用する端末へ配信するDHCPサーバの設定で、DNSサーバアドレスをそこに向けてやればよい。インターネット側から到達できる必要は無いので、グローバルアドレスを固定IP環境下で運用する必要も無い。

これを実現するためのDNSサーバ実装はいくつかあるが、オススメなのはdnsmasqを使う方法。dnsmasqは、キャッシュサーバとして動作し、予め定義しておいたドメインだけ応答をoverrideするような挙動が簡単にできる。

Fedoraの場合だと、
# dnf install dnsmasq
でインストール後、/etc/dnsmasq.confを以下のようにして、
conf-dir=/etc/dnsmasq.d,.rpmnew,.rpmsave,.rpmorig
bind-dynamic
interface=eth0
/etc/dnsmasq.d/lan.conf(名前は好きにしてよい)に
address=/aaaa.kerosoft.com/192.168.11.10
address=/bbbb.kerosoft.com/192.168.11.20
のように書く。あとは、udp/53とtcp/53をポート開放し、
# systemctl start dnsmasq
# systemctl enable dnsmasq
でdnsmasqを起動、次回からも自動起動にして完了。
通常はdnsmasqがアドレス解決を行い、/etc/resolv.d/内のファイルに書かれた"address="に該当するものがあれば、それで上書きした応答を返す。

メリット

  • 設定はまあまあ簡単である
  • 端末の台数に依らず設定を一元管理でき、ほぼ全ての端末(DHCPでアドレスを取得するもの)に設定を適用出来る

デメリット

  • 自宅サーバでDNS権威サーバを運用していると厄介(bindのviewを使って、外部向けと内部向けにゾーンを定義し、リクエスト元に応じて違う結果を返すような運用は可能だが、ゾーンファイルが2重管理になってしまう。nsupdateでゾーン内のIPアドレスが動的に更新される場合などは面倒。)
  • LAN内の端末が、DHCPで配布されていないDNSサーバを参照する設定になっていると機能しない

自宅サーバ自体をルータにする

だんだん話が大きくなってきたが、原因の根本は「グローバルアドレスをルータが持っている」ことなので、「ルータ=サーバ」であれば話は早い。内部からグローバルアドレスでアクセスしても、自分がサーバであれば目的の物が開ける、ということである。

自分も長らくこの方式を使っていた。というのは、Gigabitに対応していて色々弄れるルータが高価だったからというのと、Linuxサーバをルータとして機能させても高速で安定した通信ができたからだ。*1
Fedoraの場合は、こんな感じで設定。
# dnf install rp-pppoe

# pppoe-setup
xxx@example.com  (PPPoEのユーザ名)
eth1             (ONUが繋がっているインターフェース名)
no               (常時接続)
server           (ISPのDNSアドレスを使用する)
xxxxxxx          (PPPoEのパスワード)
no               (ユーザに接続を管理させない)
0                (ファイアウォールは別途設定する)
yes              (起動時に接続)
y                (設定を確認)

# vim /etc/sysconfig/network-scripts/ifcfg-ppp0
元々ある設定に以下を追加
PPPOE_TIMEOUT=0
LINUX_PLUGIN=/usr/lib64/pppd/2.4.7/rp-pppoe.so
MTU=1454

# pppoe-start
rp-pppoe.soの場所は、アーキテクチャによって/usr/libの下にあったり、pppdのバージョン番号が違ったりするので適宜読み替えを。できる限りkernel mode driveを利用しないと、kernel<->userland間のやりとりが多くなって通信速度の低下を招く恐れがあるため。
MTUは、自分のネットワークに合ったものを設定のこと。

それから別途、dhcpdを稼働させてLAN内にローカルIPアドレスを配布する必要がある。DNSキャッシュサーバを構築するかはどちらでもよい。

メリット

  • クライアントに設定させる項目が何も無い(そもそもルータの管理画面が見えるという問題が起こらない)
  • ルータを別途用意・稼働する必要が無く、自宅サーバ一台で全てまとまる
  • 自宅サーバでのDNS権威サーバ提供と併用できる

デメリット

  • 自宅サーバでpppoeとdhcpdの設定が必要
  • サーバのメンテナンス時に、LAN内全てのインターネット接続性が失われる
  • サーバをグローバルに直接配置するので、ファイアウォールの適切な設定が必須となる
  • ハードウェア処理が必要なレベルの高負荷通信がある場合にパフォーマンスが出ない

*1 : 少なくともOSやプロセスがクラッシュしてインターネットが落ちた事は無いし、事業者側のメンテナンスでPPPoEセッションが切れても自動復活していた

IPv6ネットワークを構築する

こういう解法もあるのでは、ということで紹介。最近ではモバイル端末を含めIPv6 readyなものが増えてきているので、思い切って(フレッツ網以外の)IPv6ネットワークを開通させてしまう。ISPからIPv6用のPPPoEサービスが提供されていたり、IPoEにより配布されているものもあるので、そこまで敷居は高くないはずだ。そのようなサービスの提供が無い場合、Hurricane Electric(HE)のFree IPv6 Tunnel Brokerを利用すればIPv6アドレスを/48でトンネルしてもらうことが出来る。(ISPから割り当てられるグローバルIPv4アドレスが変動する場合、トンネルアドレスを更新する処理をサーバで定期実行する必要あり)

上記の方法でIPv6アドレスを振り、next hop経路を::/0に設定したら、あとは自ドメインのDNSのAAAAレコードにアドレスを記載するだけ。

フレッツ網でないIPv6ネットワークは、殆どの場合インターネットへの接続性もあり、通常IPv4よりもIPv6を優先してアクセスする設定となっている機器が多いので、単にアドレスを配ってやれば問題が解消するという寸法だ。

メリット

  • クライアントに設定させる項目が何も無い
  • 自宅サーバをIPv6 readyにできる
  • 同時にLAN内もIPv6 readyにできる(自宅サーバやルータでトンネルを行う場合は、別途RAの送信が必要)

デメリット

  • IPv6に非対応の機器、IPv6よりIPv4を優先する機器には効果が無い*2
  • ルータがIPv6 PPPoEに対応していること、あるいはサーバからHEにトンネルを張るなどの諸準備が必要

*2 : モバイル端末でもキャリアの設定などによってこうなっていたことがある

ルータにHairpin NAT(NAT Loopback, NAT reflection)を設定する

最後にこれ。上記の中で確実かつ、自宅サーバでDNS権威サーバを提供していても問題が無いパターン。ただし、ルータがHairpin NATあるいはNAT Loopback, NAT reflectionと呼ばれる機能に対応している必要がある。

これはつまり、ルータがルーティングする際に「LAN内から自分のグローバルアドレス向けの通信」を内部のサーバ宛にねじ曲げてしまうNAT設定のことである。ただ一方向のアドレス変換をすればよいのではなく、戻りのパケット(サーバ→LAN内の機器)の面倒も見る必要があるため、インターネット用のNAT処理(アクセスのアドレスをローカル機器のアドレスからグローバルアドレスへ変換し、応答をローカルアドレスをdestにして戻す)とは別のNATを行う(アクセスのアドレスをグローバルアドレスから自宅サーバのローカルアドレスに変換し、応答をグローバルアドレスをsrcに戻す)必要があることになる。

メリット

  • クライアントに設定させる項目が何も無い
  • クライアントがどのDNSサーバを使っていても、確実に動作する
  • 自宅サーバをメンテナンスしていても、インターネット接続性が失われない

デメリット

  • NAT Hairpinに対応したルータを使用する必要がある(少ない)
  • ルータ上での作り込みや設定次第だが、グローバルアドレスが固定IPでなければいけないこともある
  • 設定がややこしい
EdgeRouter X (ER-X)に乗り換えてからは、ルータ≠自宅サーバとなってしまったので、現在Hairpin NAT機能を使っている。その設定方法については、こちらで記述。
hairpin-nat.png

設定例

参考文献

linux - Accessing the DNAT'ted webserver from inside the LAN - Server Fault