介绍
Riverlight Gathering 已有正常运行的 IPv4 活动指南。访客需要通过 IPv6 获得同样完整的指南,包括到访信息和可下载的节目单。网络地址已经准备好,但 Web 服务尚未监听 IPv6,指南的 AAAA 记录也指向错误地址。
你将分开解决这两个问题:先让直接 IPv6 应用访问成功,再修正名称。整个过程中都要保留 IPv4、欢迎台、其他 DNS 记录,以及所有原始页面和下载文件的字节。前置要求是基本的终端、路径和 Tab 操作,以及识别地址、名称和端口;不要求 Nginx 或 IPv6 管理经验。70 分钟是作者估计时长。
Guide Server 和 Guide Client 是共享本训练实例内核的隔离网络节点,不是独立 VM。只修改 guide.conf 的监听语句和 guide.zone 中的目标 AAAA/SOA 序列号;下载文件保存在客户端工作目录。不要修改路由、地址、IPv6 开关、其他站点、源页面或平台设置。这是已准备的本地网络,不涉及公网 IPv6、RA、DHCPv6、隧道或 NAT64。
比较两种地址族
本步骤将先阅读正常的 IPv4 指南,再区分“IPv6 地址可达”和“应用正在监听”。从 Guide Client 开始。此终端起始目录是 /home/labex/project/ipv6-guide/client,其 shell 和目录状态独立于 Guide Server 持续保留。pwd 输出当前目录:
pwd
IPv4 地址由四个十进制部分组成,例如 10.77.0.10。IPv6 使用八组十六进制数字。每组开头的零可以省略;一个 :: 可以替代连续的全零组。这里的 fd77:7::10 表示 fd77:0007:0000:0000:0000:0000:0000:0010。末尾的 10 是十六进制,并不是 IPv4 地址末尾的十进制数。这些私有训练地址不代表能够访问公网。
curl 获取 HTTP 资源。-4 强制使用 IPv4,-f 将 HTTP 错误响应视为失败,-s 隐藏进度,-S 仍显示错误。--noproxy '*' 对所有主机绕过代理;引号让 * 保持为字面值,不展开为文件名。端口 8080 选择指南应用。-o 将接收的字节保存到文件;v4 是已准备的输出目录:
curl --noproxy '*' -4 -fsS http://guide.riverlight.test:8080/index.html -o v4/index.html
保存成功通常不输出内容。head -c 180 读取前 180 个字节,不修改文件:
head -c 180 v4/index.html
预期看到包含 Riverlight Gathering 的 HTML。这是需要保留的正常参考。页面完整的浏览器外观还需要样式表,稍后会保存它。
现在测试准备好的 IPv6 地址。ping -6 发送 IPv6 回显请求;-c 1 在一次请求后停止。它测试网络可达性,而非 HTTP:
ping -6 -c 1 fd77:7::10
预期收到回复。URL 中的 IPv6 字面地址要用方括号包住,以区分地址中的冒号与端口分隔符。整个 URL 也要加引号。-6 强制使用 IPv6;--max-time 3 将请求限制为三秒:
curl --noproxy '*' -6 -fsS --max-time 3 'http://[fd77:7::10]:8080/'
此请求预期失败,显示 curl: (7) 和连接被拒绝。IPv6 地址存在并能回复回显,但应用尚未打开该 IPv6 端点。如果出现超时,则表示在时限内未收到有效响应,与立即拒绝不同。不要通过禁用 IPv6 解决这两种情况。普通双栈浏览器可能改用 IPv4 重试,所以在那里看到页面不能证明 IPv6 成功。
名称拼写错误可能使 curl 报错 6,表示名称解析失败。对照拼写,再执行第一条命令。保存路径拼写错误会报告本地写入错误;用 pwd 和给出的 v4/index.html 路径检查。它们又不同于 HTTP 404:后者说明服务器已可达,只是所请求的资源不存在。
让 Web 服务监听 IPv6
本步骤将保留正常的 IPv4 监听,并添加单独的 IPv6 监听。切换到 Guide Server。起始目录是 /home/labex/project/ipv6-guide/config。cat 读取准备好的端点表和简短的目标配置:
cat endpoints.tsv
cat guide.conf
指南应使用 10.77.0.10 和 fd77:7::10,端口为 8080。欢迎台使用端口 8081,必须保留。server_name 选择该站点名称,root 指定原始页面位置,index 选择主页。花括号将一个 server 分组,每条指令以分号结束。
ss 读取内核套接字。-l 选择监听项,-t 选择 TCP,-n 显示数字地址和端口,-p 显示所属进程:
ss -ltnp
找到 IPv4 10.77.0.10:8080 上的 Nginx;此时尚无指南的 IPv6 监听。欢迎台的 IPv6 :8081 套接字并不提供指南端口的服务。
接下来用完整模板替换整个短文件。cat > guide.conf 将内容写入该文件,替换其先前内容。<<'NGINX' 开始一个 here-document:shell 会将后续行按字面内容读取,直到只有 NGINX 的那一行。粘贴整个代码块,包括最后的结束标记。先用 cp 保存本地备份;第二个文件名是副本:
cp guide.conf guide.conf.before
cat > guide.conf <<'NGINX'
server {
listen 10.77.0.10:8080;
listen [fd77:7::10]:8080 ipv6only=on;
server_name guide.riverlight.test;
root /opt/labex/ipv6-guide/www;
index index.html;
error_page 404 /404.html;
}
NGINX
listen 打开应用端点。新加入的方括号地址是 IPv6;ipv6only=on 让该监听仅接收 IPv6。保留的 IPv4 行独立提供 IPv4 服务。仅配置地址本身不会创建这个监听套接字。
已准备的 guide-control 命令只检查或加载本课独立服务。web-check 运行 Nginx 配置测试,不加载改动:
guide-control web-check
预期看到 syntax is ok 和 test is successful。如果分号、花括号或地址拼错,错误会指出文件及行号;此时尚未加载任何改动。重新输入上面的完整模板,再检查。若要恢复最初正常的 IPv4 配置,cp guide.conf.before guide.conf 可以还原备份;加载前仍需检查。不要重启平台的 Nginx 或网络。
web-load 会再次测试,然后请求重载。重载在应用保存配置时保留本课的主进程;仅保存文件不会改变运行中的服务:
guide-control web-load
ss -ltnp
预期 10.77.0.10:8080 和 [fd77:7::10]:8080 都由 Nginx 监听。如果日志报告端点已被占用,先将文件与完整模板比较并查看 ss,不要停止无关服务。
切换到 Guide Client。-w 在响应体之后输出连接事实。加引号的格式中,\n 表示换行;curl 会用实际对端地址替换 %{remote_ip},用响应状态替换 %{http_code}:
curl --noproxy '*' -6 -fsS --max-time 3 -w '\npeer=%{remote_ip} status=%{http_code}\n' 'http://[fd77:7::10]:8080/'
预期先看到 Riverlight HTML,然后是 peer=fd77:7::10 status=200。既要读状态,也要读内容:无关的默认页面即使返回 200 仍然不正确。此时的成功直连将应用层问题隔离出来;你还没有修正指南的名称。
让名称指向可用的 IPv6 服务
本步骤只修正目标 AAAA 记录,并让真实缓存自然更新。从 Guide Client 开始。DNS(域名系统)将名称映射到数据。A 记录提供 IPv4 地址,AAAA 提供 IPv6 地址。DNS 查询本身可以通过 IPv4 传输,同时返回 IPv6 地址。
dig 查询 DNS。@10.77.0.2 选择已准备的权威服务器,它负责此区域。+noall +answer 隐藏其他部分,只显示应答行:
dig @10.77.0.2 guide.riverlight.test A +noall +answer
dig @10.77.0.2 guide.riverlight.test AAAA +noall +answer
A 记录正确,为 10.77.0.10。AAAA 当前是 fd77:7::99,与可用服务不符。现在查询客户端独立的缓存解析器,地址是回环 127.0.0.1:
dig @127.0.0.1 guide.riverlight.test AAAA +noall +answer
每行包含名称、TTL、IN、记录类型和值。TTL 即 Time To Live,表示缓存应答还可复用的剩余秒数。准备的区域使用 30 秒。该查询可能缓存旧地址,这是正常现象。
切换到 Guide Server,读取完整区域:
cat guide.zone
$TTL 30 设置默认存活时间。@ 表示当前区域根。SOA(Start of Authority)记录括号中的第一个数字是区域版本,即序列号。NS 指定区域的权威服务器。以点结尾的是完整名称;guide 这样的短名称相对于 riverlight.test。除指南 AAAA 外保留所有记录,并将本次修订的序列号从 1 增为 2。序列号记录区域版本,不会清除现有客户端缓存。
备份文件,再使用已经学过的 here-document 模式替换整个短区域。ZONE 两侧的单引号也保护 $TTL,避免 shell 展开变量:
cp guide.zone guide.zone.before
cat > guide.zone <<'ZONE'
$TTL 30
@ IN SOA ns.riverlight.test. admin.riverlight.test. (2 60 30 3600 30)
@ IN NS ns.riverlight.test.
ns IN A 10.77.0.2
guide IN A 10.77.0.10
guide IN AAAA fd77:7::10
desk IN A 10.77.0.10
desk IN AAAA fd77:7::10
contact IN TXT "Welcome desk opens at 10:00"
ZONE
dns-check 运行原生 BIND 区域校验器,不改变实际 DNS:
guide-control dns-check
预期看到 loaded serial 2 和 OK。这里的 loaded 是指校验器读取文件,不是运行中的权威服务器发生改变。解析失败时,阅读行号,重新输入完整模板,再检查。如有需要,cp guide.zone.before guide.zone 可恢复原始文件;它也会恢复原来错误的 AAAA,因此只是恢复起点,不是最终答案。
dns-load 先检查,再通过私有控制通道仅重载本课区域:
guide-control dns-load
切换到 Guide Client,分别查询权威服务器和缓存:
dig @10.77.0.2 guide.riverlight.test AAAA +noall +answer
dig @127.0.0.1 guide.riverlight.test AAAA +noall +answer
权威服务器现在应返回 fd77:7::10。缓存可能仍显示旧地址,直到其剩余 TTL 到期。sleep 31 等待 31 秒,不修改任何缓存:
sleep 31
dig @127.0.0.1 guide.riverlight.test AAAA +noall +answer
现在应得到正确 IPv6 地址,不需要清空全局缓存或修改解析器。如果权威服务器仍然错误,回到已保存的区域并使用 dns-load;如果权威正确而缓存仍不同,则阅读 TTL,再等待相应的有限时间。删除 AAAA 只会移除 IPv6 名称访问,并不能修复它。
最后强制发出具名 IPv6 请求:
curl --noproxy '*' -6 -fsS --max-time 3 -w '\npeer=%{remote_ip} status=%{http_code}\n' http://guide.riverlight.test:8080/
预期看到 Riverlight HTML 和 peer=fd77:7::10 status=200。直接 IPv6 成功而名称访问失败,说明应查看 DNS,而非重建监听。
通过两种地址族阅读并下载完整指南
本步骤将通过两种地址族使用完整指南,同时保留受保护的欢迎台和记录。从 Guide Client 开始。只有正确主页,不能证明详情链接、样式和完整下载都可用。
通过真实指南名称,使用 IPv4 保存四个原始资源。准备好的 v4 文件夹只保存你下载的字节;每个 -o 路径指定相应资源的保存文件:
curl --noproxy '*' -4 -fsS http://guide.riverlight.test:8080/index.html -o v4/index.html
curl --noproxy '*' -4 -fsS http://guide.riverlight.test:8080/visit.html -o v4/visit.html
curl --noproxy '*' -4 -fsS http://guide.riverlight.test:8080/style.css -o v4/style.css
curl --noproxy '*' -4 -fsS http://guide.riverlight.test:8080/programme.txt -o v4/programme.txt
使用 IPv6 重复获取,分别保存,避免成功结果覆盖 IPv4 证据:
curl --noproxy '*' -6 -fsS http://guide.riverlight.test:8080/index.html -o v6/index.html
curl --noproxy '*' -6 -fsS http://guide.riverlight.test:8080/visit.html -o v6/visit.html
curl --noproxy '*' -6 -fsS http://guide.riverlight.test:8080/style.css -o v6/style.css
curl --noproxy '*' -6 -fsS http://guide.riverlight.test:8080/programme.txt -o v6/programme.txt
cmp 逐字节比较两个文件。没有输出并返回提示符表示相同;报告差异则说明资源不一致。比较每个资源,再阅读完整节目单:
cmp v4/index.html v6/index.html
cmp v4/visit.html v6/visit.html
cmp v4/style.css v6/style.css
cmp v4/programme.txt v6/programme.txt
cat v6/programme.txt
一直读到 WET WEATHER 和最后的合成活动说明。文件存在或大小正确,不能证明完整日程和无障碍信息已正确到达。如果两个错误文件恰好相同,单靠 cmp 也不能证明内容为原始内容;检查会同时对照准备的原件与实际服务。
切换到 Saved Guide。选择 Open IPv4 saved guide,阅读节目卡片,再选择 Make a day of it 查看到访和无障碍信息。选择该页的 Save the programme 下载节目单。使用浏览器的 Back 按钮从详情页返回主页,再 Back 一次返回查看器的选择页。选择 Open IPv6 saved guide,重复同样的链接和下载。两者都应是相同且完整的 Riverlight 指南。

阅读三张节目卡片,并使用到访与下载链接;这个页面就是实际保存的指南。
查看器只读取 Guide Client 中的 v4 和 v6 文件,绝不会获取缺失文件。如果样式或页面缺失,回到 Guide Client,重新执行对应地址族和资源的保存命令,再重新加载浏览器页面。浏览器到查看器的连接只是展示路径;证明 IPv6 的是终端中强制地址族的请求和实际对端,而不是查看器 URL。
切换到 Guide Client。保持独立欢迎台通过两种地址族均可访问:
curl --noproxy '*' -4 -fsS http://desk.riverlight.test:8081/
curl --noproxy '*' -6 -fsS http://desk.riverlight.test:8081/
两者都返回 Welcome desk: open 10:00–20:00. Keep this site available.。检查保留的 A 和 TXT 记录:
dig @10.77.0.2 guide.riverlight.test A +short
dig @10.77.0.2 contact.riverlight.test TXT +short
预期分别为 10.77.0.10 和 "Welcome desk opens at 10:00"。如果受保护的值不同,使用完整原始模板恢复,同时保留已修正的指南 AAAA,然后检查并重载。不要复制源页面、添加代理、替换服务进程或改变地址来让检查变绿。检查只观察当前服务和已保存的结果;普通 GET 和 DNS 查询可能追加原生日志,但不会加载或修复你的工作。
总结
你为正常的 IPv4 指南添加了真正的 IPv6 监听,修正了 AAAA 记录,并让独立 DNS 缓存自然更新。强制指定地址族的请求交付了同样的原始主页、到访页、样式表和完整节目单。你保留了 IPv4、欢迎台、其他记录以及准备好的网络。可达性、名称解析、监听和正确应用内容是不同的事实。



