OCI 上のサーバを IPv6 対応させる
自分は OCI (Oracle Cloud) に Always Free の Compute Instance (IaaS VM) を立てて利用している。今回、なんとなく IPv6 対応できるようにしとくかー、と思って、した。
IPv6 でサーバに到達する仕組み
IPv6 でクライアントとサーバが通信するに至るには、当然クライアント側で「自分、IPv6 でそっちにアクセスできます!」という準備が整っていることが前提となるが、サーバ側も「自分、IPv6 でのアクセスを受け付けられます!」というセットアップが必要になる。
クライアント側が IPv6 で通信しようとしてもサーバ側が対応していない場合は、ISP などが用意するゲートウェイにて共有 IPv4 アドレスが付与されて通信が行われる。そのため、サーバ側で X-Forwarded-For や X-Real-IP といった HTTP ヘッダを見ても、ゲートウェイの IPv4 アドレスしか分からないことになる。
サーバ側で IPv6 対応ができていて、DNS でも AAAA レコード (IPv4 アドレスを指定する A レコードのように、IPv6 アドレスを指定するためのレコード) を指定してあると、サーバへの IPv6 通信の経路が出来上がるワケだが、通信環境によっては IPv6 よりも IPv4 の方が速い場合もある。そのため、一般的なブラウザ等では Happy Eyeballs という仕組みを持っており、IPv4 での通信の方が速いと判断した場合は、IPv6 に対応した環境であっても IPv4 で通信が行われる場合もある。
IPv6 (IPoE 方式) で通信できると何が良いのかというと、従来の IPv4 (PPPoE 方式) と比べて通信が速く、混雑に左右されにくくなるという。前述のとおり、大抵の ISP なら「IPv6 でうまく通信できなさそうなら IPv4 で」というフォールバックも出来ているので、クライアント側の OS 設定で IPv6 も有効にしておいて損はないだろう。
OCI の仮想ネットワーク環境を IPv6 対応する
まずは Compute Instance の外側にある VCN (仮想ネットワーク) 周りの設定を調整して、IPv6 対応させていこう。
- VCN : IPv6 の CIDR ブロックを付与する … IPv4 に関しては
/16などで CIDR が割り当てられていると思う。コレに追加して、::/56な CIDR を自動指定できる - ルーティングテーブル :
0.0.0.0でインターネット・ゲートウェイに接続するようなルールが既にあると思うが、コレに追加して::/0でインターネット・ゲートウェイに接続するルールも追加する - サブネット :
/64になる IPv6 接頭辞を割り当てる (CIDR 指定するだけでテキトーにやってくれる) - セキュリティリスト・イングレスルール : 必要に応じて、22・80・443 ポートなどに関して
::/0からのアクセスを許可するように設定する - セキュリティリスト・エグレスルール : VCN 内から
::/0へのアクセスは全て許可するようにしておくと楽 - Compute Instance・VNIC : 自分の場合、サーバ用途のため Public IPv4 アドレスを割り当ててあるのだが、この VNIC に対して「IPv6 アドレスの割り当て」を行う。色々設定が行えるが何も指定せず自動設定に任せた。作成後、「IPv6 アドレスの予約」をしておくと IPv6 アドレスを固定できる
コレでネットワーク的には IPv6 アドレスで Compute Instance まで到達できるようになった。
Compute Instance 内の nginx で IPv6 アクセスを受け付ける
次は nginx (v1.28.0 を使用) の設定で、IPv6 でのアクセスを受け付けるようにする。最低限必要なのは server コンテキスト内の listen ディレクティブ指定。
server {
listen [::]:80 default_server; # IPv6 アクセスを許可する
listen 80 default_server;
listen [::]:443 ssl default_server; # IPv6 アクセスを許可する
listen 443 ssl default_server;
# 以下省略…
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
}
default_server の指定はよしなに。[::]:80 とか [::]:443 とかでの指定を追加する感じ。設定できたら $ nginx -t で設定ファイルの構文チェックをした後に、$ systemctl restart nginx などで nginx を再起動して設定を有効にする。
ちなみに、前述のネットワーク周りの設定が完了していれば、OCI インスタンス内で ip コマンドを叩いて自身の IPv6 アドレスが確認できるようになっているはずだ。
# IPv6 アドレスを割り当てていない状態
$ ip -6 addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 state UP qlen 1000
inet6 XXXX::XXXX:XXXX:XXXX/64 scope link
valid_lft forever preferred_lft forever
# IPv6 アドレスを割り当てた状態 (VM 自体の再起動などは必要なし)
$ ip -6 addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 state UP qlen 1000
inet6 XXXX:XXXX:XXXX:XXXX:X:XXXX:XXXX:XXXX/128 scope global dynamic noprefixroute # ← この `/128` のアドレス部分が自分の IPv6 アドレス
valid_lft 89961sec preferred_lft 86361sec
inet6 XXXX::XXXX:XXXX:XXXX/64 scope link
valid_lft forever preferred_lft forever
# IPv6 アドレス確認サービスなどに `curl` を投げてみても良いだろう
$ curl -6 https://ipv6-test.com/api/myip.php
DNS 設定で AAAA レコードを指定する
自分は Cloudflare で DNS 設定を行っているのだが、どの DNS サービスでも同じように指定すれば良い。A レコードで IPv4 アドレスを指定していると思うが、コレと同等のことを AAAA レコードという形で、IPv6 アドレスを指定するようにすればいい。
Cloudflare の場合、オレンジ色の雲アイコンで表現される「Proxied プロキシ済み」に設定してしまうと、Cloudflare のサーバを経由するようになってしまう点に注意。VM 内で Let's Encrypt などを使用して証明書を発行しており、nginx で SSL 証明書を設定しているような場合、その前に Cloudflare 側で SSL 証明書をチェックしようとしてしまうためおかしくなってしまう。Cloudflare の CDN キャッシュを使用しているなど、意図的に Cloudflare を使用している場合を除いて、基本的には灰色の雲アイコンで表示される「DNS Only DNS のみ」(プロキシステータス OFF) に設定しておいた方が良い。
動作確認してみる
ココまでの設定ができたら、クライアント側から IPv6 アドレスが見えるかどうか確認してみる。WSL2 より dig と nslookup コマンドで確認した。
# IPv6 設定前・AAAA レコードが返ってこない (`ANSWER: 0` 部分)
$ dig AAAA example.com
; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> AAAA example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1026
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
# IPv6 設定後・AAAA レコードが返ってきた
$ dig AAAA example.com
; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> AAAA example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60554
;; flags: qr rd ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available
;; QUESTION SECTION:
;example.com. IN AAAA
;; ANSWER SECTION:
example.com. 0 IN AAAA XXXX:XXXX:XXXX:XXXX:X:XXXX:XXXX:XXXX
# IPv6 設定前・AAAA レコードが返ってこない
$ nslookup -type=AAAA example.com
Non-authoritative answer:
*** Can't find example.com: No answer
# IPv6 設定後・AAAA レコードが返ってきた
$ nslookup -type=AAAA example.com
Non-authoritative answer:
Name: example.com
Address: XXXX:XXXX:XXXX:XXXX:X:XXXX:XXXX:XXXX
$ curl -6 でも IPv6 で通信確認できるが、WSL2 では基本的に通信に失敗するため留意。WSL2 の設定ファイルで「ミラーモード」などのネットワークモードに設定していないと、通信は Windows ホスト側で IPv4 に NAT されるためだ。
# WSL2 で IPv6 での `curl` に失敗しても基本的には「仕様」なので気にしない
$ curl -6 https://example.com/
curl: (7) Failed to connect to example.com port 443 after 1 ms: Couldn't connect to server
自分は WSL2 からではなく、Windows GitBash から $ curl -6 で通信して確認した。
ついでに、Public IPv6 でサーバへ到達できるようにしてあると、ブラウザからでも IPv6 アドレスを指定してアクセスができる。IPv6 アドレスはブラケット [] で囲んであげる必要がある。
- 記述例 :
http://[XXXX:XXXX:XXXX:XXXX:X:XXXX:XXXX:XXXX]/index.html
以上
今回、自分のメイン PC でも IPv6 を有効にしつつ、IPv4・IPv6 ともに使用する DNS サーバを Cloudflare が提供する DNS リゾルバ「1.1.1.1」に設定した。
OCI のネットワークから VM まで IPv6 対応をしたので、nginx のアクセスログなどでユーザの IPv6 アドレスが確認できるようになった。IPv6 でサーバまでアクセス出来ているということだ。
このサイト neos21.net は GitHub Pages にカスタムドメインを指定して公開しているのだが、GitHub Pages 用の A レコード (IPv4 用) しか指定してなかったため、今回セットで AAAA レコード (IPv6 用) も指定することにした。
- 参考 : GitHub Pages サイトのカスタムドメインを管理する - GitHub ドキュメント
-
AAAA レコードを作成するには、apex ドメインが GitHub Pages の IP アドレスを指すようにします
-
別に体感できるほど通信が速くなったーとかそういうことはないけども、コレでとりあえず自分が公開・利用しているサーバ類に関してはいずれも IPv6 対応ができたことになる。