ENZH
和 AI 讨论这篇文章
ChatGPTClaude

从零搭梯子,这份手册扔给 claude code 直接跑

自建代理服务架构蓝图自建代理服务架构蓝图

这个系列是什么:一份完整的技术 runbook,直接扔给 claude code 就能跑。把手册复制走,占位符(YOUR_VPS_IP、your.domain.com 这些)换成你自己的,发给 agent,让它按步骤执行。背后的故事在实战录同名篇。

自建代理,从零到能用

这份手册把自建代理的完整流程走了一遍:VPS 怎么选、协议怎么配、证书怎么申、订阅服务器怎么搭,最后到客户端配置。每一步都是能直接跑的命令,也都是我自己在机器上实际跑过的。你可以自己照着做,也可以整份扔给 agent 让它执行,反正占位符换掉就行。


目录

  1. VPS 选择与初始配置
  2. 第一个坑:shadowsocks 几小时就被封
  3. sing-box 多协议部署
  4. BBR 网络加速
  5. SSL 证书申请与配置
  6. 订阅服务器搭建(nginx)
  7. 节点名称整理
  8. Clash Verge 客户端配置(macOS)
  9. 踩坑记录
  10. 验证清单

1. VPS 选择与初始配置

1.1 选 VPS 看什么

选 VPS 我一般看四个东西。这四个直接决定后面封不封、快不快,别的参数都是次要的。

  • IP 质量:静态住宅 IP(residential IP)比数据中心 IP 难封得多。Atlas Networks 有西雅图和洛杉矶的住宅 IP,可以考虑。
  • 线路质量:从国内连美国,线路首选 9929(AS9929)和 CN2 GIA,延迟低,还能绕开骨干网的拥堵。普通的 AS4837 就差很多。
  • 带宽和月流量:至少 100Mbps,月流量 1TB 起步。
  • SSH 端口:有些服务商默认给的不是标准端口,记得看开机邮件。

我这台的配置在下面这张表里。后面所有命令都是在这台机器上跑出来的,你照着做的时候,把 IP 和端口换成自己的就行。

参数值
服务商Atlas Networks
位置洛杉矶,9929 网络
IPYOUR_VPS_IP
SSH 端口YOUR_SSH_PORT
系统Ubuntu 24.04.1 LTS
月流量限额3TB

1.2 初始 SSH 登录

ssh root@YOUR_VPS_IP -p YOUR_SSH_PORT

登录进去先把基础的东西弄好。更新系统、装常用工具、把时区统一设成 UTC,都是一次性的活,一分钟跑完:

# 更新系统
apt-get update && apt-get upgrade -y

# 安装常用工具
apt-get install -y curl wget vim git unzip net-tools

# 设置时区为 UTC(保持一致性)
timedatectl set-timezone UTC

# 确认系统版本
lsb_release -a

1.3 安全加固(推荐)

# 修改 SSH 配置,禁用密码登录(建议先配好公钥再操作)
vim /etc/ssh/sshd_config
# 确保以下两行存在:
# PasswordAuthentication no
# PubkeyAuthentication yes

# 重启 SSH 服务
systemctl restart sshd

# 开启防火墙(ufw),只放行需要的端口
ufw allow YOUR_SSH_PORT/tcp   # SSH
ufw allow 80/tcp      # HTTP(acme 验证 / nginx)
ufw allow 443/tcp     # HTTPS(nginx)
ufw allow 16796/tcp   # VLESS-Reality
ufw allow 18877/udp   # Hysteria2
ufw allow 31227/udp   # TUIC-v5
ufw allow 2082/tcp    # Vmess-WS(可选)
ufw enable
ufw status

VPS 服务商的坑:有些服务商默认把 PubkeyAuthentication 关掉了。如果公钥已经复制上去,密钥还是登不进,先查这个:

grep PubkeyAuthentication /etc/ssh/sshd_config
# 如果显示 "no",改掉:
sed -i 's/^PubkeyAuthentication no/PubkeyAuthentication yes/' /etc/ssh/sshd_config
systemctl restart sshd

2. 第一个坑:shadowsocks 几小时就被封

2.1 当时怎么部署的

最开始我的想法很简单:用 docker 跑一个 shadowsocks-rust,能用就行。当时的命令是这样的:

docker run -d \
  --name ss-rust \
  --restart always \
  -p 8388:8388/tcp \
  -p 8388:8388/udp \
  -e PASSWORD="your_password" \
  ghcr.io/shadowsocks/ssserver-rust:latest \
  ssserver -s "0.0.0.0:8388" -m "aes-256-gcm" -k "your_password" --udp-only false

配置参数:

  • 端口:8388
  • 加密方式:aes-256-gcm

2.2 结果

没过几个小时,IP 就被 GFW 封了。连端口直接超时,从国内完全连不上。

2.3 为什么被封

Shadowsocks(还有没做混淆的 VMess、普通 Socks5)是「裸协议」。GFW 的流量探针会这么干:

  1. 往可疑端口主动发探测包
  2. 算流量的熵值(加密流量的熵值很高)
  3. 看流量特征,认出是哪种代理协议
  4. 封掉这个 IP 的端口,甚至整个 IP

GFW 靠主动探测和熵值分析封杀裸协议,而 VLESS-Reality 伪装成正常 HTTPS 流量绕过识别GFW 靠主动探测和熵值分析封杀裸协议,而 VLESS-Reality 伪装成正常 HTTPS 流量绕过识别

反正结论就一条,给国内用的 IP 不能裸跑 SS/VMess/Socks5,必须换成能混淆流量的新协议。所以下一节换成了 sing-box。


3. sing-box 多协议部署

3.1 为什么选 sing-box

sing-box 是目前最成熟的多协议代理内核,支持:

  • VLESS + Reality:借真实网站的 TLS 指纹,GFW 分不出这是代理还是正常的 HTTPS,很难被封
  • Hysteria2:跑在 QUIC/UDP 上,速度快,适合带宽大的场景
  • TUIC v5:也跑在 UDP 上,延迟低

3.2 一键脚本安装

# 一键安装
bash <(wget -qO- https://raw.githubusercontent.com/yonggekkk/sing-box-yg/main/sb.sh)

脚本第一次跑完会存到 /root/sb.sh,之后直接敲 sb 这个快捷命令就能进管理菜单。

3.3 安装过程

脚本跑起来会出一个菜单。先选 1(安装),然后按 Enter 用默认配置就行。脚本会自己做完这几件事:

  • 安装 sing-box 服务
  • 生成 5 个协议的配置
  • 写入 systemd 服务
  • 启动服务

注意:sing-box 的安装脚本装着装着,可能会把 ufw 删掉。如果你装之前配了防火墙规则,装完得看看规则还在不在。iptables 默认策略是 ACCEPT(等于没有防火墙),只跑代理的 VPS 这样也能接受,但别忘了查一下。

3.4 5 个协议一览

协议默认端口传输层抗封性备注
VLESS-Reality-Vision(随机)TCP★★★★★首选,伪装成 HTTPS 流量
Vmess-WebSocket(随机)TCP★★最弱,不建议日常用
Hysteria2(随机)UDP★★★★速度最快
TUIC-v5(随机)UDP★★★★低延迟
Anytls(随机)TCP★★★★TLS 伪装,较新协议

注意:脚本每次装都会随机分端口,别照搬旧教程里的端口号。装完看输出,确认实际用的是哪个端口。

3.5 查看配置文件

# 所有配置文件在此
ls /etc/s-box/

# Clash Mihomo 客户端配置(包含所有节点)
cat /etc/s-box/clmi.yaml

# sing-box 客户端配置
cat /etc/s-box/sbox.json

3.6 验证服务状态

# 查看 sing-box 服务状态
systemctl status sing-box

# 查看实时日志
journalctl -u sing-box -f

# 确认 TCP 端口监听
ss -tlnp | grep -E "16796|2082"

# Hysteria2 和 TUIC 是 UDP,用 -u
ss -ulnp | grep -E "18877|31227"

3.7 常用管理命令

# 启动/停止/重启
systemctl start sing-box
systemctl stop sing-box
systemctl restart sing-box

# 查看服务端配置
cat /etc/s-box/sb.json

# 进入管理菜单
sb

4. BBR 网络加速

BBR 是 Google 做的 TCP 拥塞控制算法,开了以后跨国连接能快不少。Linux 4.9+ 的内核已经自带,打开就行。

4.1 通过脚本启用

# 进入管理菜单
sb

# 选择选项 11(BBR 加速)

4.2 手动启用

# 检查内核版本(必须 >= 4.9)
uname -r

# 编辑 sysctl 配置
cat >> /etc/sysctl.conf << 'EOF'
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
EOF

# 应用
sysctl -p

# 验证
sysctl net.ipv4.tcp_congestion_control
# 应该输出:net.ipv4.tcp_congestion_control = bbr

# 确认 BBR 模块已加载
lsmod | grep bbr

5. SSL 证书申请与配置

Reality 协议本身用不着 SSL 证书,但 Hysteria2 和 TUIC 要,nginx 订阅服务器也得走 HTTPS,所以证书这一步逃不掉。

5.1 DNS 配置

在 Cloudflare 给域名加一条 A 记录:

类型: A
名称: sub(或你想要的子域名)
IPv4 地址: YOUR_VPS_IP
代理状态: 仅 DNS(灰色云朵)— 初始证书申请用

灰云和橙云得在对的时候切。第一次申请 SSL 证书时用灰色云朵(仅 DNS),等订阅服务器配好了(第 6 节),再改成橙色云朵(开 Cloudflare 代理)。原因大概是这样:

  1. 国内用户没法直接连 VPS IP 去拿订阅 URL
  2. Cloudflare CDN 在国内连得上,可以帮忙中转订阅请求
  3. 代理连接(VLESS、Hysteria2、TUIC 等)用的是配置文件里硬编码的 VPS IP,不走域名,所以开不开 Cloudflare 代理都没关系
  4. 只有订阅的 HTTP 请求走 Cloudflare,实际的代理流量直连 VPS

订阅的 HTTP 请求走 Cloudflare CDN 中转,代理流量则直连配置里硬编码的 VPS IP,两条路径互不干扰订阅的 HTTP 请求走 Cloudflare CDN 中转,代理流量则直连配置里硬编码的 VPS IP,两条路径互不干扰

简单说:申请证书时用灰色云朵 → 订阅服务器配好后改成橙色云朵。代理协议直连 IP,不受影响。

5.2 获取 Cloudflare API Token

  1. 登录 Cloudflare Dashboard
  2. 我的个人资料 → API 令牌 → 创建令牌
  3. 用模板:编辑区域 DNS
  4. 区域资源:选你的域名
  5. 创建并保存 Token(只显示一次)

5.3 安装 acme.sh

# 安装(如果 sb.sh 还没装的话)
curl https://get.acme.sh | sh -s email=your@email.com

# 激活环境变量
source ~/.bashrc
# 或直接用完整路径
~/.acme.sh/acme.sh --version

5.4 清理 acme.sh 缓存(重要!)

这里有个坑,卡了我不少时间。sb.sh 跑的时候会调 acme.sh,往账户缓存里写进一个错的邮件地址。不清掉的话,后面申请证书会一直报错:

# 清理错误的账户缓存
rm -rf ~/.acme.sh/ca/ ~/.acme.sh/*.json

# 确认清理完毕
ls ~/.acme.sh/

5.5 申请证书

# 设置 Cloudflare API Token
export CF_Token="你的Cloudflare_API_Token"

# 申请 ECC 证书(比 RSA 更小更快)
~/.acme.sh/acme.sh --issue \
  --dns dns_cf \
  -d your.domain.com \
  --ecc \
  --server letsencrypt \
  --accountemail "your@gmail.com" \
  --force

# 完成后显示证书路径,类似:
# /root/.acme.sh/your.domain.com_ecc/your.domain.com.cer
# /root/.acme.sh/your.domain.com_ecc/your.domain.com.key
# /root/.acme.sh/your.domain.com_ecc/fullchain.cer

参数说明:

  • --dns dns_cf:用 Cloudflare DNS API 验证,不用开 80 端口
  • --ecc:椭圆曲线证书
  • --server letsencrypt:Let's Encrypt CA
  • --force:强制重新申请

5.6 安装证书到指定路径

# 创建目标目录
mkdir -p /root/ygkkkca

# 安装证书,设置自动重载
~/.acme.sh/acme.sh --install-cert \
  -d your.domain.com \
  --ecc \
  --cert-file /root/ygkkkca/cert.crt \
  --key-file /root/ygkkkca/private.key \
  --fullchain-file /root/ygkkkca/fullchain.crt \
  --reloadcmd "systemctl restart sing-box"

这一步顺便把自动续期也设好了。证书到期前 30 天,acme.sh 会自己去申请新证书,再跑 --reloadcmd 把服务重启。

5.7 复制证书到 sing-box 目录

# 复制到 sing-box 读取的路径
cp /root/ygkkkca/fullchain.crt /etc/s-box/cert.pem
cp /root/ygkkkca/private.key /etc/s-box/private.key

# 设置权限
chmod 600 /etc/s-box/private.key

# 重启 sing-box
systemctl restart sing-box

# 验证
systemctl status sing-box

5.8 验证证书

# 查看证书信息
openssl x509 -in /root/ygkkkca/fullchain.crt -noout -text | grep -E "Subject:|Not After"

# 查看 acme.sh 管理的证书列表
~/.acme.sh/acme.sh --list

6. 订阅服务器搭建(nginx)

搭订阅服务器就是图省事。用 nginx 给出一个订阅 URL,Clash/sing-box 客户端点一下就能更新,不用每次手动改节点配置。

先确认 80/443 没被运营商封:有些机房默认在网络边缘把进来的 80/443 丢掉,只放行高位端口。这时候 nginx 在本地 listen 443 一切正常,从外网就是连不上。所以配好以后一定要从外面测一次(详见坑 12)。如果 443 被封了,就把订阅服务器挪到一个放行的高位端口,订阅 URL 带上端口就行。代理协议走的是自己的高位端口,不受影响。

6.1 安装 nginx

apt-get install -y nginx

# 启动并设置开机自启
systemctl enable nginx
systemctl start nginx
systemctl status nginx

6.2 生成随机订阅 Token

Token 就是订阅 URL 的路径,相当于密码。别人不知道这个路径,就拿不到你的配置:

# 生成 16 位随机 token
TOKEN=$(cat /proc/sys/kernel/random/uuid | tr -d "-" | head -c 16)
echo "你的 Token 是: $TOKEN"

# 保存 token
echo $TOKEN > /etc/s-box/.sub_token
cat /etc/s-box/.sub_token

6.3 修正 Clash 配置文件

用 nginx 发配置之前,先把证书验证的设置改对。打开 Clash Mihomo 的客户端配置:

# 编辑 Clash Mihomo 客户端配置
vim /etc/s-box/clmi.yaml

找到这几行改掉:

# 修改前:
skip-cert-verify: true

# 修改后:
skip-cert-verify: false

# 同时找到 sni 字段,改为你的真实域名:
sni: your.domain.com

用 sed 批量替换更省事:

# 关闭跳过证书验证
sed -i 's/skip-cert-verify: true/skip-cert-verify: false/g' /etc/s-box/clmi.yaml

# 检查
grep "skip-cert-verify" /etc/s-box/clmi.yaml

6.4 配置 nginx

TOKEN=$(cat /etc/s-box/.sub_token)

cat > /etc/nginx/sites-available/sub << EOF
server {
    listen 80;
    listen 443 ssl;
    server_name your.domain.com;

    ssl_certificate /root/ygkkkca/fullchain.crt;
    ssl_certificate_key /root/ygkkkca/private.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location /${TOKEN} {
        alias /etc/s-box/clmi.yaml;
        default_type "text/plain; charset=utf-8";
    }

    location /singbox/${TOKEN} {
        alias /etc/s-box/sbox.json;
        default_type "application/json; charset=utf-8";
    }

    location / {
        return 404;
    }
}
EOF

6.5 启用站点

# 创建软链接
ln -sf /etc/nginx/sites-available/sub /etc/nginx/sites-enabled/sub

# 删除默认站点(避免冲突)
rm -f /etc/nginx/sites-enabled/default

# 测试配置
nginx -t

# 重载
systemctl reload nginx

6.6 流量统计

只要订阅响应里带上 Subscription-Userinfo 这个头,Clash 和 sing-box 客户端就能显示上传/下载用了多少、还剩多少额度。这一节就是把这个头配出来。

安装 vnstat

apt-get install -y vnstat
systemctl enable vnstat
systemctl start vnstat

# 查看网卡名称——别照抄教程里的 ens3
ip -o -4 route show to default | awk '{print $5}'
# 较新的 Ubuntu/KVM 镜像多是 ens17,老的才是 ens3/eth0。以实际输出为准

创建流量统计脚本

cat > /etc/s-box/update_traffic.sh << 'SCRIPT'
#!/bin/bash
IFACE="ens17"  # 替换为你的网卡名(先用上面的 ip route 命令确认,别想当然填 ens3)
MONTHLY_LIMIT_GB=3000  # 月流量限额(GB),3000 = 3TB
MONTHLY_LIMIT_BYTES=$((MONTHLY_LIMIT_GB * 1073741824))

STATS=$(vnstat -i "$IFACE" --json m 2>/dev/null)

if [ -z "$STATS" ]; then
    UPLOAD=0
    DOWNLOAD=0
else
    UPLOAD=$(echo "$STATS" | python3 -c "
import sys, json
data = json.load(sys.stdin)
months = data.get('interfaces', [{}])[0].get('traffic', {}).get('month', [])
print(months[-1].get('tx', 0) if months else 0)
" 2>/dev/null || echo 0)
    DOWNLOAD=$(echo "$STATS" | python3 -c "
import sys, json
data = json.load(sys.stdin)
months = data.get('interfaces', [{}])[0].get('traffic', {}).get('month', [])
print(months[-1].get('rx', 0) if months else 0)
" 2>/dev/null || echo 0)
fi

EXPIRE=$(date -d "$(date +%Y-%m-01) +1 month" +%s 2>/dev/null || date -d "next month" +%s)

cat > /etc/s-box/.traffic_header.conf << EOF
add_header Subscription-Userinfo "upload=${UPLOAD}; download=${DOWNLOAD}; total=${MONTHLY_LIMIT_BYTES}; expire=${EXPIRE}";
EOF
SCRIPT

chmod +x /etc/s-box/update_traffic.sh
bash /etc/s-box/update_traffic.sh

设置定时任务

# 每 5 分钟更新一次
(crontab -l 2>/dev/null; echo "*/5 * * * * /bin/bash /etc/s-box/update_traffic.sh > /dev/null 2>&1") | crontab -

更新 nginx 配置

在每个订阅 location 块里加 include /etc/s-box/.traffic_header.conf;:

TOKEN=$(cat /etc/s-box/.sub_token)

cat > /etc/nginx/sites-available/sub << EOF
server {
    listen 80;
    listen 443 ssl;
    server_name your.domain.com;

    ssl_certificate /root/ygkkkca/fullchain.crt;
    ssl_certificate_key /root/ygkkkca/private.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location /${TOKEN} {
        alias /etc/s-box/clmi.yaml;
        default_type "text/plain; charset=utf-8";
        add_header Content-Disposition "inline";
        include /etc/s-box/.traffic_header.conf;
    }

    location /singbox/${TOKEN} {
        alias /etc/s-box/sbox.json;
        default_type "application/json; charset=utf-8";
        include /etc/s-box/.traffic_header.conf;
    }

    location / {
        return 404;
    }
}
EOF

nginx -t && systemctl reload nginx

客户端刷新一下订阅,就能看到流量用量的进度条了。

6.7 验证订阅 URL

TOKEN=$(cat /etc/s-box/.sub_token)
echo "Clash 订阅 URL: https://your.domain.com/${TOKEN}"
echo "Sing-box 订阅 URL: https://your.domain.com/singbox/${TOKEN}"

# 本地测试
curl -s "https://your.domain.com/${TOKEN}" | head -20

7. 节点名称整理

7.1 问题

sb.sh 生成的节点名后面带一串机器 ID,在客户端里看着又丑,又看不出是哪个协议:

vless-reality-vision-C20260225127975
hysteria2-C20260225127975

7.2 重命名

# 备份
cp /etc/s-box/clmi.yaml /etc/s-box/clmi.yaml.bak

# 用 sed 替换
sed -i "s/vless-reality-vision-C[0-9A-Za-z]*/⭐ VLESS-Reality 首选/g" /etc/s-box/clmi.yaml
sed -i "s/hysteria2-C[0-9A-Za-z]*/🚀 Hysteria2 快速/g" /etc/s-box/clmi.yaml
sed -i "s/tuic-C[0-9A-Za-z]*/⚡ TUIC-v5 低延迟/g" /etc/s-box/clmi.yaml
sed -i "s/vmess-ws-C[0-9A-Za-z]*/🔸 Vmess-WS 备用/g" /etc/s-box/clmi.yaml
sed -i "s/anytls-C[0-9A-Za-z]*/🔒 Anytls 隐匿/g" /etc/s-box/clmi.yaml

7.3 从自动选择组里移除 Vmess-WS

Vmess-WS 是五个协议里最弱的,容易被 GFW 认出来,不该放进自动选择组。先看一下现在的配置:

# 查看当前配置
grep -A 20 "proxy-groups" /etc/s-box/clmi.yaml | head -30

找到自动选择组:

proxy-groups:
  - name: 自动选择
    type: url-test
    proxies:
      - ⭐ VLESS-Reality 首选
      - 🚀 Hysteria2 快速
      - ⚡ TUIC-v5 低延迟
      - 🔸 Vmess-WS 备用   # 删掉这一行
    url: http://www.gstatic.com/generate_204
    interval: 300

手动编辑,把 Vmess-WS 那一行删掉:

vim /etc/s-box/clmi.yaml

改完验一下 YAML 格式没坏:

python3 -c "import yaml; yaml.safe_load(open('/etc/s-box/clmi.yaml'))" && echo "YAML 格式正确"

7.4 让修改生效

如果改的是 nginx 发出去的那份配置文件,客户端下次更新订阅就会拿到新的,不用重启 sing-box。只有改了 sing-box 自己的配置(比如端口、证书路径)才要重启:

systemctl restart sing-box
systemctl status sing-box

8. Clash Verge 客户端配置(macOS)

8.1 安装

推荐用 Clash Verge Rev 这个分支,原版已经停更了。

配置文件位置:

~/Library/Application Support/io.github.clash-verge-rev.clash-verge-rev/

8.2 导入订阅

  1. 打开 Clash Verge
  2. 点顶部 订阅
  3. 右上角 +
  4. 输入订阅 URL:https://your.domain.com/YOUR_TOKEN
  5. 点 导入
  6. 点击刚导入的配置卡片激活它(卡片有高亮边框 = 已激活)

最常见的问题是代理页只有 DIRECT 和 REJECT,看不到节点。这是配置导入了但没激活,回去再点一下配置卡片就行。

8.3 基础设置

设置项推荐值说明
系统代理开启让系统流量走 Clash
模式规则(Rule)按规则分流,国内流量不走代理
TUN 模式可选更彻底的流量接管
混合端口7897HTTP/SOCKS5 混合端口(默认)

8.4 代理组配置

代理页我推荐这么设:

  • GLOBAL:选 自动选择
  • 自动选择(url-test):放 VLESS-Reality、Hysteria2、TUIC-v5,自动测速,挑延迟最低的
  • 手动切换:想用哪个节点时自己选

8.5 连接测试

# macOS 终端
curl -x socks5://127.0.0.1:7897 https://www.google.com -I

# 或 HTTP 代理
curl -x http://127.0.0.1:7897 https://ip.me

再用浏览器打开 https://ip.me,看显示的是不是 VPS 的 IP。

8.6 更新订阅

服务端配置改了以后,在订阅页点一下配置卡片右边的刷新按钮就行。


9. 踩坑记录

下面这 13 个坑全是我自己踩过的,按现象、原因、解法记下来。遇到同样现象的话直接对着查,能省不少时间。

坑 1:SS/裸 VMess 被秒封

SS 部署完没几个小时,IP 就被封了。原因前面讲过,GFW 会主动去探可疑的端口,而 SS 的流量特征太明显。换成 VLESS-Reality 或 Hysteria2 就行。反正给国内用的 VPS,裸跑 SS/VMess 基本撑不过一天。


坑 2:acme.sh 账户缓存错误

acme.sh 申请证书报错,说邮件对不上。这是因为 sb.sh 调 acme.sh 的时候,往账户缓存里写了个错的邮件地址,把缓存清掉就好:

rm -rf ~/.acme.sh/ca/ ~/.acme.sh/*.json

清完重新申请,记得加上 --accountemail 和 --force。


坑 3:Cloudflare 橙色云朵的正确时机

申请证书时开着橙色代理,acme.sh 就验证不过。因为橙色代理会把真实 IP 藏起来,acme.sh 验证证书时就被干扰了。所以申请证书时用灰色云朵(仅 DNS),等订阅服务器配好了再改成橙色云朵,这样国内用户也能通过 Cloudflare CDN 拿到订阅。代理协议用的是配置文件里硬编码的 IP,不受影响。


坑 4:Hysteria2 和 TUIC 是 UDP

用 nc -zv 或 telnet 测端口,显示 Connection refused,可服务其实好好的。原因很简单,nc -zv 和 telnet 默认走 TCP,而 Hysteria2 和 TUIC 走的是 UDP。换成 UDP 模式测就行:

# UDP 模式测试
nc -zuv YOUR_IP 18877

# 或在服务端查看
ss -ulnp | grep -E "18877|31227"

坑 5:Clash Verge 代理页只显示 DIRECT/REJECT

导入订阅之后看不到节点,多半不是订阅坏了,是配置导入了但没激活。回到订阅页点一下配置卡片,出现高亮边框就行。


坑 6:Vmess-WS 不该放在自动选择组

自动选择偶尔会切到 Vmess-WS,它延迟高,还最容易被封。把 Vmess-WS 从 url-test 的 proxies 列表里删掉,只留 VLESS-Reality、Hysteria2、TUIC-v5 就行。


坑 7:证书路径需要手动同步

acme.sh 续期成功了,sing-box 却还在用旧证书。因为两边路径不一样,acme.sh 把证书装在 /root/ygkkkca/,sing-box 读的是 /etc/s-box/cert.pem,这两处不会自己同步。直接把复制这一步加进 reloadcmd:

~/.acme.sh/acme.sh --install-cert \
  -d your.domain.com \
  --ecc \
  --cert-file /root/ygkkkca/cert.crt \
  --key-file /root/ygkkkca/private.key \
  --fullchain-file /root/ygkkkca/fullchain.crt \
  --reloadcmd "cp /root/ygkkkca/fullchain.crt /etc/s-box/cert.pem && cp /root/ygkkkca/private.key /etc/s-box/private.key && systemctl restart sing-box"

坑 8:Clash Verge 重启后配置丢失

重启 Clash Verge 以后,手动改的设置没了。在客户端里直接改配置就会这样,一重启就可能被覆盖,这个没什么好修的。所以节点重命名和各种优化,全都放到服务端的 YAML 文件里做,再通过订阅 URL 发下去。客户端只管拉下来用,别在本地改。


坑 9:PubkeyAuthentication 被服务商关闭

公钥已经复制到 VPS 上了,密钥还是登不进去,照样让你输密码。这是因为有些 VPS 服务商默认在 sshd_config 里把 PubkeyAuthentication 关了。这样改:

grep PubkeyAuthentication /etc/ssh/sshd_config
# 如果显示 "no":
sed -i 's/^PubkeyAuthentication no/PubkeyAuthentication yes/' /etc/ssh/sshd_config
systemctl restart sshd

坑 10:sing-box 脚本会删除 ufw

装 sing-box 之前配好了 ufw,装完一跑 ufw status,直接报命令不存在,因为 sb.sh 装的时候可能把 ufw 卸掉了。所以装完要再查一遍防火墙,ufw 没了就重新装上,把规则再配一遍。如果这台 VPS 只跑代理,iptables 默认的 ACCEPT 策略也能接受。


坑 11:国内无法获取订阅 URL

国内用户手上要是没有现成的 VPN,直接连 VPS IP 是拿不到订阅文件的,因为 IP 可能被墙了,或者国内网络直接连不过去。给订阅域名开上 Cloudflare 橙色代理(CDN)就行。Cloudflare CDN 在国内连得上,可以帮忙中转订阅请求;代理配置文件里用的是直连 IP,不受影响。


坑 12:运营商在边缘封了 80/443

sing-box 的代理端口都通,订阅 URL 却怎么都打不开,在服务器上用 ss -tlnp 一看,nginx 明明在监听 80、443。原因是有些机房(实测台湾原生 IP 这类)默认在网络边缘把进来的 80/443 丢掉,只放行高位端口。本地监听一切正常,外网就是连不进来。

所以要从外面测,别只看服务器内部:

# 从你自己的机器上测,不是在服务器上(nc -G 是 macOS/BSD 的;Linux 用 -w)
for p in 443 2096 YOUR_TCP_PORT; do nc -z -G6 YOUR_VPS_IP $p && echo "$p 通" || echo "$p 被封"; done
# 注:只测 TCP。Hysteria2/TUIC 是 UDP,得用坑 4 的 nc -zuv 测

两种修法:

快的修法,是让 nginx 再多监听一个放行的高位端口(比如 2096),订阅 URL 带上端口 https://your.domain.com:2096/TOKEN。改完用 systemctl restart nginx(动了 listen 指令,restart 最稳)。代理协议走自己的高位端口,不受影响。

干净的修法我更推荐,还能顺手解决国内拉订阅的问题。拿高位端口当源站,订阅子域名开 Cloudflare 橙云,再加一条 Origin Rule,把回源端口改成 2096。这样客户端连的是 CF 的标准 443,URL 不用带端口,CF 自己用 2096 回源。你的 API Token 得有 Zone > Origin Rules > Edit 权限,zone 的 SSL 模式得是 Full 档(如果已经有别的橙云记录在跑,那就已经是了)。

# 1) 订阅记录切橙云
curl -s -X PATCH ".../zones/$ZID/dns_records/$RID" -H "Authorization: Bearer $CF" --data '{"proxied":true}'
# 2) Origin Rule:CF 回源走 2096
curl -s -X PUT ".../zones/$ZID/rulesets/phases/http_request_origin/entrypoint" \
  -H "Authorization: Bearer $CF" \
  --data '{"rules":[{"action":"route","action_parameters":{"origin":{"port":2096}},"expression":"(http.host eq \"sub.your.domain.com\")","enabled":true}]}'

最后跑 curl -sI https://your.domain.com/TOKEN 验一下,看到 server: cloudflare、cf-cache-status: DYNAMIC 和 200 就成了。代理节点连的是裸 IP,橙云完全碰不到它们。


坑 13:CF Token 过期,续期静默失败

证书几个月后过期了,可 acme.sh 的定时续期「看起来」一直在跑。原因是申请证书时用的 Cloudflare API Token 过期了,或者被吊销了。acme 续期要靠这个 Token 去改 DNS,Token 一死,续期就失败,而且不会报到你眼前。

所以申请前先验一次 Token,平时用不过期的 Token,别用临时的。验的时候别用 /user/tokens/verify,那是 user 级的接口,碰上「只授权了某个 zone」的 Token,它会误报 Invalid API Token,明明能用也说无效。真去读一次 zone 来验才准:

# 真实功能验证,不是 /user/tokens/verify
curl -s "https://api.cloudflare.com/client/v4/zones?name=your-zone.com" \
  -H "Authorization: Bearer $CF_Token" | python3 -m json.tool
# success: true 且 result 非空才往下走

(真死掉的 Token 两个接口都过不了;zone 范围的好 Token 只是过不了 /user/tokens/verify 而已。)


加第二个节点别从头来:已经有一个能用的节点,再开一台时直接克隆最省事。把 /etc/s-box 整个打包搬过去,sb.json 和 sing-box 二进制跟机器没关系(监听 ::、Reality 借公共 SNI、证书走路径),照搬就行。只要改三个地方,客户端配置里的 IP(用 sed 批量换掉旧 IP),节点名里的机器 ID,还有给新域名单独申一张证书。这比重跑一遍交互脚本快得多,也不会手抖配错。


10. 验证清单

按顺序一项一项确认,全都通过,服务就没问题。服务端七项,客户端三项,最后再看一眼 Clash Verge 界面上的状态。

服务端

# 1. sing-box 运行正常
systemctl is-active sing-box
# 期望:active

# 2. 所有端口监听
ss -tlnp | grep -E "16796|2082"   # TCP
ss -ulnp | grep -E "18877|31227"   # UDP

# 3. BBR 已启用
sysctl net.ipv4.tcp_congestion_control
# 期望:bbr

# 4. SSL 证书有效
openssl x509 -in /root/ygkkkca/fullchain.crt -noout -dates
# 确认 notAfter 在未来

# 5. nginx 运行正常
systemctl is-active nginx
# 期望:active

# 6. 订阅 URL 可访问
TOKEN=$(cat /etc/s-box/.sub_token)
curl -sk "https://your.domain.com/${TOKEN}" | head -5
# 期望看到 YAML 配置内容

# 7. 证书与私钥匹配
openssl x509 -in /etc/s-box/cert.pem -pubkey -noout | openssl sha256
openssl pkey -in /etc/s-box/private.key -pubout | openssl sha256

客户端

# 确认系统代理
networksetup -getwebproxy Wi-Fi
# 期望:Enabled: Yes, Server: 127.0.0.1, Port: 7897

# 测试代理
curl -x http://127.0.0.1:7897 https://ip.me
# 期望显示 VPS IP

# 测试 Google
curl -x http://127.0.0.1:7897 -I https://www.google.com
# 期望:HTTP/2 200

Clash Verge 界面

检查项期望状态
订阅页 → 配置卡片高亮边框(已激活)
代理页 → 节点列表显示 VLESS-Reality、Hysteria2、TUIC-v5
设置页 → 系统代理已开启
设置页 → 代理模式规则(Rule)
代理页 → 延迟测试各节点显示延迟数值

自动续期

# 查看定时任务
crontab -l | grep acme

# 干跑续期(不实际更新)
~/.acme.sh/acme.sh --renew -d your.domain.com --ecc --dry-run

附录:快速参考

常用命令

# sing-box 管理
sb                           # 管理菜单
systemctl restart sing-box   # 重启
journalctl -u sing-box -f    # 实时日志

# 证书管理
~/.acme.sh/acme.sh --list    # 列出所有证书
~/.acme.sh/acme.sh --renew -d your.domain.com --ecc  # 手动续期

# 订阅
TOKEN=$(cat /etc/s-box/.sub_token)
echo "Clash 订阅: https://your.domain.com/${TOKEN}"

# nginx
nginx -t                     # 测试配置
systemctl reload nginx        # 热重载

端口总览

注意:sing-box 脚本每次装都会随机分配代理协议的端口,下表里标了"随机"的端口,以你实际安装时的输出为准。

服务端口协议说明
SSHYOUR_SSH_PORTTCP服务器管理
nginx HTTP80TCP自动跳转 HTTPS
nginx HTTPS443TCP订阅服务器
VLESS-Reality(随机)TCP主力节点
Vmess-WS(随机)TCP备用
Hysteria2(随机)UDP高速节点
TUIC-v5(随机)UDP低延迟节点
Anytls(随机)TCPTLS 伪装节点

重要文件

文件用途
/etc/s-box/sb.jsonsing-box 服务端配置
/etc/s-box/clmi.yamlClash 客户端订阅内容
/etc/s-box/sbox.jsonsing-box 客户端订阅内容
/etc/s-box/.sub_token订阅 URL 的访问 Token
/root/ygkkkca/fullchain.crtSSL 证书
/root/ygkkkca/private.keySSL 私钥
/etc/nginx/sites-available/subnginx 站点配置
/etc/s-box/update_traffic.sh流量统计更新脚本
/etc/s-box/.traffic_header.conf生成的 nginx 流量统计头
~/.acme.sh/acme.sh 工作目录
和 AI 讨论这篇文章
ChatGPTClaude
AI 随想第 17 篇 · 共 28 篇

订阅更新

新文章发布时发到你的邮箱,不发别的。


© Xingfan Xia 2024 - 2026 · CC BY-NC 4.0