先花一分钟看懂原理
这套方案是什么
客户端只和 CF 打交道。墙只能看到你在访问一个普通的 CF 网站,看不到 VPS 的真实 IP。
- 你的设备 → CF(443 端口,TLS,SNI 是你的节点域名)
- CF → VPS 上的 Nginx(443)
- Nginx 按路径把流量交给本机的 Xray
- Xray → 互联网
整条链路里只有 CF 直接面对你的设备,Nginx 和 Xray 都藏在它后面。
一台 VPS、一个自己的域名、一个免费的 CF 账号
多了一跳。速度主要看 CF 到你所在运营商的线路,晚高峰可能变慢,可以用文末的「优选 IP」改善
不会 Linux 也没关系:按顺序复制粘贴命令即可,需要你自己改的只有域名
套 CF 不一定比直连快,有时还更慢。如果你的 VPS 是中国优化线路,那么直连更快。
Cloudflare 用户协议第 2.2.1 条禁止用它的服务提供 VPN 或类似代理服务(j 项),也禁止把域名流量导向不是 CF 分配给这个域名的 IP(b 项,也就是文末的「优选 IP」)。截至 2026 年 10 月,公开讨论里还没看到普通 VPS 套橙云被处理的案例(用 Workers 搭的节点有过集中失效),但条款上属于违规,账号可能被停用。
所以单独注册一个 CF 账号、单独买一个便宜域名专门搭节点,别和重要网站放在一起。
备好 4 样东西,登录上 VPS
准备工作
系统选 Debian 12 或 Ubuntu 22.04 / 24.04
任何注册商都行,例如 Namesilo
免费版就够
Windows 用 FinalShell;Mac / Linux 用自带终端;安卓手机可用 ConnectBot
把域名托管到 Cloudflare
- 登录 CF → 添加站点(Add a domain)→ 输入域名 → 选 Free 计划
- CF 会给你两条 NS(名称服务器)地址
- 回到买域名的网站,把域名的 NS 改成 CF 给的这两条
- 等 CF 后台显示 Active(几分钟到 24 小时不等)
登录 VPS
大多数厂商给的是 root 密码:
ssh root@你的VPS的IP
有的厂商(如甲骨文、AWS)不给 root 密码,而是用建机时下载的私钥文件 + 默认用户名(Ubuntu 镜像一般是 ubuntu):
ssh -i 私钥文件路径 ubuntu@你的VPS的IP sudo -i
- 第一次连接会问 yes/no,输入
yes回车 - 用私钥登录的,先执行
sudo -i切到 root。下文所有命令都在 root 下执行 - 粘贴命令:终端里一般是右键或 Ctrl+Shift+V,不是 Ctrl+V
- VPS 的 IP 已经被墙、SSH 连不上:先开着别的代理再连
检查两处:厂商后台、系统防火墙
开放 80 / 443 端口
端口没开,后面全白做,CF 会报 522。要检查两个地方。
检查 1:厂商网页后台的防火墙 / 安全组
很多厂商默认全开,不用管。有「安全组」「防火墙规则」这类设置的,添加入站规则:TCP,端口 80 和 443,来源 0.0.0.0/0。
检查 2:系统里的防火墙
大多数 VPS 的系统里默认没有防火墙,不用管。执行 ufw status:
inactive 或提示找不到命令跳过active执行下面两行ufw allow 80/tcp ufw allow 443/tcp
甲骨文(Oracle Cloud):两道防火墙都要开
甲骨文有两层防火墙,漏掉任何一层都会连不上,这是甲骨文上最常见的坑。
第 1 道:网页后台的安全列表
实例详情 → 点「子网」→ 安全列表(Security Lists)→ 默认安全列表 → 添加入站规则
0.0.0.0/080,443第 2 道:系统里的 iptables
甲骨文的 Ubuntu 镜像自带一套 iptables 规则,默认只放行 22 端口。执行:
iptables -I INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT netfilter-persistent save
开端口只用上面这两行命令。甲骨文自己用 iptables 管防火墙,再开 ufw 两套会打架,SSH 可能直接连不上,只能去网页后台的控制台救(甲骨文社区有这类记录)。照着网上别的教程敲 ufw enable 就会碰到。
- 建实例时把镜像从默认的 Oracle Linux 换成 Ubuntu,ARM 和 AMD 都行
- 刚开机时
apt可能提示被占用(系统在自动更新),等几分钟再继续
改 4 个地方,拿到 15 年有效的源站证书
Cloudflare 后台设置
在 CF 后台改 4 个地方,最后拿到一张 15 年有效、不用续签的源站证书。CF 界面偶尔改版,按名字找即可。
-
添加解析
DNS → Records → Add record
Type
ANamenode(节点域名就是node.你的域名,下文用node.example.com举例)IPv4 address你的 VPS IPProxy status橙色云朵打开(Proxied),这是整套方案的核心 - SSL 模式 SSL/TLS → Overview → 选 Full (strict)(完全(严格))
- WebSockets Network → 确认 WebSockets 是开启状态(默认就是开的)
-
生成源站证书
SSL/TLS → Origin Server → Create Certificate
- 选项保持默认(RSA,包含
*.你的域名和你的域名,有效期 15 年)→ Create - 页面上会出现两段文本:Origin Certificate(证书)和 Private Key(私钥)
两段都复制到电脑记事本里保存好。私钥只显示这一次,关掉页面就看不到了。
- 选项保持默认(RSA,包含
浏览器打开 https://dns.google/resolve?name=node.example.com&type=A(换成你的域名)。返回 104. 或 172. 开头的 IP 就对了;返回的是 VPS 自己的 IP,说明橙云没开。
- 有效期 15 年,不用续签
- 不需要从外网验证服务器,VPS 的 IP 被墙了也能装
- 不用创建 API 令牌,少一个泄露点
它只在 CF 和 VPS 之间使用,客户端看到的仍然是 CF 的正规证书。代价见「常见问题」最后一条。
装软件、放证书、开 BBR
VPS 基础环境与证书
安装软件
apt update && apt install -y curl nginx openssl nano rm -f /etc/nginx/sites-enabled/default
第二行删掉 Nginx 自带的默认站点,避免和我们的配置冲突。
放入证书
mkdir -p /etc/ssl/cf nano /etc/ssl/cf/origin.pem
会打开一个编辑器。把记事本里的 Origin Certificate 整段粘贴进去(从 -----BEGIN CERTIFICATE----- 到 -----END CERTIFICATE-----),然后保存退出:Ctrl+O → 回车 → Ctrl+X。
用同样的方法放私钥:
nano /etc/ssl/cf/origin.key粘贴 Private Key 整段,同样 Ctrl+O → 回车 → Ctrl+X。然后执行:
chmod 600 /etc/ssl/cf/origin.key openssl x509 -in /etc/ssl/cf/origin.pem -noout -subject -enddate
第二条能打印出 CloudFlare 字样和一个十几年后的日期,就说明证书放对了。报错的话,重新打开文件,检查有没有粘贴完整。
开启 BBR(建议)
echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf sysctl -p
全文唯一要你改的地方在这一步
安装并配置 Xray
安装
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install
设置变量全文唯一需要你改的地方
把第一行的 node.example.com(下面橙色框住的部分)换成你在第二步设置的节点域名,然后整段粘贴:
DOMAIN=node.example.com UUID=$(xray uuid) WSPATH=/api/v3/$(openssl rand -hex 8) cat > /root/node-info.txt <<EOF DOMAIN=$DOMAIN UUID=$UUID WSPATH=$WSPATH EOF cat /root/node-info.txt
屏幕上会显示你的域名、UUID 和路径,它们已经保存在 /root/node-info.txt。
先执行 sudo -i(root 登录的跳过),再执行 source /root/node-info.txt 把变量找回来,然后继续。
生成 Xray 配置
cat > /usr/local/etc/xray/config.json <<EOF { "log": { "loglevel": "warning" }, "inbounds": [ { "listen": "127.0.0.1", "port": 10000, "protocol": "vless", "settings": { "clients": [ { "id": "$UUID" } ], "decryption": "none" }, "streamSettings": { "network": "ws", "wsSettings": { "path": "$WSPATH" } } } ], "outbounds": [ { "protocol": "freedom" } ] } EOF xray run -test -config /usr/local/etc/xray/config.json
最后一行输出 Configuration OK。
配置里的几处要点
listen: 127.0.0.1Xray 只在本机监听,外网扫描不到,所有流量必须经过 Nginxdecryption: none保持这样,不要开启 VLESS Encryption(vlessenc)。它本身能过 CDN,但两端必须配得一模一样,而且不少客户端还不支持,新手开了容易连不上flow不要加 flow: xtls-rprx-vision,Vision 流控不能跑在普通 WebSocket 上普通访问看到网页,带正确路径的才转给 Xray
配置 Nginx 反代与伪装页
Nginx 对外监听 443:普通访问看到的是一个普通网页,只有带正确路径的 WebSocket 请求才会转给 Xray。
伪装页
echo '<!doctype html><title>Welcome</title><h1>Welcome</h1><p>Site under construction.</p>' > /var/www/html/index.html
想更像真网站,可以换成任何静态网页模板,放进 /var/www/html/。
生成 Nginx 配置
cat > /etc/nginx/conf.d/xray.conf <<EOF server { listen 80; server_name $DOMAIN; return 301 https://\$host\$request_uri; } server { listen 443 ssl; server_name $DOMAIN; ssl_certificate /etc/ssl/cf/origin.pem; ssl_certificate_key /etc/ssl/cf/origin.key; ssl_protocols TLSv1.2 TLSv1.3; root /var/www/html; index index.html; location $WSPATH { if (\$http_upgrade != "websocket") { return 404; } proxy_pass http://127.0.0.1:10000; proxy_http_version 1.1; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host \$host; proxy_read_timeout 300s; } } EOF nginx -t
输出 syntax is ok 和 test is successful。
- 命令里的
\$是故意的,不要删,否则 Nginx 变量会被 shell 吃掉 nginx -t如果报某条指令is duplicate,说明同一条指令写了两次,删掉其中一行即可
加固:直接用 IP 访问时拒绝握手
现在有人直接访问 https://你的VPS的IP,Nginx 会亮出带你域名的证书。网络扫描站会把这些记下来,等于公开了「这个 IP 就是这个域名的源站」,CF 帮你藏的 IP 就白藏了。
加一个兜底站点:没带对域名的连接,一律拒绝握手。
cat > /etc/nginx/conf.d/00-default.conf <<EOF server { listen 443 ssl default_server; ssl_reject_handshake on; } EOF nginx -t
看 nginx -t 的输出:
test is successful完成unknown directive "ssl_reject_handshake"Nginx 版本太老(Ubuntu 22.04 自带的就是),执行下面这段代替openssl req -x509 -nodes -newkey rsa:2048 -days 3650 -subj "/CN=localhost" \ -keyout /etc/ssl/cf/default.key -out /etc/ssl/cf/default.pem cat > /etc/nginx/conf.d/00-default.conf <<EOF server { listen 443 ssl default_server; ssl_certificate /etc/ssl/cf/default.pem; ssl_certificate_key /etc/ssl/cf/default.key; return 444; } EOF nginx -t
这段给兜底站点配一张写着 localhost 的假证书,连接进来后直接断开,同样看不到你的域名。
挡的是「扫 IP 看证书」。挡不住「拿着你的域名挨个 IP 去试」,要连这个也挡,做进阶里的「源站只放行 CF 的 IP」。
把 listen 443 ssl; 改成 listen 8443 ssl;(兜底站点 00-default.conf 里的 443 也一起改),第一步的防火墙也放行 8443,客户端端口也改成 8443。
CF 支持的 HTTPS 端口:44320532083208720968443
三个测试:链路全通,且直接访问 IP 被拒
启动与验证
systemctl enable --now xray nginx systemctl restart xray nginx systemctl status xray nginx --no-pager
两个服务都显示绿色的 active (running)。
测试 1:伪装页能打开
curl -sI https://$DOMAIN | head -n 5
看到 200 和 server: cloudflare。也可以直接用浏览器打开 https://你的节点域名,能看到 Welcome 页面。
测试 2:WebSocket 能通到 Xray
curl -s -i --http1.1 --max-time 5 \ -H "Connection: Upgrade" -H "Upgrade: websocket" \ -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==" \ https://$DOMAIN$WSPATH | head -n 1
看到 101 Switching Protocols,就说明 CF → Nginx → Xray 整条链路全通,可以去配客户端了。
测试 3:直接访问 IP 被拒绝
curl -sk -o /dev/null -w '%{http_code}\n' https://127.0.0.1 curl -sk -o /dev/null -w '%{http_code}\n' --resolve $DOMAIN:443:127.0.0.1 https://$DOMAIN
第一行输出 000(不带域名,握手被拒,什么都没拿到),第二行输出 200(带对域名,照常打开伪装页)。第一行如果也是 200,说明兜底站点没生效,回第五步的加固检查。
出问题时看日志
journalctl -u xray -n 50 --no-pager tail -n 50 /var/log/nginx/error.log
错误码对照见「常见问题排查」。
下一步:生成链接并导入客户端 →一条命令生成 vless:// 链接
生成链接并导入客户端
在 VPS 上一条命令生成节点链接:
source /root/node-info.txt echo "vless://${UUID}@${DOMAIN}:443?encryption=none&security=tls&sni=${DOMAIN}&fp=chrome&type=ws&host=${DOMAIN}&path=$(echo "$WSPATH" | sed 's#/#%2F#g')#CF-WS"
输出的那一整行 vless://... 就是节点链接,复制到客户端里「从剪贴板导入」即可。用 8443 的话,把链接里的 :443 改成 :8443。
v2rayN、Clash Verge Rev复制链接 → 从剪贴板导入
Clash Verge Rev、v2rayN复制链接 → 从剪贴板导入
v2rayNG、FlClash右上角 + → 从剪贴板导入
Shadowrocket、Stash(需外区 Apple ID)复制链接后打开 App 会自动识别
手动填写对照表
Clash / Mihomo 配置写法
- name: CF-WS type: vless server: node.example.com port: 443 uuid: 你的UUID udp: true tls: true servername: node.example.com client-fingerprint: chrome network: ws ws-opts: path: /api/v3/你的路径 headers: Host: node.example.com
server(地址)以后可以换成优选 IP,但 servername(SNI)和 Host 永远填你的域名,不能填 IP。
嫌慢,或想藏得更深
进阶(可选)
优选 Cloudflare IP
节点能用但嫌慢,或者出现「ping 得通、连不上」(有的地区、时段运营商会掐 CF 的部分 IP),可以用 CloudflareSpeedTest 从 CF 的众多 IP 里挑出你本地连得最快的那个,填进客户端的「地址」。
- 在 GitHub 搜
XIU2/CloudflareSpeedTest,下载对应系统的版本(新版程序名是cfst,旧版叫CloudflareST) - 在你自己的电脑上运行(不是 VPS 上),因为要测的是你本地到 CF 的速度
- 把结果
result.csv里排第一的 IP 填进客户端的「地址」,SNI 和 Host 保持域名不变
测速前必须关掉所有代理 / VPN,否则测出来的是代理线路的速度。
# 节点用 443 端口 ./cfst -tp 443 -dn 10 # 节点用 8443 端口 ./cfst -tp 8443 -dn 10
- 用 8443 时不要加
-f导入网上收集的反代 IP 列表,那些 IP 基本只开 443 - 想看下载速度就不要加
-httping,加了测不出下载速度 - 优选 IP 会随时间变化,变慢了就重新测一次
- 晚上某个网段突然大面积超时,换一个不同网段的 IP 再测
- 优选 IP 正是 CF 条款禁止的用法(见开头的说明),这也是建议节点单独用一个 CF 账号的原因
源站只放行 CF 的 IP
第一步里 443 对所有人开放。改成只放行 CF 的 IP 段后,别人直接扫你 VPS 的 IP,什么都看不到。
- 在厂商后台的安全组(甲骨文是安全列表)里,把 443 规则的来源从
0.0.0.0/0换成 CF 的 IPv4 段,一段一条规则 - CF 的 IP 段列表:
https://www.cloudflare.com/ips-v4 - 22 端口(SSH)的规则别动
- 做了这一步,下面「常见问题」里的灰云直连退路也会失效,需要时得先把规则改回来
- 本文的 Nginx 只监听 IPv4,所以只放 IPv4 段就够。如果你自己给 Nginx 加了 IPv6 监听(
listen [::]:443),CF 的 IPv6 段https://www.cloudflare.com/ips-v6也要加上,否则 IPv6 这条路没被拦住 - CF 的 IP 段很少变动,但以官网列表为准,隔几个月核对一次
先看浏览器里 CF 给的错误码
常见问题排查
浏览器打开节点域名时,CF 给出的错误码基本就能定位问题在哪一段。
- 原因
- CF 连不到 VPS。九成是第一步的端口没开(甲骨文是两道防火墙漏了一道)
- 处理
- 回第一步逐项核对;再用下面的 tcpdump 方法
- 原因
- Nginx 没在运行
- 处理
systemctl status nginx,按报错修好后systemctl restart nginx
- 原因
- Nginx 证书没配好,或没监听
443 ssl - 处理
nginx -t;检查第三步的证书文件是否完整
- 原因
- 源站证书不对
- 处理
- 确认用的是 CF Origin 证书,且节点域名在证书范围内
- 原因
- Xray 没运行,或端口对不上
- 处理
systemctl status xray;确认两边都是 10000
- 原因
- SNI 或 Host 写的不是节点域名本身
- 处理
- 对照第七步重新填
- 原因
- 浏览器不带 WebSocket 升级头,被 Nginx 挡掉了
- 处理
- 不用处理
- 原因
- UUID / 路径填错;SNI 或 Host 填成了 IP;开了 vision 流控
- 处理
- 重新生成第七步的链接导入
- 原因
- CF 线路晚高峰拥堵,或运营商限速 CF
- 处理
- 做「优选 IP」
- 原因
- 运营商在掐 CF
- 处理
- 先优选 IP、换端口;还不行,见灰云直连退路
- 原因
- 域名被 DNS 污染,解析到一个墙内打不开的 IP
- 处理
- 客户端「地址」直接填一个 CF 的 IP(见「优选 IP」),SNI 和 Host 保持域名
522 排查:流量到底有没有进来
tcpdump -ni any tcp port 443
运行后用浏览器访问几次节点域名:
按 Ctrl+C 停止。没有 tcpdump 就先 apt install -y tcpdump。
想保留灰云直连退路,就改用 acme.sh
源站证书只有 CF 认。遇到运营商掐 CF、优选 IP 也救不回来时,可以把 CF 里的橙云临时关成灰云,让客户端直连 VPS。但用的是源站证书的话,客户端会因为证书不受信任而连不上。换成 Let's Encrypt 证书,橙云、灰云都能用。
先在 CF:我的个人资料 → API 令牌 → 创建令牌,权限选 Zone:DNS:Edit,作用域只选这个域名。然后在 VPS 上:
source /root/node-info.txt curl https://get.acme.sh | sh -s email=you@example.com source ~/.bashrc ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt export CF_Token="你的令牌" ~/.acme.sh/acme.sh --issue --dns dns_cf -d $DOMAIN --keylength ec-256 ~/.acme.sh/acme.sh --install-cert -d $DOMAIN --ecc \ --fullchain-file /etc/ssl/cf/origin.pem \ --key-file /etc/ssl/cf/origin.key \ --reloadcmd "systemctl reload nginx"
令牌不要发给任何人,也不要贴进聊天。
- 证书直接覆盖原来的两个文件,Nginx 配置不用改。证书 90 天有效,acme.sh 会自动续期
- 灰云时 VPS 的 IP 直接暴露,只当临时退路。VPS 的 IP 已经被墙的话,灰云也没用
六件不要做的事,四条维护命令
不要做的事与日常维护
不要做
- 不要把 CF 的 SSL 模式设成 Flexible(灵活):CF 到 VPS 这一段会变成明文
- 不要开 VLESS Encryption,也不要加 vision 流控(理由见第四步)
- 不要把 Xray 改成监听
0.0.0.0:外网会直接扫到它 - 不要把节点链接、域名、服务器 IP 晒到群里或网上。要给家人朋友用,就在
clients里再加一个{ "id": "另一个UUID" }(用xray uuid生成),每人一个。如果发截图,一定要打码自己的 VPS IP - WS 路径别用
/ws、/v2ray、/vless这种烂大街的(本文脚本已自动生成随机路径) - 不要拿放着重要网站的 CF 账号和域名搭节点:CF 条款不允许代理用途(见开头的说明),账号被停用会连累同账号下的其他网站。单独注册一个账号、买一个便宜域名专门用
日常维护
systemctl restart xrayapt update && apt upgrade -ysystemctl restart xray nginxcat /root/node-info.txt/root/node-info.txt 里存着节点的全部信息,建议另外在自己电脑上保存一份。