自宅のルータがヘアピンNATに対応していない問題に対応した際のメモ。

ヘアピンNATとは、内部ネットワークから公開されている自分の外部IPアドレス(例: サーバ)にアクセスする際に、リクエストをルータが受け取り、適切に内部ネットワークの該当デバイスに転送する機能を指します。

この機能がないと、ローカルネットワーク内のPCやスマートフォンは、同じローカルネットワーク内にあるサーバに、サーバの公開ドメイン名を使用してアクセスすることができません。

例えば、 example.com というドメイン名で公開している自宅のサーバに、家の中からアクセスしたい場合、通常のルータ設定だとこのサーバにアクセスできません。

これを解消するためには、ローカル環境のみで、公開しているドメインのIPアドレスを、ローカルIPアドレスとして解決するDNSサーバを構築する必要があります。 この記事では、その方法をご紹介します。

dnsmasqの設定

今回はDockerコンテナで dnsmasq を動かすことにします。
dnsmasqの設定ファイルである dnsmasq.conf を作成します。

dnsmasq.conf の例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# FQDNではない、ローカルなホスト名を上流に転送しない
domain-needed

# IPアドレス範囲に対する逆引きクエリを上流に転送しない
bogus-priv

# 上流のDNSサーバのアドレスを見つけるために使用するresolv.confファイルの指定
resolv-file=/etc/dnsmasq_resolv.conf

# 各種ドメインに対してローカルIPアドレスを返す定義。適宜追加する
address=/foo.example.com/192.168.0.2
address=/bar.example.com/192.168.0.2

Dockerfileの作成

Dockerfile を作成します。
Alpine LinuxベースでDockerイメージを使用して dnsmasq をインストールし、前述の設定ファイルをコピーしています。

1
2
3
4
5
6
7
FROM alpine:3.18

RUN apk --no-cache add dnsmasq
RUN echo nameserver 1.1.1.1 > /etc/dnsmasq_resolv.conf
COPY dnsmasq.conf /etc/dnsmasq.conf

CMD ["dnsmasq", "-k"]

Docker イメージのビルド

上記の Dockerfile を用いてDockerイメージをビルドします。
mydns という名前でイメージをビルドしています。

1
docker build -t mydns .

Docker コンテナの起動

イメージがビルドされたら、それを使用してコンテナを起動します。
DNSサービスは53番ポートで動作するため、ホストの53番ポートをコンテナの53番ポートにマッピングします。

1
docker run -d -p 53:53/udp --name mydns_container mydns

-d: バックグラウンドでコンテナを実行します。
-p 53:53/udp: UDPの53番ポートをホストとコンテナでマッピングします。
--name mydns_container: コンテナに mydns_container という名前をつけます。

動作確認

DNSサーバが正しく動作しているかを確認するために、dig コマンドを使用します。

1
dig @127.0.0.1 foo.example.com

出力結果の中で、以下のような部分が表示されることを確認します。

1
2
;; ANSWER SECTION:
foo.example.com.   IN   A   192.168.0.2

以上で、Docker上にDNSサーバの構築は完了です。 DockerサーバのIPアドレスをクライアントのDNSサーバに設定することで、ローカルDNSサーバを使用することができます。