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. 前置条件
  2. VPS 初始化
  3. 安装 Docker
  4. 准备目录结构
  5. 生成凭证
  6. TLS 证书
  7. 编写配置文件
  8. Docker Compose 部署
  9. 验证运行
  10. 客户端配置
  11. 常见问题
  12. 日常维护

1. 前置条件

  • 一台境外 VPS(Debian 12 或 13,x86_64)
  • Root SSH 访问
  • 一个域名(推荐但非必需 —— 自签证书也能跑 Hysteria2)
  • 如果是有 1Panel 等面板的机器,注意防火墙冲突(见第 11 节)

2. VPS 初始化

Terminal window
# 更新系统
apt update && apt upgrade -y
# 基础工具
apt install -y curl wget vim ufw
# 开启 BBR 拥塞控制
cat >> /etc/sysctl.conf << 'EOF'
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
EOF
sysctl -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}/tcp
ufw allow 443/tcp # VLESS Reality
ufw allow 8443/udp # Hysteria2
# ⚠️ 先检查有没有 1Panel,它的防火墙会覆盖 ufw
if systemctl is-active --quiet 1panel-core 2>/dev/null; then
echo "检测到 1Panel,注意:需要单独在 1Panel 防火墙里放行 443/tcp 和 8443/udp!"
fi
ufw --force enable

3. 安装 Docker

Terminal window
# 官方一键脚本(Debian/Ubuntu)
curl -fsSL https://get.docker.com | sh
# 启动并设为开机自启
systemctl enable docker
systemctl start docker
# 安装 Docker Compose v2(作为 Docker 插件)
apt install -y docker-compose-plugin
# 验证
docker --version
docker compose version

4. 准备目录结构

Terminal window
mkdir -p /opt/sing-box/cert
mkdir -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):

Terminal window
# 拉取镜像
docker pull ghcr.io/sagernet/sing-box:latest
# Reality 密钥对
docker run --rm ghcr.io/sagernet/sing-box generate reality-keypair
# UUID
docker 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>填入客户端配置
UUIDa1b2c3d4-...服务端 + 客户端
Short IDa1b2c3d4e5f6a7b8服务端 + 客户端
HY2 密码随机 base64 字符串服务端 + 客户端

6. TLS 证书

方案 A:有域名(推荐)

Terminal window
# 安装 acme.sh
curl https://get.acme.sh | sh
source ~/.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:自签证书(无域名)

Terminal window
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: hostsing-box 需要直接监听宿主机端口,host 模式零损耗,无需 NAT
volumesconfig.json 和 cert 放在同一个目录,映射到容器内 /etc/sing-box
command: -C-C 指定配置目录(容器扫描该目录下所有 .json 文件),去掉了 -D(默认工作目录不需要持久化)
restart: always容器崩溃或宿主机重启后自动恢复

启动:

Terminal window
cd /opt/sing-box
docker compose up -d

9. 验证运行

Terminal window
# 查看容器状态
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.x
INFO[0000] starting instance at /etc/sing-box/config.json
INFO[0000] inbound/hysteria2[hy2-in]: started at [::]:8443
INFO[0000] inbound/vless[reality-in]: started at [::]:443

10. 客户端配置

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 无响应。

修复:

Terminal window
# 写入持久规则
echo '-A 1PANEL_BASIC -p udp --dport 8443 -j ACCEPT' \
>> /opt/1panel/firewall/1panel_basic.rules
# 立即生效(先停 1panel-core 因为它在 nftables 上加了锁)
systemctl stop 1panel-core
sleep 2
iptables -A 1PANEL_BASIC -p udp --dport 8443 -j ACCEPT
systemctl start 1panel-core

11.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 版本

Terminal window
cd /opt/sing-box
docker 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. 日常维护

Terminal window
# 查看日志
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

附录:一条命令部署

如果你不想手动分步走,把所有配置文件准备好后,以下指令一键拉起:

Terminal window
# 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