迁移总方案:博客 + 播客脱离共享 CDN 代理 IP 依赖
背景与目标(2026-08-29 更新)
当前问题:博客(Cloudflare Pages)和播客音频(Cloudflare R2)都跑在 Cloudflare 的代理网络上,2026/27 赛季 LaLiga 反盗版封锁几乎天天有比赛日触发,导致这两块服务频繁被 O2 误伤。
重要更正:原方案曾建议博客迁往 Vercel,但经查证,Vercel、Netlify、GitHub Pages、BunnyCDN 等主流共享 IP CDN/托管平台,同样被 LaLiga 这轮封锁波及过——本质上都是"几十万个域名挤在同一批共享 IP 上",只是被点名的频率和时间点不同,不是安全选项。因此博客的迁移目标改为自建到已有的 Linode VPS,用独立静态 IP 避开"共享大池子"这个结构性风险。
目标架构:
博客 → 自建到 Linode VPS(独立静态 IP,不与任何共享 CDN 池混用)
播客音频 → Backblaze B2(独立网络出口,目前未见被波及)
+ archive.org(可选长期镜像)
RSS feed → 跟博客一起自建到 VPS
DNS → Nameserver 仍留在 Cloudflare(不受影响),但相关记录改成
灰云 DNS-only 或直接指向新服务商,不再走 Cloudflare 代理
总体原则:稳字当头
- 分阶段,不并行操作多个系统——一次只动一件事,出问题能立刻定位是哪一步
- 新旧并行运行,验证通过再切流量——旧服务在确认新服务稳定前,一律不下线、不删除
- 先低风险资产练手,后核心资产——博客先行,播客音频(涉及历史存量数据)放后面
- 每一步都有明确的验证方法,不是"感觉应该好了"就往下走
- 每个阶段都留回滚预案——任何一步出问题,能在几分钟内退回上一个稳定状态
- 不动现有的关键基础设施——VPS 上已有的 Xray Reality 代理是日常依赖的服务,迁移过程优先选不影响它的方案,即使多花点小钱或多绕一步
Phase 0:准备阶段(不影响任何线上服务,随时可以开始)
- 确认 Linode VPS 当前的资源状况(磁盘剩余空间、443 端口已被 Xray 占用——处理方式见 Phase 1 第二步之后的说明)
- 注册 Backblaze B2 账号,创建一个 bucket(比如
yemushi-podcast),生成 Application Key(记得勾选读写权限) - (可选)注册 archive.org 账号,在
archive.org/account/s3.php生成 IAS3 密钥,留到 Phase 3 用 - 把 Cloudflare 后台当前所有相关 DNS 记录截图或导出备份(类型、名称、值、TTL、是否代理),这是最重要的一步——出问题时靠这份记录能几分钟内手动改回原样
- 记录当前博客和播客涉及的所有域名/子域名清单,避免迁移时漏掉某个不常用的子域名
- 备份现有 Xray 配置:
cp /usr/local/etc/xray/config.json /usr/local/etc/xray/config.json.bak,不管后面选哪个方案处理 443 冲突,先留一份备份
这一步做完,什么都还没变,可以慢慢来,不用赶。
Phase 1:博客自建到 Linode VPS(先拿这个练手,风险最低)
1.1 VPS 基础检查与安全加固
# SSH 登录 VPS
ssh root@你的VPS_IP
# 更新系统
apt update && apt upgrade -y
# 检查磁盘空间,确认够用
df -h
# 确认 443 端口被谁占用(预期会看到 xray)
ss -tlnp | grep -E ':80|:443'
安全加固(比基础版更完整,因为这台机器要长期对公网暴露 80/443):
a) SSH 加固
# 配置 SSH 密钥登录(如果还没有)
ssh-keygen -t ed25519 -C "[email protected]"
ssh-copy-id root@你的VPS_IP
nano /etc/ssh/sshd_config
修改这几项:
PasswordAuthentication no
PermitRootLogin no # 彻底禁 root 直接登录,比 prohibit-password 更严格
PubkeyAuthentication yes
MaxAuthTries 3 # 限制单次连接的认证尝试次数
ClientAliveInterval 300
ClientAliveCountMax 2 # 空闲连接自动断开
systemctl restart sshd
由于 PermitRootLogin no 需要先有一个非 root 的管理账号能 sudo,先建好:
adduser admin
usermod -aG sudo admin
mkdir -p /home/admin/.ssh
cp /root/.ssh/authorized_keys /home/admin/.ssh/
chown -R admin:admin /home/admin/.ssh
chmod 700 /home/admin/.ssh
chmod 600 /home/admin/.ssh/authorized_keys
先用 admin 账号登录测试成功之后,再改 sshd_config 禁用 root 登录,避免把自己锁在门外。
b) 防火墙(IPv4 + IPv6 分别确认)
apt install -y ufw
# 确认 IPv6 支持已开启
grep IPV6 /etc/default/ufw
# 应该看到 IPV6=yes,没有的话改成 yes
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
# 确认规则同时覆盖了 v4 和 v6
ufw status verbose
ufw status verbose 的输出里每条规则应该同时出现 (v6) 版本,确认新的 IPv6 地址上的 80/443 确实被放行、且没有意外放开其他端口。
c) fail2ban 加固,并扩展监控 Caddy 日志
apt install -y fail2ban
# 给 sshd 单独配置更严格的封禁策略
cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
[sshd]
enabled = true
[caddy-auth]
enabled = true
port = http,https
filter = caddy-auth
logpath = /var/log/caddy/access.log
maxretry = 10
EOF
# Caddy 默认不带 fail2ban 过滤规则,手动加一个简单版本,抓异常高频请求
cat > /etc/fail2ban/filter.d/caddy-auth.conf << 'EOF'
[Definition]
failregex = ^<HOST> .* "(GET|POST|HEAD).*" (404|444|400) .*$
ignoreregex =
EOF
systemctl restart fail2ban
fail2ban-client status
d) 自动安全更新(装完就不用天天惦记打补丁)
apt install -y unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades
# 选"是",之后系统会自动安装安全补丁
e) (强烈建议)SSH 管理入口收进你已有的 WireGuard 隧道,不对公网暴露 22 端口
你已经有 WireGuard 基础设施,这是最有效的一步——与其在公网上防守 SSH 暴力破解,不如干脆不让 22 端口对公网可见:
# 把 SSH 只允许通过 WireGuard 内网网段访问,公网防火墙直接拒绝 22
ufw delete allow OpenSSH
ufw allow in on wg0 to any port 22 proto tcp # wg0 换成你实际的 WireGuard 接口名
ufw status verbose # 确认 OpenSSH 那条公网规则已经不在了
这样即使全网扫描 IP 找开放的 22 端口,也扫不到你这台机器——管理入口完全收敛到你自己的 WireGuard 网络里,比任何 fail2ban 规则都更彻底。如果不方便这么做(比如临时需要在没连 WireGuard 的设备上应急登录),可以保留公网 22 但改成非标准端口,降低被扫描到的概率,两者都做也可以。
⚠️ 但要注意:这条只适用于你自己的交互式管理登录(admin 账号)。1.5 里 GitHub Actions 的自动部署是从 GitHub 的公网服务器发起连接的,连不上被收进 WireGuard 内网的 SSH。 部署用的 deploy 账号需要单独处理——继续保持公网可达,但用「强制命令」把它的权限锁死到只能跑 rsync,即使部署密钥意外泄露,攻击者能做的也仅限于同步文件到 /var/www/blog,拿不到任何 shell 权限。具体配置见 1.5.2。
1.2 安装 Caddy
apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
apt update
apt install -y caddy
systemctl status caddy
mkdir -p /var/www/blog
chown -R www-data:www-data /var/www/blog
1.3 处理 443 端口冲突(用 IPv6,零成本、不改 Xray)
Reality 协议的伪装原理是:不匹配 Reality 密钥的流量会被原样转发给配置里的 dest(伪装目标),由 dest 自己完成真实的 TLS 握手。Xray 进程独占了原 IPv4 的 443 监听权,不能简单叠加另一个服务。
采用方案:给 VPS 用免费分配的 IPv6 地址,Caddy 绑定这个新地址的 443,Xray 完全不动。
- 确认 Linode 已经给这台实例分配了 IPv6(Linode 默认每台实例免费带一个
/64段):
ip -6 addr show
看到类似 2600:xxxx:xxxx:xxxx::1/64 这样的地址就是可用的公网 IPv6,记下这个具体地址。
- 在 Caddyfile 里显式绑定这个 IPv6 地址:
nano /etc/caddy/Caddyfile
博客域名.com {
bind 2600:xxxx:xxxx:xxxx::1
root * /var/www/blog
file_server {
hide .* # 不暴露隐藏文件
}
encode gzip
# 安全响应头,见下方 1.3.1
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
-Server # 去掉响应头里的 Server 标识,减少信息暴露
}
}
systemctl reload caddy
- Cloudflare DNS 里博客的记录改成 AAAA 记录,指向这个 IPv6 地址,代理状态灰云 DNS-only
注意:只加 AAAA、不加 A 记录,意味着只有支持 IPv6 的网络才能访问你的博客。 目前西班牙主流运营商(Movistar、Vodafone、Orange 等)以及绝大多数移动网络都已支持 IPv6,覆盖率很高,但极少数老旧网络环境可能访问不了。如果不放心,可以在确认稳定后,再考虑要不要额外申请一个付费 IPv4(Linode 一般 $1-2/月)做双栈兜底,这一步不急,可以观察一段时间再决定。
这个方案安全的原因需要说准确:不是"IPv6 技术上封不了"(详见文末附注 2,运营商确实可以精确封锁具体 IPv6 地址),而是这个 IPv6 地址是你独享的,不会因为跟别人共享而被连坐。 只要不把这台 VPS 上的服务和任何共享 CDN/托管平台混用,这个地址就没有理由出现在封锁清单上。
Xray 那边完全不用动,它继续用原来的 IPv4 地址监听 443,两边互不干扰,直接进入 1.3.1。
1.3.1 新 IPv6 地址本身也要单独确认防火墙范围
因为 ufw 的规则默认是端口级别、不区分具体 IP,前面 1.1 里配置的 ufw allow 80/tcp / 443/tcp 会同时对 IPv4 和 IPv6 生效,这正是我们想要的(博客要在新 IPv6 上提供服务)。但要确认没有把 SSH 或其他内部服务意外暴露在这个新 IPv6 上:
# 确认新 IPv6 地址上只有 80/443 在监听,没有其他服务
ss -tlnp | grep '2600:xxxx' # 换成你实际的 IPv6 前缀
# 确认 SSH 已经按前面 1.1(e) 收进 WireGuard,公网 IPv4/IPv6 都看不到 22 端口
nmap -6 -p 22 2600:xxxx:xxxx:xxxx::1 # 从外部机器测试,预期结果是 filtered/closed
方案 B(备选,需谨慎,会改动 Xray 配置):把博客设为 Reality 的伪装目标
核心思路:把 Xray Reality 的 dest 改成指向本机 Caddy 监听的内部端口,让"伪装身份"变成你自己的真实博客。
# 务必先确认已经备份过(Phase 0 提到的那步)
cat /usr/local/etc/xray/config.json.bak > /dev/null || echo "还没备份,先去备份!"
编辑 config.json,找到 realitySettings 部分:
"realitySettings": {
"dest": "127.0.0.1:8443",
"serverNames": ["你的博客域名.com"]
}
Caddy 需要改成监听 8443 并自己完成 TLS termination(因为 dest 收到的是真实的 TLS 连接,必须有真实证书):
你的博客域名.com:8443 {
root * /var/www/blog
file_server
encode gzip
}
systemctl restart xray
systemctl reload caddy
# 立刻测试 Xray 本身是否还正常工作(比如从客户端连一下),确认没有搞挂代理
如果测试后发现 Xray 连接异常,立刻用备份恢复:
cp /usr/local/etc/xray/config.json.bak /usr/local/etc/xray/config.json
systemctl restart xray
1.4 先用测试子域名跑通整条链路(不动线上域名)
1.4.1 编辑 Caddy 配置
nano /etc/caddy/Caddyfile
test-blog.你的域名.com {
bind 2600:xxxx:xxxx:xxxx::1 # 换成你实际的 IPv6 地址
root * /var/www/blog
file_server {
hide .*
}
encode gzip
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
}
}
systemctl reload caddy
1.4.2 在 Cloudflare DNS 后台加一条测试记录
新建 AAAA 记录:test-blog → 你的 IPv6 地址,代理状态设为灰云(DNS only),TTL 设短一点(比如 300 秒)。
1.4.3 先手动放一个测试页面验证
echo "<h1>Hello from VPS</h1>" > /var/www/blog/index.html
访问 https://test-blog.你的域名.com,能看到内容且证书有效,说明 Caddy 的自动 HTTPS 和静态文件服务、以及端口共存方案都跑通了。
1.5 配置 GitHub Actions 自动构建 + 部署
1.5.1 在 VPS 上建一个部署专用用户
adduser deploy
usermod -aG www-data deploy
mkdir -p /home/deploy/.ssh
1.5.2 生成一对专门用于 GitHub Actions 部署的密钥,并用强制命令锁死权限
ssh-keygen -t ed25519 -f ./deploy_key -N ""
# 在 VPS 上,装 rrsync(rsync 官方自带的受限包装脚本,专门用于这种场景)
apt install -y rsync
find / -name rrsync 2>/dev/null # 找到 rrsync 脚本的位置,通常在 /usr/share/doc/rsync/ 或 /usr/bin
cp /usr/share/doc/rsync*/scripts/rrsync /usr/local/bin/rrsync # 路径根据实际找到的调整
chmod +x /usr/local/bin/rrsync
# authorized_keys 里用 command= 强制限定这把密钥只能执行 rrsync,且只能写入指定目录
cat >> /home/deploy/.ssh/authorized_keys << 'EOF'
command="/usr/local/bin/rrsync -wo /var/www/blog/",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAAA...(把deploy_key.pub的实际内容粘贴在这里)
EOF
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:www-data /var/www/blog
chmod -R 775 /var/www/blog
加了 command= 前缀之后,这把密钥不管被拿去做什么,SSH 服务端都会强制只执行 rrsync -wo /var/www/blog/(-wo 表示只写、不能读取和删除目录外的内容),no-pty 等选项禁止了交互式 shell、端口转发这些额外能力。即使 GitHub Secrets 意外泄露,攻击者用这把密钥能做的也仅限于往 /var/www/blog 目录写文件,拿不到 shell,进不了系统其他部分。
1.5.3 把私钥加进 GitHub 仓库的 Secrets
仓库 → Settings → Secrets and variables → Actions,新建:
DEPLOY_SSH_KEY:deploy_key私钥完整内容DEPLOY_HOST:你的 VPS 公网 IP(部署用的是公网 IPv4/原有管理 IP,不是 Caddy 绑定的新 IPv6,只要能连上 22 端口即可,两者不冲突)DEPLOY_USER:deploy
更彻底的做法(推荐):用自托管 Runner,完全不用为部署开放 22 端口
上面这套「强制命令锁死密钥」的方案本身没问题,但它要求 22 端口必须留给公网的 GitHub 服务器连进来,跟 1.1(e) 里「SSH 完全收进 WireGuard」这个更彻底的加固思路是冲突的——鱼与熊掌不能兼得。如果不想在这两者之间妥协,更干净的做法是:在 VPS 上装一个 GitHub Actions 自托管 Runner,让部署流程反过来变成"VPS 主动连出去问 GitHub 有没有新任务",而不是"GitHub 连进来",这样就完全不需要为部署开放任何入站端口,跟你现有的 WireGuard/Xray 这类"只出不进"的架构风格也更一致:
# 在 VPS 上,用 deploy 账号创建 Runner 工作目录
sudo -u deploy bash
mkdir ~/actions-runner && cd ~/actions-runner
# 去 GitHub 仓库 → Settings → Actions → Runners → New self-hosted runner
# 按页面提示下载对应版本并配置(会给你一段专属的 token 和命令)
tar xzf ./actions-runner-linux-x64-x.x.x.tar.gz
./config.sh --url https://github.com/你的用户名/你的仓库 --token 从页面复制的token
# 注册成系统服务,开机自启、断线自动重连
exit # 退回 root
cd /home/deploy/actions-runner
./svc.sh install deploy
./svc.sh start
对应的 workflow 里把 runs-on: ubuntu-latest 改成 runs-on: self-hosted,构建和部署(直接 cp/rsync 到本地 /var/www/blog,不需要再走网络 SSH)都在这台机器本地完成:
jobs:
deploy:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- name: Build
run: |
# hugo --minify
echo "替换成你自己的构建命令"
- name: Deploy locally
run: |
rsync -avzr --delete public/ /var/www/blog/
这样一来,1.1(e) 的「SSH 完全收进 WireGuard、公网 22 端口彻底不开放」就不再和部署流程冲突了,可以放心按最严格的方式配置。前面写的「强制命令锁死密钥」方案作为备选保留——如果你不想在 VPS 上常驻一个 Runner 进程(毕竟多一个需要维护的服务),也可以选那条路,两种方式选一种即可,不用都做。
1.5.4 编写 GitHub Actions workflow
.github/workflows/deploy.yml(构建命令和产物目录换成你实际用的静态生成器对应的):
name: Deploy Blog
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: |
# hugo --minify
echo "替换成你自己的构建命令"
- name: Deploy via rsync
uses: burnett01/[email protected]
with:
switches: -avzr --delete
path: public/ # 换成你实际的构建产物目录
remote_path: /var/www/blog/
remote_host: ${{ secrets.DEPLOY_HOST }}
remote_user: ${{ secrets.DEPLOY_USER }}
remote_key: ${{ secrets.DEPLOY_SSH_KEY }}
1.5.5 验证自动部署
改动一篇文章,git push,去 Actions 标签页确认构建和 rsync 都成功,刷新测试子域名确认改动生效。
1.6 正式切换域名
1.6.1 修改 Caddy 配置,加上正式域名
nano /etc/caddy/Caddyfile
你的正式博客域名.com {
bind 新IP地址 # 方案A需要;方案B不需要
root * /var/www/blog
file_server
encode gzip
}
systemctl reload caddy
1.6.2 修改 Cloudflare DNS
正式博客域名的记录改成指向对应 IP,代理状态设为灰云(DNS only)。
⚠️ 先不要删除 Cloudflare Pages 项目,保留至少一到两周作为回滚后备。
1.7 验证清单
-
curl -I https://你的正式博客域名返回 200,响应头显示 Caddy 而不是 Cloudflare - 家宽直连和手机流量各测一次
- 挑一个当天有比赛的时段专门测一次
- 改一篇文章 push 上去,确认自动部署链路在正式域名上也生效
- 重点:确认 Xray 代理服务依然正常工作,不管用的是方案 A 还是方案 B
- 检查 HTTPS 证书是否正常
1.8 观察期
稳定运行 3-7 天,覆盖至少 2-3 个比赛日。确认无异常后再考虑清理旧的 Cloudflare Pages 项目。
回滚预案
- 博客本身:把 Cloudflare DNS 记录改回原来指向 Cloudflare Pages 的配置即可,几分钟内恢复,旧项目全程没删除
- 如果用了方案 B 且 Xray 出问题:
cp /usr/local/etc/xray/config.json.bak /usr/local/etc/xray/config.json && systemctl restart xray立刻恢复
Phase 2:播客音频从 R2 迁移到 B2(核心资产,最谨慎的一步)
这一步涉及历史存量数据,是整个方案里唯一"有数据丢失风险"的环节,按下面的顺序一步都不要跳:
2.1 工具准备
curl https://rclone.org/install.sh | sudo bash
rclone config
分别把 R2 和 B2 的 Access Key / Secret Key 配置成两个独立的 remote(r2-source 和 b2-target)。
2.2 先做 dry-run
rclone sync r2-source:你的bucket名 b2-target:yemushi-podcast --dry-run -v
仔细核对文件列表和数量。这一步只打印计划,不会真的传输。
2.3 正式同步(只拷贝,不删除 R2 原文件)
rclone copy r2-source:你的bucket名 b2-target:yemushi-podcast -v --progress
用 copy 不用 sync,更安全。
2.4 抽样校验
- 随机挑 3-5 集对比文件大小
-
rclone check r2-source:你的bucket名 b2-target:yemushi-podcast做哈希校验
2.5 Pipeline 代码改成双写
upload_to_r2(file_path) # 保留原有逻辑
upload_to_b2(file_path) # 新增
双写至少维持 2-4 周。
2.6 RSS feed 切换
先只对新发布的单集试用 B2 链接,观察 Apple Podcasts / 小宇宙抓取是否正常,稳定后再考虑批量改历史链接。
2.7 观察期
覆盖至少 2-3 个比赛密集的周末,确认稳定后再考虑停止双写、清理 R2。
回滚预案
RSS 链接改回 R2 地址即可,因为全程没删除 R2 文件。
Phase 3(可选):archive.org 长期镜像
优先级最低,可在 Phase 2 稳定后慢慢配置:
- 用 IAS3 密钥把历史音频批量上传到 archive.org
- 新集数发布时 pipeline 里加一步同步上传
Phase 4:DNS 收尾检查
- 梳理 Cloudflare DNS 后台所有记录,逐条确认哪些还是橙云
- 不再需要走 Cloudflare 代理的记录改成灰云 DNS-only
- Nameserver 留在 Cloudflare 不用动
建议时间线
| 时间 | 任务 |
|---|---|
| 第 1 周 | Phase 0 准备 + Phase 1.1-1.4(VPS 加固、装 Caddy、处理 443 冲突、测试子域名跑通) |
| 第 2 周 | Phase 1.5-1.7(GitHub Actions 自动部署、正式切换域名、验证) |
| 第 3 周 | Phase 1 观察期 + Phase 2 准备(rclone 同步、抽样校验) |
| 第 4 周 | Phase 2 正式双写上线 |
| 第 5-8 周 | Phase 2 观察期,覆盖多个比赛日 |
| 之后 | Phase 3 archive.org 镜像 + Phase 4 DNS 收尾 |
哪个阶段观察下来还有疑虑,就多留观察期,不用赶进度。
通用验证清单
curl -I <新地址>,确认返回 200 且响应头显示自建服务标识- 家宽直连和手机流量各测一次
- 专门挑比赛日测试
- 检查旧服务是否还保持可用,作为回滚后路
- 涉及 VPS 改动的步骤,额外确认 Xray 代理服务未受影响
附注:为什么放弃 Vercel/Netlify,选择自建 VPS
经查证,LaLiga 这轮反盗版 IP 封锁自 2025 年初开始已陆续波及 Cloudflare、Vercel、Netlify、GitHub Pages、BunnyCDN 等主流共享 IP 的 CDN/托管平台,本质原因是这些平台都是"大量域名共享少量 IP"的结构,非法 IPTV 转播服务混在同一批 IP 里,导致误伤范围随之扩大。Vercel 官方甚至专门发博客说明此事,CEO 也公开表示即便开通了专门的举报通道,还是持续被无差别封锁。
相比之下,自建到独立静态 IP 的 VPS,不与任何大型共享 IP 池混用,被"连坐"的概率结构性更低——虽然不是 100% 的官方保证,但目前是几个选项里风险最低的一个。
附注 2:重新核实——IPv6 是否天然躲得开这类封锁?(2026-08-30 补充分析)
在最终确定用 IPv6 方案之前,专门查证了一个关键问题:运营商是不是技术上没法把 IPv6 地址全部封掉,所以 IPv6 天然更安全? 查证结果需要纠正一个想当然的假设——答案是否定的,IPv6 一样会被精确封锁,安全性的来源不是"协议层面封不了",而是别的原因。
实际情况:西班牙网友论坛上已经有人明确抱怨过这个问题——原文大意是"为什么 IPv6 也被封?理论上每个服务不是应该能有自己独立的 IPv6 地址、不用像 Cloudflare 的 IPv4 那样挤在共享池里吗?“这条留言本身就证实了两件事:第一,运营商确实在封锁清单里精确点名封禁具体的 IPv6 地址,技术上完全做得到(对防火墙来说封一个 IPv6 地址和封一个 IPv4 地址没有本质难度差异,不存在"地址空间太大封不过来"这种技术豁免);第二,IPv6 真正的优势不是"封不了”,而是"每个服务可以有自己独立的地址,不必和别人共享"——这跟我们选它的理由其实是同一个逻辑,只是需要把"封不了"这个错误理解纠正成"没有理由被封"。
这对你的方案意味着什么:
- 你的 Linode IPv6 地址安全,不是因为它是 IPv6,而是因为它是你独享的、跟任何 Cloudflare/Vercel 服务完全无关的地址——这跟之前的核心判断完全一致,只是要澄清"protocol 本身天然安全"这个说法不准确,真正起作用的是"地址不共享、不会被别的网站牵连"
- 不会无缘无故被封,但也不是绝对不可能——封锁清单本质是 LaLiga 举报 + 运营商执行的动态名单,只要你的 IPv6 地址不出现在任何被举报的服务列表里(这是大概率事件,因为你的 VPS 只是自己用),就不会被点名。真正的风险不是"IPv6 遲早被扫描到",而是"万一将来 VPS 上又混进了某个跟别人共享/容易被牵连的服务",这也是为什么方案里反复强调"不要把博客和任何共享 CDN 混用"这个原则比"用 IPv4 还是 IPv6"本身更关键
- 规则的扩张趋势值得留意:查到的最新信息显示,法院授权的封锁范围已经从最初判决书列出的 123 个 IP,扩大到目前号称最多同时封锁约 3000 个 IP(其中 35-45% 属于 Cloudflare),而且已经开始出现"不局限于比赛日"的封锁案例,2026 年 3 月还有一份新判决把范围扩大到了欧冠、网球、高尔夫等其他赛事期间。这说明这套机制本身还在扩张,不是收敛趋势——独立 IP 这个策略眼下有效,但不代表以后完全不用再关注这个问题
结论:不用改变已经定下的 IPv6 方案,这仍然是目前几个选项里最合理的一个;只是把决策依据修正为准确的——“独享、不共享"才是关键,而不是"IPv6 协议本身封不了”。