Debian 12 空 VPS 搭建 3x-ui-nginx-certbot-ufw-fail2ban
本文记录一套从空 Debian 12 VPS 开始的基础部署流程:
- SSH 从
22改为54444 - 使用公私钥登录,禁用密码登录
- 开启 UFW 防火墙
- 安装 Fail2ban 防 SSH/nginx 异常访问
- 安装 3x-ui 面板
- 使用 nginx + Certbot 管理 HTTPS 证书
- 通过 HTTPS 域名路径反代访问 3x-ui 面板
- 创建 VLESS REALITY 和 Hysteria2/HY2 入站
文中使用占位符:
<YOUR_DOMAIN> 你的面板域名
<YOUR_PUBLIC_KEY> 你的 SSH 公钥
<PANEL_PORT> 3x-ui 面板本地端口,例如 36666
<PANEL_PATH> 3x-ui 面板路径,例如 /randomPath/
<REALITY_PORT> VLESS REALITY TCP 端口,例如 28445
<HY2_PORT> Hysteria2 UDP 端口,例如 507331. 系统初始化
更新系统并安装基础工具:
apt update -y
apt upgrade -y
apt install -y curl wget net-tools vim ufw nginx certbot python3-certbot-nginx fail2ban
timedatectl set-timezone Asia/Shanghai检查时间同步:
timedatectl statusDebian 12 通常已经使用 systemd 时间同步。如果仍想使用 ntpdate 定时同步:
apt install -y ntpdate
crontab -e加入:
0 * * * * /usr/sbin/ntpdate pool.ntp.org >/dev/null 2>&12. 配置 SSH 公钥登录
先创建 root 的 SSH 目录:
mkdir -p /root/.ssh
chmod 700 /root/.ssh写入你的 SSH 公钥:
cat >> /root/.ssh/authorized_keys <<'EOF'
<YOUR_PUBLIC_KEY>
EOF
chmod 600 /root/.ssh/authorized_keys此时先不要断开当前 SSH 窗口,另开一个终端测试公钥能否登录:
ssh -p 22 root@<SERVER_IP>确认公钥登录正常后,再修改 SSH 端口和禁用密码登录。
3. SSH 从 22 改为 54444
新建独立配置文件:
vim /etc/ssh/sshd_config.d/99-custom.conf写入:
Port 54444
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password检查 SSH 配置:
sshd -t先放行新 SSH 端口:
ufw allow 54444/tcp重载 SSH:
systemctl reload ssh另开一个终端测试:
ssh -p 54444 root@<SERVER_IP>确认 54444 可以登录后,再考虑关闭 22。
4. 配置 UFW 防火墙
基础端口:
ufw allow 54444/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
ufw status如果确认 SSH 54444 已经可用,可以删除旧的 22 放行规则:
ufw status numbered
ufw delete <RULE_NUMBER>3x-ui 面板端口不建议公网开放。面板建议只通过 nginx HTTPS 反代访问。
5. 配置 Fail2ban
Fail2ban 和 UFW 的职责不同:
UFW: 控制哪些端口能访问
Fail2ban: 读取 SSH/nginx 日志,发现异常后动态封 IP写入配置:
cat > /etc/fail2ban/jail.local <<'EOF'
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd
[sshd]
enabled = true
port = 54444
filter = sshd
logpath = %(sshd_log)s
maxretry = 5
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 5
[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 10
EOF让 Fail2ban 通过 UFW 执行封禁:
cat > /etc/fail2ban/jail.d/00-firewalld-ufw.conf <<'EOF'
[DEFAULT]
banaction = ufw
banaction_allports = ufw
EOF启动并检查:
systemctl enable --now fail2ban
systemctl restart fail2ban
fail2ban-client status
fail2ban-client status sshdufw 是封禁动作,不是 jail 名称,所以 fail2ban-client status 里一般只会看到:
sshd
nginx-http-auth
nginx-botsearch测试封禁是否能写入 UFW:
fail2ban-client set sshd banip 203.0.113.123
ufw status numbered
fail2ban-client set sshd unbanip 203.0.113.1236. 网络参数优化
开启 BBR 和常用 TCP 参数:
cat >> /etc/sysctl.conf <<'EOF'
net.ipv4.tcp_syncookies=1
net.ipv4.tcp_congestion_control=bbr
net.core.default_qdisc=fq
net.core.rmem_max=26214400
net.core.wmem_max=26214400
net.ipv4.tcp_rmem=4096 87380 26214400
net.ipv4.tcp_wmem=4096 16384 26214400
net.ipv4.route.flush=1
EOF
sysctl -p
sysctl net.ipv4.tcp_congestion_control如果输出包含 bbr,说明生效。
7. 安装 3x-ui
最新版安装:
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)固定版本安装示例:
VERSION=v2.4.7
bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/${VERSION}/install.sh") "${VERSION}"两种方式二选一即可。
安装过程中建议设置:
面板端口: <PANEL_PORT>
面板路径: <PANEL_PATH>
用户名: 自行设置
密码: 自行设置安装后查看面板信息:
x-ui记录:
Panel port
webBasePath
username
password8. 域名解析与证书
先在 DNS 服务商中添加解析:
<YOUR_DOMAIN> -> 当前 VPS 公网地址如果使用 Cloudflare,首次签发证书失败时,可以先把代理状态改为 DNS only。
确认 nginx 配置正常:
nginx -t
systemctl reload nginx申请证书:
certbot --nginx -d <YOUR_DOMAIN>测试自动续期:
certbot renew --dry-run
systemctl status certbot.timer --no-pager如果 certbot.timer 正常启用,一般不需要额外写 cron。若系统没有 timer,可手动添加:
0 3 * * * certbot renew --quiet --post-hook "systemctl reload nginx"9. nginx 反代 3x-ui 面板
编辑 nginx 站点配置:
vim /etc/nginx/sites-enabled/default在 <YOUR_DOMAIN> 对应的 server { listen 443 ssl; ... } 块内添加 location。
如果 3x-ui 面板是 HTTP:
location ^~ <PANEL_PATH> {
proxy_pass http://127.0.0.1:<PANEL_PORT><PANEL_PATH>;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}如果 3x-ui 面板自身启用了 HTTPS:
location ^~ <PANEL_PATH> {
proxy_pass https://127.0.0.1:<PANEL_PORT><PANEL_PATH>;
proxy_ssl_verify off;
proxy_ssl_server_name on;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}注意:
<PANEL_PATH>建议以/开头并以/结尾- nginx 中的路径必须和 3x-ui 输出的
webBasePath完全一致 - 注意数字
0和字母O不要混淆
检查并重载:
nginx -t
systemctl reload nginx访问:
https://<YOUR_DOMAIN><PANEL_PATH>10. 创建 VLESS REALITY 入站
在 3x-ui 面板中新建入站:
Protocol: VLESS
Transport: TCP
Security: REALITY
Flow: xtls-rprx-vision
Port: <REALITY_PORT>UFW 放行 TCP:
ufw allow <REALITY_PORT>/tcp
ufw reload说明:
- REALITY 不能通过 nginx
location普通反代 - 如果 nginx 已占用
443,REALITY 建议使用独立 TCP 端口 - 客户端配置里的端口必须和
<REALITY_PORT>一致
11. 创建 Hysteria2/HY2 入站
在 3x-ui 面板中新建入站:
Protocol: Hysteria2
Port: <HY2_PORT>
UDP: enabledUFW 放行 UDP:
ufw allow <HY2_PORT>/udp
ufw reloadHY2 主要走 UDP,不要只放行 TCP。
12. 检查端口和服务
查看 nginx:
systemctl status nginx --no-pager
nginx -t查看 3x-ui:
systemctl status x-ui --no-pager
x-ui查看端口监听:
ss -tulnp | grep -E '80|443|54444|<PANEL_PORT>|<REALITY_PORT>|<HY2_PORT>'查看 UFW:
ufw status numbered查看 Fail2ban:
fail2ban-client status
fail2ban-client status sshd13. 常见问题
nginx reload 提示服务未运行
如果:
nginx.service is not active, cannot reload先启动:
nginx -t
systemctl start nginx
systemctl status nginx --no-pager -lnginx 端口被旧进程占用
如果看到:
bind() to 0.0.0.0:443 failed (98: Address already in use)检查:
ss -tlnp | grep -E ':80|:443'确认都是残留 nginx 进程时再处理:
pkill -9 nginx
rm -f /run/nginx.pid
systemctl start nginxcertbot 申请失败
常见原因:
域名没有解析到当前 VPS
Cloudflare 代理影响验证
80 端口没有开放
nginx server_name 不匹配检查:
ufw status
nginx -t
curl -I http://<YOUR_DOMAIN>反代面板 404
重点检查:
nginx location 路径是否和 3x-ui webBasePath 完全一致
location 是否写进了正确的 443 server 块
proxy_pass 是 http 还是 https排查命令:
nginx -T | grep -n -A20 -B10 "<PANEL_PATH>"
curl -I http://127.0.0.1:<PANEL_PORT><PANEL_PATH>
curl -kI https://127.0.0.1:<PANEL_PORT><PANEL_PATH>fail2ban 里没有 ufw jail
正常。ufw 是封禁动作,不是 jail 名称。查看 jail:
fail2ban-client status通常会看到:
sshd
nginx-http-auth
nginx-botsearch14. 最终安全建议
公网只建议开放:
80/tcp
443/tcp
54444/tcp
<REALITY_PORT>/tcp
<HY2_PORT>/udp不建议公网开放:
22/tcp
3x-ui 面板端口
数据库端口
Docker 后端服务端口部署完成后至少确认:
ssh -p 54444 root@<SERVER_IP>
ufw status numbered
fail2ban-client status
certbot renew --dry-run
nginx -t