3x-ui-setup
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseVPN Server Setup (3x-ui)
VPN服务器搭建(3x-ui)
Complete setup: fresh VPS from provider → secured server → working VPN with Hiddify client.
完整搭建流程:从服务商提供的全新VPS → 安全加固服务器 → 配置可正常使用的VPN并搭配Hiddify客户端。
Workflow Overview
工作流程概览
ЧАСТЬ 1: Настройка сервера
Fresh VPS (IP + root + password)
→ Determine execution mode (remote or local)
→ Generate SSH key / setup access
→ Connect as root
→ Update system
→ Create non-root user + sudo
→ Install SSH key
→ TEST new user login (critical!)
→ Firewall (ufw)
→ Kernel hardening
→ Time sync + packages
→ Configure local ~/.ssh/config
→ ✅ Server secured
ЧАСТЬ 2: Установка VPN (3x-ui)
→ Install 3x-ui panel
→ Enable BBR (TCP optimization)
→ Disable ICMP (stealth)
→ Reality: scanner → create inbound → get link
→ Install Hiddify client
→ Verify connection
→ Generate guide file (credentials + instructions)
→ Install fail2ban + lock SSH (after key verified)
→ ✅ VPN working第一部分:服务器配置
全新VPS(IP + root账号 + 密码)
→ 确定执行模式(远程或本地)
→ 生成SSH密钥 / 配置访问权限
→ 以root身份连接服务器
→ 更新系统
→ 创建非root用户并赋予sudo权限
→ 安装SSH密钥
→ 测试新用户登录(至关重要!)
→ 配置防火墙(ufw)
→ 内核加固
→ 时间同步与基础软件包安装
→ 配置本地~/.ssh/config文件
→ ✅ 服务器已安全加固
第二部分:安装VPN(3x-ui)
→ 安装3x-ui面板
→ 启用BBR(TCP优化)
→ 禁用ICMP(隐身模式)
→ Reality:扫描器 → 创建入站规则 → 获取连接链接
→ 安装Hiddify客户端
→ 验证连接有效性
→ 生成指南文件(包含凭证与操作说明)
→ 安装fail2ban并锁定SSH(密钥验证通过后执行)
→ ✅ VPN已正常运行PART 1: Server Hardening
第一部分:服务器安全加固
Secure a fresh server from provider credentials to production-ready state.
将服务商提供的全新服务器配置为生产就绪状态。
Step 0: Collect Information
步骤0:收集信息
First, determine execution mode:
Где запущен Claude Code?
- На локальном компьютере (Remote mode) -- настраиваем удалённый сервер через SSH
- На самом сервере (Local mode) -- настраиваем этот же сервер напрямую
首先,确定执行模式:
Claude Code运行在何处?
- 本地电脑(远程模式)——通过SSH配置远程服务器
- 服务器本地(本地模式)——直接配置当前服务器
Remote Mode -- ASK the user for:
远程模式 —— 向用户询问:
- Server IP -- from provider email
- Root password -- from provider email
- Desired username -- for the new non-root account
- Server nickname -- for SSH config (e.g., ,
myserver)vpn1 - Has domain? -- if unsure, recommend "no" (Reality path, simpler)
- Domain name (if yes to #5) -- must already point to server IP
- 服务器IP —— 来自服务商邮件
- Root密码 —— 来自服务商邮件
- 期望的用户名 —— 用于创建新的非root账号
- 服务器别名 —— 用于SSH配置(例如:、
myserver)vpn1 - 是否拥有域名? —— 若不确定,建议选择“否”(Reality路径,设置更简单)
- 域名(若第5项选“是”)—— 必须已解析至服务器IP
Local Mode -- ASK the user for:
本地模式 —— 向用户询问:
- Desired username -- for the new non-root account
- Server nickname -- for future SSH access from user's computer (e.g., ,
myserver)vpn1 - Has domain? -- if unsure, recommend "no" (Reality path, simpler)
- Domain name (if yes to #3) -- must already point to server IP
In Local mode, get server IP automatically:
bash
curl -4 -s ifconfig.meIf user pastes the full provider email, extract the data from it.
Recommend Reality (no domain) for beginners. Explain:
- Reality: works without domain, free, simpler setup, great performance
- TLS: needs domain purchase (~$10/year), more traditional, allows fallback site
- 期望的用户名 —— 用于创建新的非root账号
- 服务器别名 —— 后续从用户电脑通过SSH访问时使用(例如:、
myserver)vpn1 - 是否拥有域名? —— 若不确定,建议选择“否”(Reality路径,设置更简单)
- 域名(若第3项选“是”)—— 必须已解析至服务器IP
本地模式下,自动获取服务器IP:
bash
curl -4 -s ifconfig.me若用户粘贴了完整的服务商邮件,从中提取所需信息。
推荐新手使用Reality模式(无需域名),说明如下:
- Reality:无需域名即可使用,免费,设置更简单,性能出色
- TLS:需购买域名(约10美元/年),更传统,支持 fallback 站点
Execution Modes
执行模式适配
All commands in this skill are written for Remote mode (via SSH).
For Local mode, adapt as follows:
| Step | Remote Mode (default) | Local Mode |
|---|---|---|
| Step 1 | Generate SSH key on LOCAL machine | SKIP -- user creates key on laptop later (Step 22) |
| Step 2 | | Already on server. If not root: |
| Steps 3-4 | Run on server via root SSH | Run directly (already on server) |
| Step 5 | Install local public key on server | SKIP -- user sends .pub via SCP later (Step 22) |
| Step 6 | SSH test from LOCAL: | Switch user: |
| Step 7 | SKIP -- lockdown deferred to Step 22 | SKIP -- lockdown deferred to Step 22 |
| Steps 8-11 | | |
| Step 12 | Write | SKIP -- user does this from guide file (Step 22) |
| Step 13 | Verify via | Run audit directly, skip SSH lockdown checks |
| Part 2 | | |
| Step 17A | Scanner via | Scanner runs directly (no SSH wrapper) -- see Step 17A for both commands |
| Panel access | Via SSH tunnel | Direct: |
| Step 22 | Generate guide + fail2ban + lock SSH | Generate guide → SCP download → SSH key setup → fail2ban + lock SSH |
IMPORTANT: In both modes, the end result is the same -- user has SSH key access to the server from their local computer via , password auth disabled, root login disabled.
ssh {nickname}本技能中的所有命令默认针对远程模式(通过SSH执行)。
针对本地模式,按如下方式调整:
| 步骤 | 远程模式(默认) | 本地模式 |
|---|---|---|
| 步骤1 | 在本地电脑生成SSH密钥 | 跳过 —— 用户后续在笔记本电脑创建密钥(步骤22) |
| 步骤2 | | 已在服务器上。若当前不是root用户: |
| 步骤3-4 | 通过root SSH在服务器上执行 | 直接执行(已在服务器上) |
| 步骤5 | 在服务器上安装本地公钥 | 跳过 —— 用户后续通过SCP发送.pub文件(步骤22) |
| 步骤6 | 从本地测试SSH: | 切换用户: |
| 步骤7 | 跳过 —— 锁定操作推迟至步骤22 | 跳过 —— 锁定操作推迟至步骤22 |
| 步骤8-11 | 通过SSH在服务器上使用 | 直接使用 |
| 步骤12 | 在本地编写 | 跳过 —— 用户通过指南文件完成此操作(步骤22) |
| 步骤13 | 通过 | 直接运行审计,跳过SSH锁定检查 |
| 第二部分 | | 直接执行 |
| 步骤17A | 通过 | 直接运行扫描器(无需SSH包装)—— 查看步骤17A中的两种命令 |
| 面板访问 | 通过SSH隧道 | 直接访问: |
| 步骤22 | 生成指南文件 + 安装fail2ban + 锁定SSH | 生成指南文件 → 通过SCP下载 → 配置SSH密钥 → 安装fail2ban + 锁定SSH |
重要提示: 两种模式的最终结果一致——用户可通过本地电脑的命令,使用SSH密钥访问服务器,密码认证已禁用,root登录已禁用。
ssh {nickname}Step 1: Generate SSH Key (LOCAL)
步骤1:生成SSH密钥(本地电脑)
Run on the user's LOCAL machine BEFORE connecting to the server:
bash
ssh-keygen -t ed25519 -C "{username}@{nickname}" -f ~/.ssh/{nickname}_key -N ""Save the public key content for later:
bash
cat ~/.ssh/{nickname}_key.pub在连接服务器前,先在用户的本地电脑上执行:
bash
ssh-keygen -t ed25519 -C "{username}@{nickname}" -f ~/.ssh/{nickname}_key -N ""保存公钥内容备用:
bash
cat ~/.ssh/{nickname}_key.pubStep 2: First Connection as Root
步骤2:首次以Root身份连接服务器
bash
ssh root@{SERVER_IP}bash
ssh root@{SERVER_IP}Handling forced password change
处理强制修改密码
Many providers force a password change on first login. Signs:
- Prompt: "You are required to change your password immediately"
- Prompt: "Current password:" followed by "New password:"
- Prompt: "WARNING: Your password has expired"
If this happens:
- Enter the current (provider) password
- Enter a new strong temporary password (this is temporary -- SSH keys will replace it)
- You may be disconnected -- reconnect with the new password
If connection drops after password change -- this is normal. Reconnect:
bash
ssh root@{SERVER_IP}许多服务商要求首次登录时修改密码,特征如下:
- 提示:"You are required to change your password immediately"
- 提示:"Current password:" 随后是 "New password:"
- 提示:"WARNING: Your password has expired"
若出现此情况:
- 输入当前(服务商提供的)密码
- 设置一个新的强临时密码(此密码为临时使用——后续将被SSH密钥替代)
- 可能会断开连接——使用新密码重新连接
若修改密码后连接断开——此为正常现象,重新连接:
bash
ssh root@{SERVER_IP}Step 3: System Update (as root on server)
步骤3:系统更新(服务器上以root身份执行)
bash
apt update && DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt upgrade -ybash
apt update && DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt upgrade -yStep 4: Create Non-Root User
步骤4:创建非Root用户
bash
useradd -m -s /bin/bash {username}
echo "{username}:{GENERATE_STRONG_PASSWORD}" | chpasswd
usermod -aG sudo {username}Generate a strong random password. Tell the user to save it (needed for sudo). Then:
bash
undefinedbash
useradd -m -s /bin/bash {username}
echo "{username}:{GENERATE_STRONG_PASSWORD}" | chpasswd
usermod -aG sudo {username}生成一个强随机密码,告知用户保存(执行sudo时需要)。然后:
bash
undefinedVerify
验证
groups {username}
undefinedgroups {username}
undefinedStep 5: Install SSH Key for New User
步骤5:为新用户安装SSH密钥
bash
mkdir -p /home/{username}/.ssh
echo "{PUBLIC_KEY_CONTENT}" > /home/{username}/.ssh/authorized_keys
chmod 700 /home/{username}/.ssh
chmod 600 /home/{username}/.ssh/authorized_keys
chown -R {username}:{username} /home/{username}/.sshbash
mkdir -p /home/{username}/.ssh
echo "{PUBLIC_KEY_CONTENT}" > /home/{username}/.ssh/authorized_keys
chmod 700 /home/{username}/.ssh
chmod 600 /home/{username}/.ssh/authorized_keys
chown -R {username}:{username} /home/{username}/.sshStep 6: TEST New User Login -- CRITICAL CHECKPOINT
步骤6:测试新用户登录 —— 至关重要的检查点
DO NOT proceed without successful test!
Open a NEW connection (keep root session alive):
bash
ssh -i ~/.ssh/{nickname}_key {username}@{SERVER_IP}Verify sudo works:
bash
sudo whoami未通过测试前请勿继续!
打开一个新的连接(保持root会话处于活跃状态):
bash
ssh -i ~/.ssh/{nickname}_key {username}@{SERVER_IP}验证sudo权限是否正常:
bash
sudo whoamiMust output: root
输出必须为:root
**If this fails** -- debug permissions, do NOT disable root login:
```bash
**若测试失败**——调试权限,请勿禁用root登录:
```bashCheck on server as root:
在服务器上以root身份检查:
ls -la /home/{username}/.ssh/
cat /home/{username}/.ssh/authorized_keys
ls -la /home/{username}/.ssh/
cat /home/{username}/.ssh/authorized_keys
Fix ownership:
修复权限:
chown -R {username}:{username} /home/{username}/.ssh
undefinedchown -R {username}:{username} /home/{username}/.ssh
undefinedStep 7: Lock Down SSH — DEFERRED
步骤7:锁定SSH —— 推迟执行
Оба режима: ПРОПУСКАЕМ. Блокировка SSH и установка fail2ban выполняются в самом конце (Step 22), после того как SSH-ключ проверен. Это предотвращает случайную блокировку доступа во время настройки.
两种模式均跳过此步骤。SSH锁定与fail2ban安装将在最后执行(步骤22),且需在SSH密钥验证通过后进行。这可避免在配置过程中意外锁定访问权限。
Step 8: Firewall
步骤8:配置防火墙
bash
sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw --force enable
sudo ufw statusbash
sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw --force enable
sudo ufw statusStep 9: fail2ban — DEFERRED
步骤9:安装fail2ban —— 推迟执行
Пропущен. fail2ban устанавливается в конце настройки (Step 22) вместе с блокировкой SSH, чтобы не заблокировать пользователя во время настройки.
跳过此步骤。fail2ban将在配置末尾(步骤22)与SSH锁定一同安装,避免在配置过程中锁定用户。
Step 10: Kernel Hardening
步骤10:内核加固
bash
sudo tee /etc/sysctl.d/99-security.conf << 'EOF'
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
EOF
sudo sysctl -p /etc/sysctl.d/99-security.confbash
sudo tee /etc/sysctl.d/99-security.conf << 'EOF'
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
EOF
sudo sysctl -p /etc/sysctl.d/99-security.confStep 11: Time Sync + Base Packages
步骤11:时间同步与基础软件包
bash
sudo apt install -y chrony curl wget unzip net-tools
sudo systemctl enable chronybash
sudo apt install -y chrony curl wget unzip net-tools
sudo systemctl enable chronyStep 12: Configure Local SSH Config
步骤12:配置本地SSH配置
On the user's LOCAL machine:
bash
cat >> ~/.ssh/config << 'EOF'
Host {nickname}
HostName {SERVER_IP}
User {username}
IdentityFile ~/.ssh/{nickname}_key
IdentitiesOnly yes
EOFTell user: Теперь подключайся командой -- без пароля и IP.
ssh {nickname}在用户的本地电脑上执行:
bash
cat >> ~/.ssh/config << 'EOF'
Host {nickname}
HostName {SERVER_IP}
User {username}
IdentityFile ~/.ssh/{nickname}_key
IdentitiesOnly yes
EOF告知用户:现在你可以使用命令连接服务器——无需输入密码和IP。
ssh {nickname}Step 13: Final Verification
步骤13:最终验证
Connect as new user and run quick audit:
bash
ssh {nickname}以新用户身份连接并运行快速审计:
bash
ssh {nickname}Then on server:
然后在服务器上执行:
sudo ufw status
sudo sysctl net.ipv4.conf.all.rp_filter
Expected: ufw active, rp_filter = 1.
**Note:** SSH lockdown и fail2ban проверяются в конце (Step 22) после подтверждения работы SSH-ключа.
**Часть 1 завершена. Базовая настройка сервера готова. Переходим к установке VPN.**
---sudo ufw status
sudo sysctl net.ipv4.conf.all.rp_filter
预期结果:ufw处于活跃状态,rp_filter = 1。
**注意:** SSH锁定与fail2ban的检查将在末尾(步骤22)完成,需在SSH密钥确认可用后执行。
**第一部分完成。服务器基础配置已就绪。接下来进行VPN安装。**
---PART 2: VPN Installation (3x-ui)
第二部分:VPN安装(3x-ui)
All commands from here use -- the shortcut configured in Part 1.
ssh {nickname}从本部分开始,所有命令均使用——即第一部分中配置的快捷方式。
ssh {nickname}Step 14: Install 3x-ui
步骤14:安装3x-ui
3x-ui install script requires root. Run with sudo:
bash
ssh {nickname} "curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh -o /tmp/3x-ui-install.sh && echo 'n' | sudo bash /tmp/3x-ui-install.sh"The answers "no" to port customization prompt -- a random port and credentials will be generated.
echo 'n'Note: Do NOT use -- process substitution does not work with sudo (file descriptors are not inherited).
sudo bash <(curl ...)IMPORTANT: Capture the output! It contains:
- Generated username
- Generated password
- Panel port
- Panel web base path
Extract and save these values. Show them to the user:
Данные панели 3x-ui (СОХРАНИ!):
Username: {panel_username}
Password: {panel_password}
Port: {panel_port}
Path: {web_base_path}
URL: https://127.0.0.1:{panel_port}/{web_base_path} (через SSH-туннель)Verify 3x-ui is running:
bash
ssh {nickname} "sudo x-ui status"If not running:
ssh {nickname} "sudo x-ui start"Panel port is NOT opened in firewall intentionally -- access panel only via SSH tunnel for security.
3x-ui安装脚本需要root权限,使用sudo执行:
bash
ssh {nickname} "curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh -o /tmp/3x-ui-install.sh && echo 'n' | sudo bash /tmp/3x-ui-install.sh"echo 'n'注意: 请勿使用——进程替换与sudo不兼容(文件描述符不会被继承)。
sudo bash <(curl ...)重要提示: 保存输出内容!其中包含:
- 生成的用户名
- 生成的密码
- 面板端口
- 面板web基础路径
提取并保存这些值,展示给用户:
3x-ui面板信息(务必保存!):
用户名: {panel_username}
密码: {panel_password}
端口: {panel_port}
路径: {web_base_path}
URL: https://127.0.0.1:{panel_port}/{web_base_path}(通过SSH隧道访问)验证3x-ui是否运行:
bash
ssh {nickname} "sudo x-ui status"若未运行:
ssh {nickname} "sudo x-ui start"面板端口未在防火墙上开放——为安全起见,仅通过SSH隧道访问面板。
Step 14b: Enable BBR
步骤14b:启用BBR
BBR (Bottleneck Bandwidth and RTT) dramatically improves TCP throughput, especially on lossy links -- critical for VPN performance.
bash
ssh {nickname} 'current=$(sysctl -n net.ipv4.tcp_congestion_control); echo "Current: $current"; if [ "$current" != "bbr" ]; then echo "net.core.default_qdisc=fq" | sudo tee -a /etc/sysctl.conf && echo "net.ipv4.tcp_congestion_control=bbr" | sudo tee -a /etc/sysctl.conf && sudo sysctl -p && echo "BBR enabled"; else echo "BBR already active"; fi'Verify:
bash
ssh {nickname} "sysctl net.ipv4.tcp_congestion_control net.core.default_qdisc"Expected: , .
net.ipv4.tcp_congestion_control = bbrnet.core.default_qdisc = fqBBR(Bottleneck Bandwidth and RTT)可显著提升TCP吞吐量,尤其是在丢包链路中——对VPN性能至关重要。
bash
ssh {nickname} 'current=$(sysctl -n net.ipv4.tcp_congestion_control); echo "当前配置: $current"; if [ "$current" != "bbr" ]; then echo "net.core.default_qdisc=fq" | sudo tee -a /etc/sysctl.conf && echo "net.ipv4.tcp_congestion_control=bbr" | sudo tee -a /etc/sysctl.conf && sudo sysctl -p && echo "BBR已启用"; else echo "BBR已处于活跃状态"; fi'验证:
bash
ssh {nickname} "sysctl net.ipv4.tcp_congestion_control net.core.default_qdisc"预期结果:,。
net.ipv4.tcp_congestion_control = bbrnet.core.default_qdisc = fqStep 15: Disable ICMP (Stealth)
步骤15:禁用ICMP(隐身模式)
Makes server invisible to ping scans:
bash
ssh {nickname} "sudo sed -i 's/-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT/-A ufw-before-input -p icmp --icmp-type echo-request -j DROP/' /etc/ufw/before.rules && sudo sed -i 's/-A ufw-before-forward -p icmp --icmp-type echo-request -j ACCEPT/-A ufw-before-forward -p icmp --icmp-type echo-request -j DROP/' /etc/ufw/before.rules && sudo ufw reload"Verify:
bash
ping -c 2 -W 2 {SERVER_IP}Expected: no response (timeout).
使服务器对ping扫描不可见:
bash
ssh {nickname} "sudo sed -i 's/-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT/-A ufw-before-input -p icmp --icmp-type echo-request -j DROP/' /etc/ufw/before.rules && sudo sed -i 's/-A ufw-before-forward -p icmp --icmp-type echo-request -j ACCEPT/-A ufw-before-forward -p icmp --icmp-type echo-request -j DROP/' /etc/ufw/before.rules && sudo ufw reload"验证:
bash
ping -c 2 -W 2 {SERVER_IP}预期结果:无响应(超时)。
Step 16: Branch -- Reality or TLS
步骤16:分支选择——Reality或TLS
Path A: VLESS Reality (NO domain needed) -- RECOMMENDED
路径A:VLESS Reality(无需域名)——推荐使用
Go to Step 17A.
进入步骤17A。
Path B: VLESS TLS (domain required)
路径B:VLESS TLS(需域名)
Go to .
references/vless-tls.md参考。
references/vless-tls.mdStep 17A: Find Best SNI with Reality Scanner
步骤17A:使用Reality扫描器寻找最佳SNI
Scan the server's /24 subnet to find real websites on neighboring IPs that support TLS 1.3, H2 (HTTP/2), and X25519 -- the exact stack Reality needs to mimic a genuine TLS handshake. The found domain becomes the masquerade target (SNI/dest), making VPN traffic indistinguishable from regular HTTPS to a neighboring site on the same hosting.
Why subnet scanning matters:
- Reality reproduces a real TLS 1.3 handshake with the dest server -- the dest must support TLS 1.3 + H2 + X25519, or Reality won't work
- RealiTLScanner (from the XTLS project) checks exactly this -- it only outputs servers compatible with Reality
- DPI sees the SNI in TLS ClientHello and can probe the IP to verify the domain actually lives there
- Popular domains (microsoft.com, google.com) are often on CDN IPs far from the VPS -- active probing catches this
- A small unknown site on a neighboring IP (e.g., ) is ideal -- nobody filters it, and it's in the same subnet
shop.finn-auto.fi - Do NOT manually pick an SNI without the scanner -- a random domain may not support TLS 1.3 or may be on a different IP range
Download and run Reality Scanner against the /24 subnet:
Remote mode (Claude Code on user's laptop):
bash
ssh {nickname} 'ARCH=$(dpkg --print-architecture); case "$ARCH" in amd64) SA="64";; arm64|aarch64) SA="arm64-v8a";; *) SA="$ARCH";; esac && curl -sL "https://github.com/XTLS/RealiTLScanner/releases/latest/download/RealiTLScanner-linux-${SA}" -o /tmp/scanner && chmod +x /tmp/scanner && file /tmp/scanner | grep -q ELF || { echo "ERROR: scanner binary not valid for this architecture"; exit 1; }; MY_IP=$(curl -4 -s ifconfig.me); SUBNET=$(echo $MY_IP | sed "s/\.[0-9]*$/.0\/24/"); echo "Scanning subnet: $SUBNET"; timeout 120 /tmp/scanner --addr "$SUBNET" 2>&1 | head -80'Local mode (Claude Code on the VPS itself):
bash
ARCH=$(dpkg --print-architecture); case "$ARCH" in amd64) SA="64";; arm64|aarch64) SA="arm64-v8a";; *) SA="$ARCH";; esac && curl -sL "https://github.com/XTLS/RealiTLScanner/releases/latest/download/RealiTLScanner-linux-${SA}" -o /tmp/scanner && chmod +x /tmp/scanner && file /tmp/scanner | grep -q ELF || { echo "ERROR: scanner binary not valid for this architecture"; exit 1; }; MY_IP=$(curl -4 -s ifconfig.me); SUBNET=$(echo $MY_IP | sed "s/\.[0-9]*$/.0\/24/"); echo "Scanning subnet: $SUBNET"; timeout 120 /tmp/scanner --addr "$SUBNET" 2>&1 | head -80Note: The commands are identical — Local mode simply runs without the wrapper since Claude Code is already on the VPS. GitHub releases use non-standard arch names ( instead of , instead of ). The block maps them. The check ensures the download is a real binary, not a 404 HTML page. Timeout is 120s because scanning 254 IPs takes longer than a single IP.
ssh {nickname}64amd64arm64-v8aarm64casefile | grep ELF扫描服务器的**/24子网**,寻找相邻IP上支持TLS 1.3、H2(HTTP/2)和X25519的真实网站——这些是Reality模拟真实TLS握手所需的精确协议栈。找到的域名将作为伪装目标(SNI/目标),使VPN流量与访问同一主机上相邻站点的常规HTTPS流量无法区分。
为什么子网扫描很重要:
- Reality会与目标服务器重现真实的TLS 1.3握手——目标服务器必须支持TLS 1.3 + H2 + X25519,否则Reality无法正常工作
- RealiTLScanner(来自XTLS项目)会精确检查这些条件——仅输出与Reality兼容的服务器
- DPI会在TLS ClientHello中查看SNI,并可探测IP以验证域名是否确实存在于该IP上
- 热门域名(如microsoft.com、google.com)通常位于远离VPS的CDN IP上——主动探测会发现这一点
- 同一子网中的小型未知站点(例如)是理想选择——无人会过滤此类站点,且与VPS位于同一子网
shop.finn-auto.fi - 请勿手动选择SNI而不使用扫描器——随机域名可能不支持TLS 1.3,或位于不同的IP段
下载并运行Reality扫描器对/24子网进行扫描:
远程模式(Claude Code在用户笔记本上):
bash
ssh {nickname} 'ARCH=$(dpkg --print-architecture); case "$ARCH" in amd64) SA="64";; arm64|aarch64) SA="arm64-v8a";; *) SA="$ARCH";; esac && curl -sL "https://github.com/XTLS/RealiTLScanner/releases/latest/download/RealiTLScanner-linux-${SA}" -o /tmp/scanner && chmod +x /tmp/scanner && file /tmp/scanner | grep -q ELF || { echo "错误:扫描器二进制文件与当前架构不兼容"; exit 1; }; MY_IP=$(curl -4 -s ifconfig.me); SUBNET=$(echo $MY_IP | sed "s/\.[0-9]*$/.0\/24/"); echo "正在扫描子网: $SUBNET"; timeout 120 /tmp/scanner --addr "$SUBNET" 2>&1 | head -80'本地模式(Claude Code在VPS上):
bash
ARCH=$(dpkg --print-architecture); case "$ARCH" in amd64) SA="64";; arm64|aarch64) SA="arm64-v8a";; *) SA="$ARCH";; esac && curl -sL "https://github.com/XTLS/RealiTLScanner/releases/latest/download/RealiTLScanner-linux-${SA}" -o /tmp/scanner && chmod +x /tmp/scanner && file /tmp/scanner | grep -q ELF || { echo "错误:扫描器二进制文件与当前架构不兼容"; exit 1; }; MY_IP=$(curl -4 -s ifconfig.me); SUBNET=$(echo $MY_IP | sed "s/\.[0-9]*$/.0\/24/"); echo "正在扫描子网: $SUBNET"; timeout 120 /tmp/scanner --addr "$SUBNET" 2>&1 | head -80注意: 两种模式的命令完全相同——本地模式仅需去掉包装,因为Claude Code已在VPS上运行。GitHub发布使用非标准架构名称(代替,代替)。块用于映射这些名称。检查确保下载的是真实的二进制文件,而非404 HTML页面。超时设置为120秒,因为扫描254个IP所需时间较长。
ssh {nickname}64amd64arm64-v8aarm64casefile | grep ELFChoosing the best SNI from scan results
从扫描结果中选择最佳SNI
Every domain in the scanner output already supports TLS 1.3 + H2 + X25519 (the scanner filters for this). From those results, prefer domains in this order:
- Small unknown sites on neighboring IPs (e.g., ,
shop.finn-auto.fi) -- ideal, not filtered by DPIportal.company.de - Regional/niche services (e.g., local hosting panels, small business sites) -- low profile
- Well-known tech sites (e.g., ,
github.com) -- acceptable but less idealtwitch.tv
AVOID these as SNI:
- ,
www.google.com,www.microsoft.com-- commonly blacklisted by DPI, people in Amnezia chats report these stop workinggoogletagmanager.com - Any domain behind a CDN (Cloudflare, Akamai, Fastly) -- the IP won't match the CDN edge, active probing detects this
- Domains that resolve to a completely different IP range than the VPS
How to verify a candidate SNI: The scanner output shows which IP responded with which domain. Pick a domain where the responding IP is in the same /24 as the VPS.
If scanner finds nothing or times out -- some providers (e.g., OVH) have sparse subnets. Try scanning a wider range (512 IPs):
/23Remote mode:
bash
ssh {nickname} 'MY_IP=$(curl -4 -s ifconfig.me); SUBNET=$(echo $MY_IP | sed "s/\.[0-9]*$/.0\/23/"); timeout 180 /tmp/scanner --addr "$SUBNET" 2>&1 | head -80'Local mode:
bash
MY_IP=$(curl -4 -s ifconfig.me); SUBNET=$(echo $MY_IP | sed "s/\.[0-9]*$/.0\/23/"); timeout 180 /tmp/scanner --addr "$SUBNET" 2>&1 | head -80If still nothing, use as a last-resort fallback -- it supports TLS 1.3 and resolves to many IPs globally, and is less commonly filtered than google/microsoft. But always prefer a real neighbor from the scan -- a neighbor is guaranteed to be in the same subnet and verified by the scanner for TLS 1.3 + H2 + X25519 compatibility.
www.yahoo.comSave the best SNI for the next step.
扫描结果中的每个域名均已支持TLS 1.3 + H2 + X25519(扫描器已过滤)。从这些结果中,优先选择以下顺序的域名:
- 相邻IP上的小型未知站点(例如、
shop.finn-auto.fi)——理想选择,不会被DPI过滤portal.company.de - 区域/ niche服务(例如本地主机面板、小型企业网站)——低关注度
- 知名科技站点(例如、
github.com)——可接受但并非最佳选择twitch.tv
避免选择以下SNI:
- 、
www.google.com、www.microsoft.com——常被DPI列入黑名单,Amnezia聊天用户反馈这些域名会失效googletagmanager.com - 任何位于CDN后的域名(Cloudflare、Akamai、Fastly)——IP与CDN边缘不匹配,主动探测会发现这一点
- 解析到与VPS完全不同IP段的域名
如何验证候选SNI: 扫描结果会显示哪个IP响应了哪个域名。选择与VPS位于同一/24子网的域名。
若扫描器未找到结果或超时——部分服务商(例如OVH)的子网较为稀疏。尝试扫描更广泛的范围(512个IP):
/23远程模式:
bash
ssh {nickname} 'MY_IP=$(curl -4 -s ifconfig.me); SUBNET=$(echo $MY_IP | sed "s/\.[0-9]*$/.0\/23/"); timeout 180 /tmp/scanner --addr "$SUBNET" 2>&1 | head -80'本地模式:
bash
MY_IP=$(curl -4 -s ifconfig.me); SUBNET=$(echo $MY_IP | sed "s/\.[0-9]*$/.0\/23/"); timeout 180 /tmp/scanner --addr "$SUBNET" 2>&1 | head -80若仍未找到结果,可使用作为最后的备选——它支持TLS 1.3,且在全球拥有多个解析IP,相比谷歌/微软域名被过滤的概率更低。但始终优先选择扫描到的真实相邻站点——相邻站点确保与VPS位于同一子网,且已被扫描器验证支持TLS 1.3 + H2 + X25519。
www.yahoo.com保存最佳SNI以备下一步使用。
Step 18A: Create VLESS Reality Inbound via API
步骤18A:通过API创建VLESS Reality入站规则
Pre-check: Verify port 443 is not occupied by another service (some providers pre-install apache2/nginx):
bash
ssh {nickname} "ss -tlnp | grep ':443 '"If something is listening on 443, stop and disable it first (e.g., ). Otherwise the VLESS inbound will silently fail to bind.
sudo systemctl stop apache2 && sudo systemctl disable apache23x-ui has an API. Since v2.8+, the installer auto-configures SSL, so the panel runs on HTTPS. Use to skip certificate verification (self-signed cert on localhost).
-kFirst, get session cookie:
bash
ssh {nickname} 'PANEL_PORT={panel_port}; curl -sk -c /tmp/3x-cookie -b /tmp/3x-cookie -X POST "https://127.0.0.1:${PANEL_PORT}/{web_base_path}/login" -H "Content-Type: application/x-www-form-urlencoded" -d "username={panel_username}&password={panel_password}"'Generate keys for Reality:
bash
ssh {nickname} "sudo /usr/local/x-ui/bin/xray-linux-* x25519"This outputs two lines: = private key, = public key (confusing naming by xray). Save both.
PrivateKeyPasswordGenerate UUID for the client:
bash
ssh {nickname} "sudo /usr/local/x-ui/bin/xray-linux-* uuid"Generate random Short ID:
bash
ssh {nickname} "openssl rand -hex 8"Create the inbound:
bash
ssh {nickname} 'PANEL_PORT={panel_port}; curl -sk -c /tmp/3x-cookie -b /tmp/3x-cookie -X POST "https://127.0.0.1:${PANEL_PORT}/{web_base_path}/panel/api/inbounds/add" -H "Content-Type: application/json" -d '"'"'{
"up": 0,
"down": 0,
"total": 0,
"remark": "vless-reality",
"enable": true,
"expiryTime": 0,
"listen": "",
"port": 443,
"protocol": "vless",
"settings": "{\"clients\":[{\"id\":\"{CLIENT_UUID}\",\"flow\":\"xtls-rprx-vision\",\"email\":\"user1\",\"limitIp\":0,\"totalGB\":0,\"expiryTime\":0,\"enable\":true}],\"decryption\":\"none\",\"fallbacks\":[]}",
"streamSettings": "{\"network\":\"tcp\",\"security\":\"reality\",\"externalProxy\":[],\"realitySettings\":{\"show\":false,\"xver\":0,\"dest\":\"{BEST_SNI}:443\",\"serverNames\":[\"{BEST_SNI}\"],\"privateKey\":\"{PRIVATE_KEY}\",\"minClient\":\"\",\"maxClient\":\"\",\"maxTimediff\":0,\"shortIds\":[\"{SHORT_ID}\"],\"settings\":{\"publicKey\":\"{PUBLIC_KEY}\",\"fingerprint\":\"chrome\",\"serverName\":\"\",\"spiderX\":\"/\"}},\"tcpSettings\":{\"acceptProxyProtocol\":false,\"header\":{\"type\":\"none\"}}}",
"sniffing": "{\"enabled\":true,\"destOverride\":[\"http\",\"tls\",\"quic\",\"fakedns\"],\"metadataOnly\":false,\"routeOnly\":false}",
"allocate": "{\"strategy\":\"always\",\"refresh\":5,\"concurrency\":3}"
}'"'"''If API approach fails -- tell user to access panel via SSH tunnel (Step 18A-alt).
预检查: 验证端口443未被其他服务占用(部分服务商预装了apache2/nginx):
bash
ssh {nickname} "ss -tlnp | grep ':443 '"若443端口被占用,先停止并禁用该服务(例如)。否则VLESS入站规则将静默绑定失败。
sudo systemctl stop apache2 && sudo systemctl disable apache23x-ui提供API。从v2.8+版本开始,安装程序会自动配置SSL,因此面板运行在HTTPS上。使用跳过证书验证(本地主机使用自签名证书)。
-k首先,获取会话cookie:
bash
ssh {nickname} 'PANEL_PORT={panel_port}; curl -sk -c /tmp/3x-cookie -b /tmp/3x-cookie -X POST "https://127.0.0.1:${PANEL_PORT}/{web_base_path}/login" -H "Content-Type: application/x-www-form-urlencoded" -d "username={panel_username}&password={panel_password}"'生成Reality密钥:
bash
ssh {nickname} "sudo /usr/local/x-ui/bin/xray-linux-* x25519"输出包含两行: = 私钥, = 公钥(xray的命名方式易混淆)。保存这两个值。
PrivateKeyPassword为客户端生成UUID:
bash
ssh {nickname} "sudo /usr/local/x-ui/bin/xray-linux-* uuid"生成随机Short ID:
bash
ssh {nickname} "openssl rand -hex 8"创建入站规则:
bash
ssh {nickname} 'PANEL_PORT={panel_port}; curl -sk -c /tmp/3x-cookie -b /tmp/3x-cookie -X POST "https://127.0.0.1:${PANEL_PORT}/{web_base_path}/panel/api/inbounds/add" -H "Content-Type: application/json" -d '"'"'{
"up": 0,
"down": 0,
"total": 0,
"remark": "vless-reality",
"enable": true,
"expiryTime": 0,
"listen": "",
"port": 443,
"protocol": "vless",
"settings": "{\"clients\":[{\"id\":\"{CLIENT_UUID}\",\"flow\":\"xtls-rprx-vision\",\"email\":\"user1\",\"limitIp\":0,\"totalGB\":0,\"expiryTime\":0,\"enable\":true}],\"decryption\":\"none\",\"fallbacks\":[]}",
"streamSettings": "{\"network\":\"tcp\",\"security\":\"reality\",\"externalProxy\":[],\"realitySettings\":{\"show\":false,\"xver\":0,\"dest\":\"{BEST_SNI}:443\",\"serverNames\":[\"{BEST_SNI}\"],\"privateKey\":\"{PRIVATE_KEY}\",\"minClient\":\"\",\"maxClient\":\"\",\"maxTimediff\":0,\"shortIds\":[\"{SHORT_ID}\"],\"settings\":{\"publicKey\":\"{PUBLIC_KEY}\",\"fingerprint\":\"chrome\",\"serverName\":\"\",\"spiderX\":\"/\"}},\"tcpSettings\":{\"acceptProxyProtocol\":false,\"header\":{\"type\":\"none\"}}}",
"sniffing": "{\"enabled\":true,\"destOverride\":[\"http\",\"tls\",\"quic\",\"fakedns\"],\"metadataOnly\":false,\"routeOnly\":false}",
"allocate": "{\"strategy\":\"always\",\"refresh\":5,\"concurrency\":3}"
}'"'"''若API方法失败——告知用户通过SSH隧道访问面板(步骤18A-alt)。
Step 18A-alt: SSH Tunnel to Panel (manual fallback)
步骤18A-alt:通过SSH隧道访问面板(手动备选方案)
If API fails, user can access panel in browser:
bash
ssh -L {panel_port}:127.0.0.1:{panel_port} {nickname}Then open in browser: (browser will warn about self-signed cert -- accept it)
https://127.0.0.1:{panel_port}/{web_base_path}Guide user through the UI:
- Login with generated credentials
- Inbounds -> Add Inbound
- Protocol: VLESS
- Port: 443
- Security: Reality
- Client Flow: xtls-rprx-vision
- Target & SNI: paste the best SNI from scanner
- Click "Get New Cert" for keys
- Create
若API失败,用户可在浏览器中访问面板:
bash
ssh -L {panel_port}:127.0.0.1:{panel_port} {nickname}然后在浏览器中打开:(浏览器会警告自签名证书——接受即可)
https://127.0.0.1:{panel_port}/{web_base_path}引导用户完成UI操作:
- 使用生成的凭证登录
- 进入Inbounds(入站规则)→ Add Inbound(添加入站规则)
- 协议:VLESS
- 端口:443
- 安全:Reality
- 客户端流:xtls-rprx-vision
- 目标与SNI:粘贴扫描得到的最佳SNI
- 点击"Get New Cert"(获取新证书)生成密钥
- 创建
Step 19: Get Connection Link
步骤19:获取连接链接
Get the client connection link from 3x-ui API:
bash
ssh {nickname} 'PANEL_PORT={panel_port}; curl -sk -b /tmp/3x-cookie "https://127.0.0.1:${PANEL_PORT}/{web_base_path}/panel/api/inbounds/list" | python3 -c "
import json,sys
data = json.load(sys.stdin)
for inb in data.get(\"obj\", []):
if inb.get(\"protocol\") == \"vless\":
settings = json.loads(inb[\"settings\"])
stream = json.loads(inb[\"streamSettings\"])
client = settings[\"clients\"][0]
uuid = client[\"id\"]
port = inb[\"port\"]
security = stream.get(\"security\", \"none\")
if security == \"reality\":
rs = stream[\"realitySettings\"]
sni = rs[\"serverNames\"][0]
pbk = rs[\"settings\"][\"publicKey\"]
sid = rs[\"shortIds\"][0]
fp = rs[\"settings\"].get(\"fingerprint\", \"chrome\")
flow = client.get(\"flow\", \"\")
link = f\"vless://{uuid}@$(curl -4 -s ifconfig.me):{port}?type=tcp&security=reality&pbk={pbk}&fp={fp}&sni={sni}&sid={sid}&spx=%2F&flow={flow}#vless-reality\"
print(link)
break
"'Show the link to the user. This is what they'll paste into Hiddify.
IMPORTANT: Terminal line-wrap fix. Long VLESS links break when copied from terminal. ALWAYS provide the link in TWO formats:
- The raw link (for reference)
- A ready-to-copy block with LLM cleanup prompt:
Скопируй всё ниже и вставь в любой LLM (ChatGPT, Claude) чтобы получить чистую ссылку:
Убери все переносы строк и лишние пробелы из этой ссылки, выдай одной строкой:
{VLESS_LINK}Also save the link to a file for easy access:
bash
ssh {nickname} "echo '{VLESS_LINK}' > ~/vpn-link.txt"Tell the user: Ссылка также сохранена в файл ~/vpn-link.txt
Cleanup session cookie:
bash
ssh {nickname} "rm -f /tmp/3x-cookie"从3x-ui API获取客户端连接链接:
bash
ssh {nickname} 'PANEL_PORT={panel_port}; curl -sk -b /tmp/3x-cookie "https://127.0.0.1:${PANEL_PORT}/{web_base_path}/panel/api/inbounds/list" | python3 -c "
import json,sys
data = json.load(sys.stdin)
for inb in data.get(\"obj\", []):
if inb.get(\"protocol\") == \"vless\":
settings = json.loads(inb[\"settings\"])
stream = json.loads(inb[\"streamSettings\"])
client = settings[\"clients\"][0]
uuid = client[\"id\"]
port = inb[\"port\"]
security = stream.get(\"security\", \"none\")
if security == \"reality\":
rs = stream[\"realitySettings\"]
sni = rs[\"serverNames\"][0]
pbk = rs[\"settings\"][\"publicKey\"]
sid = rs[\"shortIds\"][0]
fp = rs[\"settings\"].get(\"fingerprint\", \"chrome\")
flow = client.get(\"flow\", \"\")
link = f\"vless://{uuid}@$(curl -4 -s ifconfig.me):{port}?type=tcp&security=reality&pbk={pbk}&fp={fp}&sni={sni}&sid={sid}&spx=%2F&flow={flow}#vless-reality\"
print(link)
break
"'将链接展示给用户。用户需要将此链接粘贴到Hiddify客户端中。
重要提示:修复终端换行问题。长VLESS链接从终端复制时会断裂。请始终以两种格式提供链接:
- 原始链接(仅供参考)
- 可直接复制的块,附带LLM清理提示:
复制以下所有内容并粘贴到任意LLM(ChatGPT、Claude)中以获取干净的链接:
请移除该链接中的所有换行符和多余空格,以单行形式输出:
{VLESS_LINK}同时将链接保存到文件中以便访问:
bash
ssh {nickname} "echo '{VLESS_LINK}' > ~/vpn-link.txt"告知用户:链接已保存到文件~/vpn-link.txt中
清理会话cookie:
bash
ssh {nickname} "rm -f /tmp/3x-cookie"Step 20: Guide User -- Install Hiddify Client
步骤20:引导用户安装Hiddify客户端
Tell the user:
Теперь установи клиент Hiddify на своё устройство:
Android: Google Play -> "Hiddify" или https://github.com/hiddify/hiddify-app/releases
iOS: App Store -> "Hiddify"
Windows: https://github.com/hiddify/hiddify-app/releases (скачай .exe)
macOS: https://github.com/hiddify/hiddify-app/releases (скачай .dmg)
Linux: https://github.com/hiddify/hiddify-app/releases (.deb или .AppImage)
После установки:
1. Открой Hiddify
2. Нажми "+" или "Add Profile"
3. Выбери "Add from clipboard" (ссылка уже скопирована)
4. Или отсканируй QR-код (я могу его показать)
5. Нажми кнопку подключения (большая кнопка в центре)
6. Готово! Проверь IP на сайте: https://2ip.ru告知用户:
现在请在你的设备上安装Hiddify客户端:
Android: Google Play搜索"Hiddify",或访问https://github.com/hiddify/hiddify-app/releases
iOS: App Store搜索"Hiddify"
Windows: 访问https://github.com/hiddify/hiddify-app/releases(下载.exe文件)
macOS: 访问https://github.com/hiddify/hiddify-app/releases(下载.dmg文件)
Linux: 访问https://github.com/hiddify/hiddify-app/releases(下载.deb或.AppImage文件)
安装完成后:
1. 打开Hiddify
2. 点击"+"或"Add Profile"(添加配置文件)
3. 选择"Add from clipboard"(从剪贴板添加)(链接已复制)
4. 或扫描QR码(我可以为你展示)
5. 点击连接按钮(中央的大按钮)
6. 完成!访问https://2ip.ru验证IPStep 21: Verify Connection Works
步骤21:验证连接是否正常工作
After user connects via Hiddify, verify:
bash
ssh {nickname} "sudo x-ui status && ss -tlnp | grep -E '443|{panel_port}'"用户通过Hiddify连接后,进行验证:
bash
ssh {nickname} "sudo x-ui status && ss -tlnp | grep -E '443|{panel_port}'"Step 22: Generate Guide File & Finalize SSH Access
步骤22:生成指南文件并完成SSH访问配置
This step generates a comprehensive guide file with all credentials and instructions, then finalizes SSH key-based access.
本步骤将生成包含所有凭证和说明的综合指南文件,然后完成基于SSH密钥的访问配置。
Remote Mode
远程模式
22R-1: Generate guide file locally
Use the Write tool to create on the user's local machine. Use the Guide File Template below, substituting all with actual values.
~/vpn-{nickname}-guide.md{variables}Tell user: Методичка сохранена в ~/vpn-{nickname}-guide.md — там все пароли, доступы и инструкции.
22R-2: Final lockdown — fail2ban + SSH
Verify SSH key access works:
bash
ssh {nickname} "echo 'SSH key access OK'"If successful, install fail2ban and lock SSH:
bash
ssh {nickname} 'sudo apt install -y fail2ban && sudo tee /etc/fail2ban/jail.local << JAILEOF
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 24h
JAILEOF
sudo systemctl enable fail2ban && sudo systemctl restart fail2ban'bash
ssh {nickname} 'sudo sed -i "s/^#\?PermitRootLogin.*/PermitRootLogin no/" /etc/ssh/sshd_config && sudo sed -i "s/^#\?PasswordAuthentication.*/PasswordAuthentication no/" /etc/ssh/sshd_config && sudo systemctl restart sshd'Verify lockdown + SSH still works:
bash
ssh {nickname} "grep -E 'PermitRootLogin|PasswordAuthentication' /etc/ssh/sshd_config && sudo systemctl status fail2ban --no-pager -l && echo 'Lockdown OK'"22R-1:在本地生成指南文件
使用写入工具在用户本地电脑创建。使用以下指南文件模板,将所有替换为实际值。
~/vpn-{nickname}-guide.md{variables}告知用户:指南文件已保存到~/vpn-{nickname}-guide.md中——其中包含所有密码、访问信息和操作说明。
22R-2:最终锁定——安装fail2ban并配置SSH
验证SSH密钥访问是否正常:
bash
ssh {nickname} "echo 'SSH密钥访问正常'"若验证成功,安装fail2ban并锁定SSH:
bash
ssh {nickname} 'sudo apt install -y fail2ban && sudo tee /etc/fail2ban/jail.local << JAILEOF
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 24h
JAILEOF
sudo systemctl enable fail2ban && sudo systemctl restart fail2ban'bash
ssh {nickname} 'sudo sed -i "s/^#\?PermitRootLogin.*/PermitRootLogin no/" /etc/ssh/sshd_config && sudo sed -i "s/^#\?PasswordAuthentication.*/PasswordAuthentication no/" /etc/ssh/sshd_config && sudo systemctl restart sshd'验证锁定配置 + SSH是否仍正常工作:
bash
ssh {nickname} "grep -E 'PermitRootLogin|PasswordAuthentication' /etc/ssh/sshd_config && sudo systemctl status fail2ban --no-pager -l && echo '锁定配置正常'"Local Mode
本地模式
In Local mode, Claude Code runs on the server. SSH lockdown was skipped (Step 7), so password auth still works. The flow:
本地模式下,Claude Code运行在服务器上。SSH锁定已被跳过(步骤7),因此密码认证仍可用。流程如下:
22L-1: Generate guide file on server
22L-1:在服务器上生成指南文件
Use the Write tool to create on the server. Use the Guide File Template below, substituting all with actual values.
/home/{username}/vpn-guide.md{variables}使用写入工具在服务器上创建。使用以下指南文件模板,将所有替换为实际值。
/home/{username}/vpn-guide.md{variables}22L-2: User downloads guide via SCP
22L-2:用户通过SCP下载指南文件
Tell the user:
Методичка готова! Скачай её на свой компьютер.
Открой НОВЫЙ терминал на своём ноутбуке и выполни:
scp {username}@{SERVER_IP}:~/vpn-guide.md ./
Пароль: {sudo_password}
Файл сохранится в текущую папку. Открой его -- там все пароли и инструкции.Fallback: If SCP doesn't work (Windows without OpenSSH, network issues), show the full guide content directly in chat.
告知用户:
指南文件已准备好!请将其下载到你的电脑上。
在你的笔记本电脑上打开一个**新终端**并执行:
scp {username}@{SERVER_IP}:~/vpn-guide.md ./
密码:{sudo_password}
文件将保存到当前目录。打开文件——其中包含所有密码和操作说明。备选方案: 若SCP无法工作(Windows未安装OpenSSH、网络问题),直接在聊天中展示完整的指南内容。
22L-3: User creates SSH key on their laptop
22L-3:用户在笔记本电脑上创建SSH密钥
Tell the user:
Теперь создай SSH-ключ на своём компьютере.
Есть два варианта:
Вариант А: Следуй инструкциям из раздела "SSH Key Setup" в методичке.
Вариант Б (автоматический): Установи Claude Code на ноутбуке
(https://claude.ai/download) и скинь ему файл vpn-guide.md --
он сам всё настроит по инструкциям из раздела "Instructions for Claude Code".
После создания ключа отправь публичный ключ на сервер (следующий шаг).告知用户:
现在请在你的电脑上创建SSH密钥。
有两种选择:
选项A:按照指南文件中"SSH密钥配置"部分的说明操作。
选项B(自动方式):在笔记本电脑上安装Claude Code
(https://claude.ai/download),然后将vpn-guide.md文件发送给它——
它会根据指南文件中"Claude Code操作说明"部分自动完成所有配置。
创建密钥后,将公钥发送到服务器(下一步)。22L-4: User sends public key to server via SCP
22L-4:用户通过SCP将公钥发送到服务器
Tell the user:
Отправь публичный ключ на сервер (из терминала на ноутбуке):
scp ~/.ssh/{nickname}_key.pub {username}@{SERVER_IP}:~/
Пароль: {sudo_password}Wait for user confirmation before proceeding.
告知用户:
将公钥发送到服务器(在笔记本电脑的终端中执行):
scp ~/.ssh/{nickname}_key.pub {username}@{SERVER_IP}:~/
密码:{sudo_password}等待用户确认后再继续。
22L-5: Install key + verify
22L-5:安装密钥 + 验证
bash
mkdir -p /home/{username}/.ssh
cat /home/{username}/{nickname}_key.pub >> /home/{username}/.ssh/authorized_keys
chmod 700 /home/{username}/.ssh
chmod 600 /home/{username}/.ssh/authorized_keys
chown -R {username}:{username} /home/{username}/.ssh
rm -f /home/{username}/{nickname}_key.pubTell user to test from their laptop:
Проверь подключение с ноутбука:
ssh -i ~/.ssh/{nickname}_key {username}@{SERVER_IP}
Должно подключиться без пароля.Wait for user confirmation that SSH key works before proceeding!
bash
mkdir -p /home/{username}/.ssh
cat /home/{username}/{nickname}_key.pub >> /home/{username}/.ssh/authorized_keys
chmod 700 /home/{username}/.ssh
chmod 600 /home/{username}/.ssh/authorized_keys
chown -R {username}:{username} /home/{username}/.ssh
rm -f /home/{username}/{nickname}_key.pub告知用户在笔记本电脑上测试:
验证从笔记本电脑的连接:
ssh -i ~/.ssh/{nickname}_key {username}@{SERVER_IP}
应无需输入密码即可连接。等待用户确认SSH密钥正常工作后再继续!
22L-6: Final lockdown — fail2ban + SSH
22L-6:最终锁定——安装fail2ban并配置SSH
Only after user confirms key-based login works!
Install fail2ban:
bash
sudo apt install -y fail2ban
sudo tee /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 24h
EOF
sudo systemctl enable fail2ban
sudo systemctl restart fail2banLock SSH:
bash
sudo sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshdVerify:
bash
grep -E "PermitRootLogin|PasswordAuthentication" /etc/ssh/sshd_config
sudo systemctl status fail2ban --no-pagerExpected: , , fail2ban active.
PermitRootLogin noPasswordAuthentication noTell user to verify SSH still works from laptop:
Проверь, что SSH-ключ всё ещё работает:
ssh {nickname}
Если подключился — всё настроено!仅在用户确认基于密钥的登录正常工作后执行!
安装fail2ban:
bash
sudo apt install -y fail2ban
sudo tee /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 24h
EOF
sudo systemctl enable fail2ban
sudo systemctl restart fail2ban锁定SSH:
bash
sudo sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd验证:
bash
grep -E "PermitRootLogin|PasswordAuthentication" /etc/ssh/sshd_config
sudo systemctl status fail2ban --no-pager预期结果:,,fail2ban处于活跃状态。
PermitRootLogin noPasswordAuthentication no告知用户在笔记本电脑上验证SSH是否仍正常工作:
验证SSH密钥是否仍正常工作:
ssh {nickname}
若能连接——则所有配置已完成!22L-7: User configures SSH config
22L-7:用户配置SSH配置
Tell the user:
Последний шаг! Добавь на ноутбуке в файл ~/.ssh/config:
Host {nickname}
HostName {SERVER_IP}
User {username}
IdentityFile ~/.ssh/{nickname}_key
IdentitiesOnly yes
Теперь подключайся просто: ssh {nickname}告知用户:
最后一步!在笔记本电脑的~/.ssh/config文件中添加以下内容:
Host {nickname}
HostName {SERVER_IP}
User {username}
IdentityFile ~/.ssh/{nickname}_key
IdentitiesOnly yes
现在你可以使用简单的命令连接:ssh {nickname}22L-8: Delete guide file from server
22L-8:从服务器删除指南文件
bash
rm -f /home/{username}/vpn-guide.mdTell user: Методичка удалена с сервера. Убедись, что она сохранена на твоём компьютере.
bash
rm -f /home/{username}/vpn-guide.md告知用户:指南文件已从服务器删除。请确保已将其保存到你的电脑上。
Guide File Template
指南文件模板
Generate this file using the Write tool, substituting all with actual values collected during setup.
{variables}markdown
undefined使用写入工具生成此文件,将所有替换为配置过程中收集的实际值。
{variables}markdown
undefinedМетодичка VPN-сервера — {nickname}
VPN服务器指南 —— {nickname}
Дата создания: {current_date}
创建日期:{current_date}
1. Подключение к серверу
1. 服务器连接
| Параметр | Значение |
|---|---|
| IP | |
| Пользователь | |
| Пароль sudo | |
| SSH-ключ | |
| Быстрое подключение | |
| 参数 | 值 |
|---|---|
| IP | |
| 用户 | |
| sudo密码 | |
| SSH密钥 | |
| 快速连接命令 | |
2. Панель 3x-ui
2. 3x-ui面板
| Параметр | Значение |
|---|---|
| URL | |
| Логин | |
| Пароль | |
Доступ через SSH-туннель:
ssh -L {panel_port}:127.0.0.1:{panel_port} {nickname}Затем открой:
https://127.0.0.1:{panel_port}/{web_base_path}| 参数 | 值 |
|---|---|
| URL | |
| 登录账号 | |
| 密码 | |
通过SSH隧道访问:
ssh -L {panel_port}:127.0.0.1:{panel_port} {nickname}然后打开:
https://127.0.0.1:{panel_port}/{web_base_path}3. VPN-подключение
3. VPN连接
| Параметр | Значение |
|---|---|
| Протокол | VLESS Reality |
| Порт | 443 |
| SNI | |
| Клиент | Hiddify |
Ссылка VLESS:
{VLESS_LINK}| 参数 | 值 |
|---|---|
| 协议 | VLESS Reality |
| 端口 | 443 |
| SNI | |
| 客户端 | Hiddify |
VLESS链接:
{VLESS_LINK}4. Настройка SSH-ключа
4. SSH密钥配置
Если у тебя ещё нет SSH-ключа, следуй инструкциям для своей ОС:
若你尚未拥有SSH密钥,请根据你的操作系统遵循以下说明:
macOS / Linux
macOS / Linux
bash
undefinedbash
undefinedСоздать ключ
创建密钥
ssh-keygen -t ed25519 -C "{username}@{nickname}" -f ~/.ssh/{nickname}_key -N ""
ssh-keygen -t ed25519 -C "{username}@{nickname}" -f ~/.ssh/{nickname}_key -N ""
Отправить публичный ключ на сервер
将公钥发送到服务器
scp /.ssh/{nickname}_key.pub {username}@{SERVER_IP}:/
scp /.ssh/{nickname}_key.pub {username}@{SERVER_IP}:/
Установить права
设置权限
chmod 600 ~/.ssh/{nickname}_key
chmod 600 ~/.ssh/{nickname}_key
Добавить в SSH-конфиг
添加到SSH配置
cat >> ~/.ssh/config << 'SSHEOF'
Host {nickname}
HostName {SERVER_IP}
User {username}
IdentityFile ~/.ssh/{nickname}_key
IdentitiesOnly yes
SSHEOF
cat >> ~/.ssh/config << 'SSHEOF'
Host {nickname}
HostName {SERVER_IP}
User {username}
IdentityFile ~/.ssh/{nickname}_key
IdentitiesOnly yes
SSHEOF
Проверить подключение
验证连接
ssh {nickname}
undefinedssh {nickname}
undefinedWindows (PowerShell)
Windows(PowerShell)
powershell
undefinedpowershell
undefinedСоздать ключ
创建密钥
ssh-keygen -t ed25519 -C "{username}@{nickname}" -f $HOME.ssh{nickname}_key -N '""'
ssh-keygen -t ed25519 -C "{username}@{nickname}" -f $HOME.ssh{nickname}_key -N '""'
Отправить публичный ключ на сервер
将公钥发送到服务器
scp $HOME.ssh{nickname}_key.pub {username}@{SERVER_IP}:~/
scp $HOME.ssh{nickname}_key.pub {username}@{SERVER_IP}:~/
Добавить в SSH-конфиг
添加到SSH配置
Add-Content $HOME.ssh\config @"
Host {nickname}
HostName {SERVER_IP}
User {username}
IdentityFile ~/.ssh/{nickname}_key
IdentitiesOnly yes
"@
Add-Content $HOME.ssh\config @"
Host {nickname}
HostName {SERVER_IP}
User {username}
IdentityFile ~/.ssh/{nickname}_key
IdentitiesOnly yes
"@
Проверить подключение
验证连接
ssh {nickname}
Примечание: `chmod` не нужен на Windows. SSH использует ACL автоматически.ssh {nickname}
注意:Windows无需使用`chmod`。SSH会自动使用ACL。5. Частые команды
5. 常用命令
bash
ssh {nickname} # подключиться к серверу
ssh {nickname} "sudo x-ui status" # статус панели
ssh {nickname} "sudo x-ui restart" # перезапустить панель
ssh {nickname} "sudo x-ui log" # логи
ssh {nickname} "sudo x-ui setting -reset" # сбросить пароль панелиДобавить нового VPN-клиента:
Открой панель через SSH-туннель → Inbounds → ... → Add Client → отправь ссылку/QR.
bash
ssh {nickname} # 连接服务器
ssh {nickname} "sudo x-ui status" # 查看面板状态
ssh {nickname} "sudo x-ui restart" # 重启面板
ssh {nickname} "sudo x-ui log" # 查看日志
ssh {nickname} "sudo x-ui setting -reset" # 重置面板密码添加新VPN客户端:
通过SSH隧道打开面板 → Inbounds(入站规则)→ ... → Add Client(添加客户端)→ 发送链接/QR码。
6. Статус безопасности
6. 安全状态
| Параметр | Статус |
|---|---|
| Вход под root | Отключён |
| Вход по паролю | Отключён |
| Файрвол UFW | Включён (SSH, 80, 443) |
| fail2ban | Включён (3 попытки → бан 24ч) |
| Усиление ядра | Включено (sysctl) |
| BBR | Включён |
| ICMP (ping) | Отключён |
| 参数 | 状态 |
|---|---|
| Root登录 | 已禁用 |
| 密码登录 | 已禁用 |
| UFW防火墙 | 已启用(开放SSH、80、443端口) |
| fail2ban | 已启用(3次失败尝试 → 封禁24小时) |
| 内核加固 | 已启用(sysctl) |
| BBR | 已启用 |
| ICMP(ping) | 已禁用 |
7. Решение проблем
7. 故障排除
| Проблема | Решение |
|---|---|
| Connection refused | |
| Permission denied (publickey) | Проверь путь и права ключа: |
| Host key verification failed | |
| Панель недоступна | Используй SSH-туннель (см. раздел 2) |
| VPN не подключается | Неверный SNI или сервер лежит — проверь |
| Забыл пароль панели | |
| 问题 | 解决方案 |
|---|---|
| Connection refused(连接被拒绝) | |
| Permission denied (publickey)(公钥权限被拒绝) | 检查密钥路径和权限: |
| Host key verification failed(主机密钥验证失败) | 执行 |
| 面板无法访问 | 使用SSH隧道(参见第2部分) |
| VPN无法连接 | SNI错误——重新运行扫描器,尝试其他域名 |
| Hiddify显示错误 | 将Hiddify更新到最新版本,重新添加链接 |
| "connection refused"(连接被拒绝) | 检查x-ui是否运行: |
| 忘记面板密码 | 执行 |
8. Инструкции для Claude Code
8. Claude Code操作说明
Этот раздел для автоматической настройки через Claude Code на твоём ноутбуке.
Скопируй всё ниже и вставь в Claude Code на ноутбуке.
ЗАДАЧА: Настроить SSH-ключ и завершить настройку безопасности VPN-сервера
Данные сервера:
- SERVER_IP: {SERVER_IP}
- USERNAME: {username}
- PASSWORD: {sudo_password}
- NICKNAME: {nickname}
Шаги:
Часть А: Установка sshpass (нужен для автоматической передачи пароля)
- Определи ОС и установи sshpass:
- macOS:
brew install hudochenkov/sshpass/sshpass - Linux (Debian/Ubuntu):
sudo apt install -y sshpass
- macOS:
Часть Б: Создание и установка SSH-ключа
2. Создай SSH-ключ:
3. Установи ключ на сервере одной командой:
ssh-keygen -t ed25519 -C "{username}@{nickname}" -f ~/.ssh/{nickname}_key -N ""sshpass -p '{sudo_password}' ssh-copy-id -i ~/.ssh/{nickname}_key.pub -o StrictHostKeyChecking=accept-new {username}@{SERVER_IP}- Проверь вход по ключу (должен работать БЕЗ пароля):
ssh -i ~/.ssh/{nickname}_key {username}@{SERVER_IP} "echo 'SSH key OK'" - Добавь SSH-конфиг:
cat >> ~/.ssh/config << 'EOF' Host {nickname} HostName {SERVER_IP} User {username} IdentityFile ~/.ssh/{nickname}_key IdentitiesOnly yes EOF - Проверь подключение через конфиг:
ssh {nickname} "echo 'Config OK'"
Часть В: Финальная защита сервера (fail2ban + блокировка пароля)
7. Установи fail2ban:
ssh {nickname} 'sudo apt install -y fail2ban && sudo tee /etc/fail2ban/jail.local << JAILEOF
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 24h
JAILEOF
sudo systemctl enable fail2ban && sudo systemctl restart fail2ban'- Заблокируй парольный вход и root:
ssh {nickname} 'sudo sed -i "s/^#\?PermitRootLogin.*/PermitRootLogin no/" /etc/ssh/sshd_config && sudo sed -i "s/^#\?PasswordAuthentication.*/PasswordAuthentication no/" /etc/ssh/sshd_config && sudo systemctl restart sshd' - Проверь что SSH-ключ всё ещё работает после блокировки:
ssh {nickname} "grep -E 'PermitRootLogin|PasswordAuthentication' /etc/ssh/sshd_config && sudo systemctl status fail2ban --no-pager && echo 'Сервер полностью защищён!'" - Скажи пользователю: "Готово! SSH-ключ настроен, fail2ban установлен, парольный вход отключён. Подключайся: ssh {nickname}"
---本部分用于通过笔记本电脑上的Claude Code自动完成配置。
复制以下所有内容并粘贴到笔记本电脑上的Claude Code中。
任务:配置SSH密钥并完成VPN服务器的安全配置
服务器信息:
- SERVER_IP: {SERVER_IP}
- USERNAME: {username}
- PASSWORD: {sudo_password}
- NICKNAME: {nickname}
步骤:
部分A:安装sshpass(用于自动传递密码)
- 确定操作系统并安装sshpass:
- macOS:
brew install hudochenkov/sshpass/sshpass - Linux(Debian/Ubuntu):
sudo apt install -y sshpass
- macOS:
部分B:创建并安装SSH密钥
2. 创建SSH密钥:
3. 一键在服务器上安装密钥:
ssh-keygen -t ed25519 -C "{username}@{nickname}" -f ~/.ssh/{nickname}_key -N ""sshpass -p '{sudo_password}' ssh-copy-id -i ~/.ssh/{nickname}_key.pub -o StrictHostKeyChecking=accept-new {username}@{SERVER_IP}- 验证密钥登录是否正常(应无需输入密码):
ssh -i ~/.ssh/{nickname}_key {username}@{SERVER_IP} "echo 'SSH密钥正常'" - 添加SSH配置:
cat >> ~/.ssh/config << 'EOF' Host {nickname} HostName {SERVER_IP} User {username} IdentityFile ~/.ssh/{nickname}_key IdentitiesOnly yes EOF - 验证通过配置文件的连接:
ssh {nickname} "echo '配置正常'"
部分C:服务器最终安全配置(fail2ban + 密码锁定)
7. 安装fail2ban:
ssh {nickname} 'sudo apt install -y fail2ban && sudo tee /etc/fail2ban/jail.local << JAILEOF
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 24h
JAILEOF
sudo systemctl enable fail2ban && sudo systemctl restart fail2ban'- 禁用密码登录和root登录:
ssh {nickname} 'sudo sed -i "s/^#\?PermitRootLogin.*/PermitRootLogin no/" /etc/ssh/sshd_config && sudo sed -i "s/^#\?PasswordAuthentication.*/PasswordAuthentication no/" /etc/ssh/sshd_config && sudo systemctl restart sshd' - 验证锁定后SSH密钥是否仍正常工作:
ssh {nickname} "grep -E 'PermitRootLogin|PasswordAuthentication' /etc/ssh/sshd_config && sudo systemctl status fail2ban --no-pager && echo '服务器已完全加固!'" - 告知用户:"完成!SSH密钥已配置,fail2ban已安装,密码登录已禁用。连接命令:ssh {nickname}"
---Completion Summary
完成总结
Print this summary for the user:
VPN-сервер полностью настроен и работает!
Подключение к серверу:
Команда: ssh {nickname}
IP: {SERVER_IP}
Пользователь: {username}
SSH-ключ: ~/.ssh/{nickname}_key
Пароль sudo: {sudo_password}
Безопасность сервера:
Root-вход отключён
Парольный вход отключён
Файрвол включён (порты: SSH, 80, 443)
fail2ban защищает от брутфорса
Ядро усилено (sysctl)
BBR включён (TCP-оптимизация)
ICMP отключён (сервер не пингуется)
Панель 3x-ui:
URL: https://127.0.0.1:{panel_port}/{web_base_path} (через SSH-туннель)
Login: {panel_username}
Password: {panel_password}
VPN-подключение:
Протокол: VLESS Reality
Порт: 443
SNI: {best_sni}
Клиент:
Hiddify -- ссылка добавлена
Управление (через SSH):
ssh {nickname} # подключиться к серверу
ssh {nickname} "sudo x-ui status" # статус панели
ssh {nickname} "sudo x-ui restart" # перезапустить панель
ssh {nickname} "sudo x-ui log" # логи
SSH-туннель к админке:
ssh -L {panel_port}:127.0.0.1:{panel_port} {nickname}
Затем открыть: https://127.0.0.1:{panel_port}/{web_base_path}
Добавить нового клиента:
Открой админку -> Inbounds -> ... -> Add Client
Скинь ссылку или QR-код другому человеку
Методичка: ~/vpn-{nickname}-guide.md
Все пароли, инструкции и команды в одном файле向用户展示以下总结:
VPN服务器已完全配置并正常运行!
服务器连接信息:
命令: ssh {nickname}
IP: {SERVER_IP}
用户: {username}
SSH密钥: ~/.ssh/{nickname}_key
sudo密码: {sudo_password}
服务器安全状态:
Root登录已禁用
密码登录已禁用
防火墙已启用(开放端口:SSH、80、443)
fail2ban已安装以防止暴力破解
内核已加固(sysctl)
BBR已启用(TCP优化)
ICMP已禁用(服务器无法被ping通)
3x-ui面板信息:
URL: https://127.0.0.1:{panel_port}/{web_base_path}(通过SSH隧道访问)
登录账号: {panel_username}
密码: {panel_password}
VPN连接信息:
协议: VLESS Reality
端口: 443
SNI: {best_sni}
客户端信息:
Hiddify -- 链接已添加
管理命令(通过SSH):
ssh {nickname} # 连接服务器
ssh {nickname} "sudo x-ui status" # 查看面板状态
ssh {nickname} "sudo x-ui restart" # 重启面板
ssh {nickname} "sudo x-ui log" # 查看日志
面板SSH隧道:
ssh -L {panel_port}:127.0.0.1:{panel_port} {nickname}
然后打开:https://127.0.0.1:{panel_port}/{web_base_path}
添加新客户端:
打开面板 → Inbounds(入站规则)→ ... → Add Client(添加客户端)
将链接或QR码发送给其他人
指南文件:~/vpn-{nickname}-guide.md
所有密码、操作说明和命令均包含在此文件中Critical Rules
关键规则
Part 1 (Server)
第一部分(服务器)
- NEVER skip Step 6 (test login) -- user can be locked out permanently
- NEVER disable root before confirming new user works
- NEVER store passwords in files -- only display once to user
- If connection drops after password change -- reconnect, this is normal
- If Step 6 fails -- fix it before proceeding, keep root session open
- Generate SSH key BEFORE first connection -- more efficient workflow
- All operations after Step 6 use sudo -- not root
- Steps 7 and 9 are DEFERRED -- SSH lockdown and fail2ban are installed at the very end (Step 22)
- 绝不要跳过步骤6(测试登录)——用户可能会被永久锁定在外
- 在确认新用户正常工作前,绝不要禁用root登录
- 绝不要将密码存储在文件中——仅向用户显示一次
- 若修改密码后连接断开——重新连接,此为正常现象
- 若步骤6失败——修复问题后再继续,保持root会话处于活跃状态
- 在首次连接前生成SSH密钥——更高效的工作流程
- 步骤6之后的所有操作均使用sudo——不要使用root
- 步骤7和9推迟执行——SSH锁定和fail2ban安装将在最后执行(步骤22)
Part 2 (VPN)
第二部分(VPN)
- NEVER expose panel to internet -- access only via SSH tunnel
- NEVER skip firewall configuration -- only open needed ports
- ALWAYS save panel credentials -- show them once, clearly
- ALWAYS verify connection works before declaring success
- Ask before every destructive or irreversible action
- ALWAYS generate guide file (Step 22) -- the user's single source of truth
- Lock SSH + install fail2ban LAST (Step 22) -- only after SSH key access is verified in BOTH modes
- NEVER leave password auth enabled after setup is complete
- 绝不要将面板暴露在公网中——仅通过SSH隧道访问
- 绝不要跳过防火墙配置——仅开放必要端口
- 务必保存面板凭证——清晰地向用户显示一次
- 在宣布成功前务必验证连接是否正常工作
- 在执行任何破坏性或不可逆操作前询问用户
- 务必生成指南文件(步骤22)——这是用户的唯一参考来源
- 最后执行SSH锁定 + 安装fail2ban(步骤22)——仅在两种模式下均确认SSH密钥访问正常后执行
- 配置完成后绝不要保留密码登录功能
Troubleshooting
故障排除
| Problem | Solution |
|---|---|
| Connection drops after password change | Normal -- reconnect with new password |
| Permission denied (publickey) | Check key path and permissions (700/600) |
| Host key verification failed | |
| x-ui install fails | |
| Panel not accessible | Use SSH tunnel: |
| Reality not connecting | Wrong SNI -- re-run scanner, try different domain |
| Hiddify shows error | Update Hiddify to latest version, re-add link |
| "connection refused" | Check x-ui is running: |
| Forgot panel password | |
| SCP fails (Windows) | Install OpenSSH: Settings → Apps → Optional Features → OpenSSH Client |
| SCP fails (connection refused) | Check UFW allows SSH: |
| BBR not active after reboot | Re-check: |
| 问题 | 解决方案 |
|---|---|
| 修改密码后连接断开 | 正常现象——使用新密码重新连接 |
| Permission denied (publickey)(公钥权限被拒绝) | 检查密钥路径和权限(700/600) |
| Host key verification failed(主机密钥验证失败) | 执行 |
| x-ui安装失败 | 执行 |
| 面板无法访问 | 使用SSH隧道: |
| Reality无法连接 | SNI错误——重新运行扫描器,尝试其他域名 |
| Hiddify显示错误 | 将Hiddify更新到最新版本,重新添加链接 |
| "connection refused"(连接被拒绝) | 检查x-ui是否运行: |
| 忘记面板密码 | 执行 |
| SCP失败(Windows) | 安装OpenSSH:设置 → 应用 → 可选功能 → OpenSSH客户端 |
| SCP失败(连接被拒绝) | 检查UFW是否允许SSH: |
| 重启后BBR未激活 | 重新检查: |
x-ui CLI Reference
x-ui CLI参考
bash
x-ui start # start panel
x-ui stop # stop panel
x-ui restart # restart panel
x-ui status # check status
x-ui setting -reset # reset username/password
x-ui log # view logs
x-ui cert # manage SSL certificates
x-ui update # update to latest versionbash
x-ui start # 启动面板
x-ui stop # 停止面板
x-ui restart # 重启面板
x-ui status # 检查状态
x-ui setting -reset # 重置用户名/密码
x-ui log # 查看日志
x-ui cert # 管理SSL证书
x-ui update # 更新到最新版本