Twikoo 评论 IP 属地不对,把后端改成 IPv4-only

Twikoo 评论 IP 属地不对,把后端改成 IPv4-only

记录一次 Twikoo + Netlify 评论后端的 IP 属地显示错误排查。

背景

我的博客是静态页面,托管在 Cloudflare Pages,域名解析也在 Cloudflare。 评论区用的是 Twikoo,后端单独部署在 Netlify Functions。

页面和评论是两条路:

txt
blog.zery.cn    -> Cloudflare Pages -> 博客页面
twikoo.zery.cn  -> Netlify Function  -> Twikoo 评论后端

后面才发现,这点很重要。因为评论区显示哪个 IP、显示不显示属地,主要看 twikoo.zery.cn 这个后端域名最后把什么 IP 交给了 Twikoo,和博客页面本身是不是走 IPv6、是不是套 CDN 不是一回事。

一开始以为是 CDN 的锅

最早的问题是评论 IP 属地会乱跳,有时是香港,有时是美国。这个现象很迷惑,因为手机没有挂代理,流量显示美国就明显不对了。

当时链路大概是:

txt
访客
-> Cloudflare / 其他 CDN
-> Netlify Function
-> Twikoo

这种情况下,Netlify 有可能看到的是 CDN 节点 IP。然后Twikoo 拿节点 IP 去查属地,显示香港、美国就不奇怪了。

所以第一步先直接查验后端收到的 header。

debug-ip.jsjs
const headers = [
  'cf-connecting-ip',
  'x-real-ip',
  'x-forwarded-for',
  'x-nf-client-connection-ip',
]

手机访问时,看到过类似这样的结果:

json
{
  "cf-connecting-ip": "2409:8938:****:****:****:****:****:****",
  "x-forwarded-for": "2409:8938:****:****:****:****:****:****, 162.158.*.*, 50.18.*.*",
  "x-nf-client-connection-ip": "162.158.*.*"
}

这里其实已经很清楚了。前面的 2409:... 是手机真实 IPv6,后面的 IPv4 是中间节点。

这时如果为了让属地显示出来,取 x-forwarded-for 后面的 IPv4,确实可能有结果,但它只是 CDN 或云平台节点的归属地。

关掉小黄云后,问题没有结束

后来把 Cloudflare 小黄云关了,按理说 CDN 节点这层干扰没了。

再看 header,变成了这样:

json
{
  "cf-connecting-ip": "",
  "x-forwarded-for": "2409:8938:****:****:****:****:****:****, 54.254.*.*",
  "x-nf-client-connection-ip": "2409:8938:****:****:****:****:****:****"
}

这次 Netlify 拿到的已经是真实客户端 IP,但它是 IPv6。

问题就从“拿到的是不是本人 IP”,变成了“Twikoo 能不能查这个 IPv6 的属地”。实际表现是:Twikoo 对这个 IPv6 查不出来,于是评论区属地直接空了。

别人同样 Twikoo 却可以显示

对照了一个同样用 Twikoo 的站。奇了怪了,发现它能显示,但这不代表它一定改了 Twikoo 后端,比如额外加了 IPv6 属地库。

更可能的区别在 DNS。

它的评论后端没有 AAAA 记录,只能走 IPv4:

txt
comment.example.com A     x.x.x.x
comment.example.com AAAA  none

手机访问它的评论后端时,最后进后端的就是 IPv4。Twikoo 查 IPv4 没问题,属地自然能出来。

这也是我最后采用的办法:让评论后端只走 IPv4。

域名 DNS 怎么改

在 Cloudflare DNS 里改 twikoo 这条记录:

txt
Type: A
Name: twikoo
IPv4 address: 75.2.60.5
Proxy status: DNS only

然后确认这几件事:

txt
没有 AAAA
没有 CNAME
小黄云关闭

可以用 DNS-over-HTTPS 查一下,避免本地代理或者 Fake-IP 影响判断:

powershell
Invoke-RestMethod `
  -Uri "https://cloudflare-dns.com/dns-query?name=twikoo.zery.cn&type=A" `
  -Headers @{ accept = 'application/dns-json' }

Invoke-RestMethod `
  -Uri "https://cloudflare-dns.com/dns-query?name=twikoo.zery.cn&type=AAAA" `
  -Headers @{ accept = 'application/dns-json' }

这边最终期望是:

txt
A     75.2.60.5
AAAA  none

DNS 生效后,再用手机流量发一条新评论。

新的 header 应该接近这样:

json
{
  "x-forwarded-for": "183.217.*.*, 3.1.*.*",
  "x-nf-client-connection-ip": "183.217.*.*"
}

这时 Twikoo 拿到的是 IPv4,归属地就能正常显示。

新故事即将发生
Hello, Zery Notes

评论区

评论加载中...