【ヘアピンNATができない!】LANからだとアクセスできない問題を解決する。【ローカルDNS】
前置き
この記事が対象の人
- 自宅サーバーでサービスを運用する人
- VirtualHostを使う人
- WAN側と同じIPやドメインでLANからアクセスする人
LANからアクセスできねぇ!
ノリで自宅サーバーを構築して、一部の人が最初の方にぶち当たる問題が 「外部からアクセスできるのにLANからアクセスできねぇ!!!」 という問題。WebサーバーでVirtualHostを使ってたりするとプライベートIPでアクセスできないので、今回はこの問題を解決していきます。
なぜ起きちゃう?
問題は、ルーターにあります。ここで重要になるのが ヘアピンNAT (NATループバック)。これは、LAN内の機器にグローバルIPでアクセスできるようにするスグレモノ。
これにルーターが対応していないと、LAN内からはグローバルIPで直接アクセスできないのです。
(メーカーも公表してないっぽいから気づくのさえ難しい...)
詳しい説明はこちらから。
解決方法
方法は3つあります。
-
外部のプロキシサーバーを経由する
(自分がVPNを使ったり、アクセスをCloudflare経由にする)(簡単だけどスピートが落ちます) -
hostsファイルを編集する
(一番手軽だけど、外出時等にネット環境が変わると都度書き換える必要があります。) -
ローカルDNSを構築する
(一番シームレス(だと思う)、だが初期設定がめんどくさい)
自分に合う方法を選びましょう。今回は3個目の方法でやっていきます。
実際にやっていく
環境
今回の環境です。
- サーバーOS: Ubuntu 22.04 LTS
- クライアントOS: Windows 11 22H2
※ ウェブサーバーとDNSサーバーは同じPCに存在する
※ サーバーのプライベートIPアドレスは192.168.3.2
サーバー側の操作
インストール
最初に、一応パッケージの更新をしましょう。
sudo apt-get update
sudo apt-get upgrade
次に、DNSのソフトウェア、BIND9をインストールします。ついでにカレントディレクトリも変えちゃいましょう。
sudo apt install bind9 bind9-utils
cd /etc/bind
設定ファイルの編集
LAN内からDNSが利用できるようにします。
sudo nano named.conf.options
//緑の部分を追加してください。
//ここでLAN内のネットワークを定義します。
+acl local-area-network {
+ 192.168.3.0/24;
+};
options {
directory "/var/cache/bind";
// If there is a firewall between you and nameservers you want
// to talk to, you may need to fix the firewall to allow multiple
// ports to talk. See http://www.kb.cert.org/vuls/id/800113
// If your ISP provided one or more IP addresses for stable
// nameservers, you probably want to use them as forwarders.
// Uncomment the following block, and insert the addresses replacing
// the all-0's placeholder.
// forwarders {
// 0.0.0.0;
// };
//ここで、DNSの処理を受け付けるアクセス元を定義します。
+ allow-query {
+ localhost;
+ local-area-network;
+ };
//ここで、サーバーで定義されないドメインやIPを他のDNSに問い合わせるようにします。
+ recursion yes;
//========================================================================
// If BIND logs error messages about the root key being expired,
// you will need to update your keys. See https://www.isc.org/bind-keys
//========================================================================
dnssec-validation auto;
listen-on-v6 { any; };
};
ドメインと設定ファイルの定義
ドメインを定義するファイルを作成します。
sudo nano named.conf.my-zones
named.conf.my-zones の部分は自分に分かりやすい名前でどうぞ!
//一応ネームサーバーのドメインを設定します。
//my-server.dnsの部分は使いたいものにしてください。
zone "my-server.dns" IN {
type master; //マスタサーバーになります。
file "/etc/bind/my-server.dns.zone"; //DNSを設定するファイルです。
};
//ここからアクセスしたいドメインを入れます。
//example-my-service.comの部分は自分のFQDN(ドメイン)を入れてください。
zone "example-my-service.com" IN{
type master;
file "/etc/bind/example-web-service.com.zone";
}
DNSレコードの設定
先程定義したドメインのそれぞれについて、DNSレコードを設定していきます。
DNS
sudo nano my-server.dns.zone
$TTL 86400
@ IN SOA ns.my-server.dns. support.my-server.dns. (
; INはLANを含むインターネット。
; SOAは管理情報のこと。
; ns.my-server.dnsの部分は使用するネームサーバー。
; support.myserver.dnsの部分は担当者のメール。@は.になります。
; (メールは存在する必要はない)(多分)
20231118 ;Serial シリアル番号です。変更したら増やします。(日付が便利)
3600 ;Refresh 指定した秒数ごとにDNSの情報を再取得します。
1800 ;Retry Refreshで失敗したときにここの秒数後に再試行します。
604800 ;Expire 情報を取得できないときにセカンダリNSの情報が使える期間
865400 ;Minimum TTL ネガティブキャッシュを保持する期間
)
@ IN NS ns.my-server.dns. ;使用するネームサーバー。ns.my-server.dns とします。
ns IN A 192.168.3.2 ;ns.my-server.dnsのAレコード。サーバーのアドレスを入れます。
アクセスするドメイン
sudo nano example-my-service.com.zone
; ←このファイルはこれがコメントアウトになります
$TTL 86400
@ IN SOA ns.my-server.dns. support.my-server.dns. (
20231118
3600
1800
604800
865400
)
@ IN NS ns.my-server.dns. ;上もだけど、最後の「.」を忘れずに!
@ IN A 192.168.3.2 ;Webサーバーが置いてあるアドレス。
最後の仕上げ
最後に、大元の設定ファイルを編集します。
sudo nano named.conf
// This is the primary configuration file for the BIND DNS server named.
//
// Please read /usr/share/doc/bind9/README.Debian.gz for information on the
// structure of BIND configuration files in Debian, *BEFORE* you customize
// this configuration file.
//
// If you are just adding zones, please do that in /etc/bind/named.conf.local
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.default-zones";
//これを追加してください(named.conf.my-zonesは自分のファイル名)
+include "/etc/bind/named.conf.my-zones";
確認作業
構文にミスが無いか確認しましょう。
sudo named-checkzone my-server.dns /etc/bind/my-server.dns.zone
zone my-server.dns/IN: loaded serial 20231118
OK
sudo named-checkzone example-my-service.com /etc/bind/example-my-service.com.zone
zone example-my-service.com/IN: loaded serial 20231118
OK
どちらとも最後にOKと出れば問題ありません。
サービスのリロード
変更内容を適用し、起動時にも働くようにします。
sudo systemctl reload named
sudo systemctl enable named
LANにポート開放
ufwを利用してUDPの53番ポートを開放します。
sudo ufw allow 53/udp
sudo ufw reload
DNSが働いているか確認
nslookupで確認します。
nslookup google.com 192.168.3.2 //DNSサーバーのアドレス
ついでに登録したドメインも確認します。
nslookup example-my-service.com 192.168.3.2 //DNSサーバーのアドレス
Name: example-web-service.com
Address: 192.168.3.2 //WebサーバーのプライベートIPアドレス
こうなれば成功です。
クライアント側の操作
DNSサーバーを設定するだけです。
設定 → ネットワークとインターネット → イーサネット → 編集
このようにしてください。192.168.3.2の部分は自分のDNSサーバーのIPに変えましょう
(有線接続の場合です。)
あとはドメインにアクセスするだけです。
おめでとうございます。お疲れ様でした。
おわりに
注意
私はいわゆるアマチュアです。色々調べてますが、間違っていることがあると思いますので、そこだけ気をつけてください。何かサーバーに不具合が生じても責任は取れませんよ?言いましたからね?
指摘はどんどんお寄せください。
以下の記事を参考にしました。
本当にどうでもいい蛇足
先日電車に乗っていたところ、ある年配の方に話しかけられた。しばらく話してると学校の話になり、「私が小さかったころは学校なんてものは無かったんですよ」と仰られた。戦中、もしくは戦後の混乱で教育が受けたくても受けられない環境だったのかと戦争の悲惨さを感じながら、年齢を問うと、意外にも戦後約10年後の生まれであった。私の親族にその年齢に近い方が居るが、普通に学校があり、青春を謳歌していた。と考えれば、この人は別の地球から飛ばされて来たのではないかと思ってしまう。しばらくして、周辺の地理の話になった。「何処其処に川があった」など色々な話をするが、微妙に地理情報が異なっていた。なぜだろうか。最終的に同じ駅で降り、彼は赤信号を渡っていった。私が「危ないですよ!」と叫ぶと、「私はまだ若いから大丈夫」と笑顔で返してきた。(いやダメだろ)
プログラムを書くときに予想外な展開が起きることがあるが、現実でも起きるものであると認識させられてしまった...どちらも気をつけていきたいものだ。(?)
Discussion