sing-box Docker 部署指南:VLESS Reality + Hysteria2 双协议
sing-box Docker 部署指南(新 VPS)
适用场景:在新 VPS 上用 Docker 部署 sing-box,跑 VLESS Reality + Hysteria2 双协议。 版本:sing-box 1.13.x,Debian 12 / 13,Docker Compose v2。
目录
1. 前置条件
- 一台境外 VPS(Debian 12 或 13,x86_64)
- Root SSH 访问
- 一个域名(推荐但非必需 —— 自签证书也能跑 Hysteria2)
- 如果是有 1Panel 等面板的机器,注意防火墙冲突(见第 11 节)
2. VPS 初始化
# 更新系统apt update && apt upgrade -y
# 基础工具apt install -y curl wget vim ufw
# 开启 BBR 拥塞控制cat >> /etc/sysctl.conf << 'EOF'net.core.default_qdisc = fqnet.ipv4.tcp_congestion_control = bbrEOFsysctl -p
# 检查当前 SSH 端口(很多 VPS 商不用 22)SSH_PORT=$(ss -tlnp | grep sshd | head -1 | awk '{print $4}' | awk -F: '{print $NF}')13 collapsed lines
echo "SSH port: ${SSH_PORT:-22}"
# 防火墙放行ufw allow ${SSH_PORT:-22}/tcpufw allow 443/tcp # VLESS Realityufw allow 8443/udp # Hysteria2
# ⚠️ 先检查有没有 1Panel,它的防火墙会覆盖 ufwif systemctl is-active --quiet 1panel-core 2>/dev/null; then echo "检测到 1Panel,注意:需要单独在 1Panel 防火墙里放行 443/tcp 和 8443/udp!"fi
ufw --force enable3. 安装 Docker
# 官方一键脚本(Debian/Ubuntu)curl -fsSL https://get.docker.com | sh
# 启动并设为开机自启systemctl enable dockersystemctl start docker
# 安装 Docker Compose v2(作为 Docker 插件)apt install -y docker-compose-plugin
# 验证docker --versiondocker compose version4. 准备目录结构
mkdir -p /opt/sing-box/certmkdir -p /opt/sing-box/config最终结构:
/opt/sing-box/├── cert/│ ├── fullchain.pem # TLS 证书(自签或有域名的)│ └── privkey.pem # 私钥├── config/│ └── config.json # sing-box 配置└── docker-compose.yml # Docker Compose 编排文件5. 生成凭证
先用 Docker 临时跑一次 sing-box 来生成凭证(避免在 VPS 上裸装 sing-box):
# 拉取镜像docker pull ghcr.io/sagernet/sing-box:latest
# Reality 密钥对docker run --rm ghcr.io/sagernet/sing-box generate reality-keypair
# UUIDdocker run --rm ghcr.io/sagernet/sing-box generate uuid
# Short ID(8 字节十六进制)docker run --rm ghcr.io/sagernet/sing-box generate rand 8 --hex
# Hysteria2 密码openssl rand -base64 16记下以上四个输出:
| 凭证 | 示例值 | 用途 |
|---|---|---|
| PrivateKey | <你的PrivateKey> | 填入服务端 config.json |
| PublicKey | <你的PublicKey> | 填入客户端配置 |
| UUID | a1b2c3d4-... | 服务端 + 客户端 |
| Short ID | a1b2c3d4e5f6a7b8 | 服务端 + 客户端 |
| HY2 密码 | 随机 base64 字符串 | 服务端 + 客户端 |
6. TLS 证书
方案 A:有域名(推荐)
# 安装 acme.shcurl https://get.acme.sh | shsource ~/.bashrc
# 申请证书(需要 80 端口暂时可用)~/.acme.sh/acme.sh --issue -d your-domain.com --standalone
# 安装到 sing-box 目录~/.acme.sh/acme.sh --install-cert -d your-domain.com \ --key-file /opt/sing-box/cert/privkey.pem \ --fullchain-file /opt/sing-box/cert/fullchain.pem
# 设置自动续期后重载 sing-box 容器~/.acme.sh/acme.sh --install-cronjob# 手动加一个 reload hook:2 collapsed lines
# echo 'docker restart sing-box' >> ~/.acme.sh/renew-hook.sh# chmod +x ~/.acme.sh/renew-hook.sh方案 B:自签证书(无域名)
openssl req -x509 -nodes -newkey ec:<(openssl ecparam -name prime256v1) \ -keyout /opt/sing-box/cert/privkey.pem \ -out /opt/sing-box/cert/fullchain.pem \ -subj "/CN=localhost" -days 3650自签证书在大部分客户端上可以工作(Hysteria2 不验证证书链)。但 Shadowrocket 等部分客户端可能弹警告。
7. 编写配置文件
创建 /opt/sing-box/config/config.json,把上面生成的凭证替换进去:
{ "log": { "level": "info", "timestamp": true }, "dns": { "servers": [ {"tag": "google", "type": "tls", "server": "8.8.8.8"} ] }, "inbounds": [ { "type": "hysteria2", "tag": "hy2-in", "listen": "::",43 collapsed lines
"listen_port": 8443, "users": [ {"name": "main", "password": "你的HY2密码"} ], "tls": { "enabled": true, "server_name": "localhost", "certificate_path": "/etc/sing-box/cert/fullchain.pem", "key_path": "/etc/sing-box/cert/privkey.pem" } }, { "type": "vless", "tag": "reality-in", "listen": "::", "listen_port": 443, "users": [ { "name": "main", "uuid": "你的UUID", "flow": "xtls-rprx-vision" } ], "tls": { "enabled": true, "server_name": "www.microsoft.com", "reality": { "enabled": true, "handshake": { "server": "www.microsoft.com", "server_port": 443 }, "private_key": "你的PrivateKey", "short_id": ["你的ShortID"], "max_time_difference": "1m" } } } ], "outbounds": [ {"type": "direct", "tag": "direct-out"} ]}注意:容器内的路径是
/etc/sing-box/...,不是/opt/sing-box/...—— 后面用 volume 映射。
8. Docker Compose 部署
创建 /opt/sing-box/docker-compose.yml:
version: "3.8"
services: sing-box: image: ghcr.io/sagernet/sing-box:latest container_name: sing-box restart: always network_mode: host volumes: - /opt/sing-box/config:/etc/sing-box # 配置 + 证书 command: -C /etc/sing-box/ run logging: driver: json-file options: max-size: "10m"1 collapsed line
max-file: "3"关键说明:
| 配置项 | 原因 |
|---|---|
network_mode: host | sing-box 需要直接监听宿主机端口,host 模式零损耗,无需 NAT |
volumes | config.json 和 cert 放在同一个目录,映射到容器内 /etc/sing-box |
command: -C | -C 指定配置目录(容器扫描该目录下所有 .json 文件),去掉了 -D(默认工作目录不需要持久化) |
restart: always | 容器崩溃或宿主机重启后自动恢复 |
启动:
cd /opt/sing-boxdocker compose up -d9. 验证运行
# 查看容器状态docker compose ps
# 查看日志docker compose logs -f
# 检查端口监听(因为 host 网络模式,直接看宿主机端口)ss -tlnp | grep 443 # VLESS Reality → 应该在ss -ulnp | grep 8443 # Hysteria2 → 应该在
# 验证配置文件语法docker compose exec sing-box sing-box check -c /etc/sing-box/config.json正常日志应该类似:
INFO[0000] sing-box version 1.13.xINFO[0000] starting instance at /etc/sing-box/config.jsonINFO[0000] inbound/hysteria2[hy2-in]: started at [::]:8443INFO[0000] inbound/vless[reality-in]: started at [::]:44310. 客户端配置
VLESS Reality(Clash Verge / sing-box 客户端)
{ "type": "vless", "tag": "proxy", "server": "你的VPS_IP", "server_port": 443, "uuid": "你的UUID", "flow": "xtls-rprx-vision", "tls": { "enabled": true, "server_name": "www.microsoft.com", "utls": { "enabled": true, "fingerprint": "chrome" }, "reality": {6 collapsed lines
"enabled": true, "public_key": "你的PublicKey", "short_id": "你的ShortID" } }}Hysteria2
{ "type": "hysteria2", "tag": "hy2", "server": "你的VPS_IP", "server_port": 8443, "password": "你的HY2密码", "tls": { "enabled": true, "server_name": "localhost" }}完整客户端 config.json(同时启用两个协议 + 自动选择)
{ "log": {"level": "info", "timestamp": true}, "inbounds": [ { "type": "mixed", "tag": "mixed-in", "listen": "127.0.0.1", "listen_port": 2080 } ], "outbounds": [ { "type": "vless", "tag": "reality", "server": "你的VPS_IP",32 collapsed lines
"server_port": 443, "uuid": "你的UUID", "flow": "xtls-rprx-vision", "tls": { "enabled": true, "server_name": "www.microsoft.com", "utls": {"enabled": true, "fingerprint": "chrome"}, "reality": { "enabled": true, "public_key": "你的PublicKey", "short_id": "你的ShortID" } } }, { "type": "hysteria2", "tag": "hy2", "server": "你的VPS_IP", "server_port": 8443, "password": "你的HY2密码", "tls": {"enabled": true, "server_name": "localhost"} }, {"type": "direct", "tag": "direct"} ], "route": { "auto_detect_interface": true, "rules": [ {"ip_is_private": true, "outbound": "direct"} ], "final": "reality" }}11. 常见问题
11.1 1Panel 防火墙吞 UDP
如果 VPS 装了 1Panel,它的 nftables 规则 (1PANEL_BASIC_AFTER) 会丢弃所有未经 1Panel 明确放行的 UDP 包,导致 Hysteria2 无响应。
修复:
# 写入持久规则echo '-A 1PANEL_BASIC -p udp --dport 8443 -j ACCEPT' \ >> /opt/1panel/firewall/1panel_basic.rules
# 立即生效(先停 1panel-core 因为它在 nftables 上加了锁)systemctl stop 1panel-coresleep 2iptables -A 1PANEL_BASIC -p udp --dport 8443 -j ACCEPTsystemctl start 1panel-core11.2 Reality 连接失败:failed to dial dest: invalid address
- sing-box 1.13.x Reality 必须用
handshake字段(server+server_port),不能用旧版target - 服务端 config.json 请严格参照上面模板的
reality结构
11.3 容器重启后证书 / 配置未生效
- 确认 volume 挂载路径正确:宿主机
/opt/sing-box/config/→ 容器/etc/sing-box/ - 修改配置后需要重启容器:
docker compose restart
11.4 如何更新 sing-box 版本
cd /opt/sing-boxdocker compose pull # 拉取最新镜像docker compose up -d # 用新镜像重建容器如果新版本有 breaking changes(比如 1.12 改了 DNS 格式),需要同步更新 config.json。
11.5 GFW 封锁后的备选方案
如果 VPS IP 被 GFW 标记(VLESS + HY2 都连不上):
- Cloudflare Tunnel(免费,但需要域名 + CF 代理)
- WARP on client — 客户端装 cloudflare-warp,通过 CF 网络绕行
- 国内中转 — 阿里云 / 腾讯云轻量服务器做跳板
- 换 IP — 最省事但可能花 $
12. 日常维护
# 查看日志docker compose logs -f # 实时docker compose logs --tail=100 # 最近 100 行
# 重启docker compose restart
# 停止docker compose down
# 更新镜像docker compose pull && docker compose up -d
# 查看资源占用docker stats sing-box附录:一条命令部署
如果你不想手动分步走,把所有配置文件准备好后,以下指令一键拉起:
# 1. 确保目录就绪mkdir -p /opt/sing-box/{cert,config}
# 2. 把 config.json 放到 /opt/sing-box/config/# 3. 把证书放到 /opt/sing-box/cert/,然后在 config.json 里引用 /etc/sing-box/cert/...# 或者直接把证书也放 /opt/sing-box/config/ 下面,config.json 引用 /etc/sing-box/xxx.pem
# 4. 创建 docker-compose.yml(如上)cd /opt/sing-box && docker compose up -d