007
無料Security audit, hardening, threat modeling (STRIDE/PASTA), Red/Blue Team, OWASP checks, code review, incident response, and infrastructure security for any project.
日本語の概要は準備中です。原文の説明を表示しています。
Complete VPN server setup from scratch. Takes a fresh VPS (IP + root + password from hosting provider) through full server hardening and 3x-ui (Xray proxy panel) installation with VLESS Reality or VLESS TLS. Guides user through connecting via Hiddify client. Use when user mentions v2ray, xray, vless, 3x-ui, proxy server, vpn server, or wants to set up encrypted proxy access on a VPS. Designed for beginners — hand-holds through every step.
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Complete setup: fresh VPS from provider → secured server → working VPN with Hiddify client.
ЧАСТЬ 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
Secure a fresh server from provider credentials to production-ready state.
First, determine execution mode:
Где запущен Claude Code?
myserver, vpn1)myserver, vpn1)In Local mode, get server IP automatically:
curl -4 -s ifconfig.me
If user pastes the full provider email, extract the data from it.
Recommend Reality (no domain) for beginners. Explain:
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 | ssh root@{SERVER_IP} | Already on server. If not root: sudo su - |
| 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: ssh -i ... user@IP | Switch user: su - {username}, then sudo whoami |
| Step 7 | SKIP -- lockdown deferred to Step 22 | SKIP -- lockdown deferred to Step 22 |
| Steps 8-11 | sudo on server via SSH | sudo directly (no SSH prefix) |
| Step 12 | Write ~/.ssh/config on LOCAL | SKIP -- user does this from guide file (Step 22) |
| Step 13 | Verify via ssh {nickname} | Run audit directly, skip SSH lockdown checks |
| Part 2 | ssh {nickname} "sudo ..." | sudo ... directly (no SSH prefix) |
| Step 17A | Scanner via ssh {nickname} '...' | Scanner runs directly (no SSH wrapper) -- see Step 17A for both commands |
| Panel access | Via SSH tunnel | Direct: https://127.0.0.1:{panel_port}/{web_base_path} |
| 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 ssh {nickname}, password auth disabled, root login disabled.
Run on the user's LOCAL machine BEFORE connecting to the server:
ssh-keygen -t ed25519 -C "{username}@{nickname}" -f ~/.ssh/{nickname}_key -N ""
Save the public key content for later:
cat ~/.ssh/{nickname}_key.pub
ssh root@{SERVER_IP}
Many providers force a password change on first login. Signs:
If this happens:
If connection drops after password change -- this is normal. Reconnect:
ssh root@{SERVER_IP}
apt update && DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt upgrade -y
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:
# Verify
groups {username}
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}/.ssh
DO NOT proceed without successful test!
Open a NEW connection (keep root session alive):
ssh -i ~/.ssh/{nickname}_key {username}@{SERVER_IP}
Verify sudo works:
sudo whoami
# Must output: root
If this fails -- debug permissions, do NOT disable root login:
# Check on server as root:
ls -la /home/{username}/.ssh/
cat /home/{username}/.ssh/authorized_keys
# Fix ownership:
chown -R {username}:{username} /home/{username}/.ssh
Оба режима: ПРОПУСКАЕМ. Блокировка SSH и установка fail2ban выполняются в самом конце (Step 22), после того как SSH-ключ проверен. Это предотвращает случайную блокировку доступа во время настройки.
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 status
Пропущен. fail2ban устанавливается в конце настройки (Step 22) вместе с блокировкой SSH, чтобы не заблокировать пользователя во время настройки.
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.conf
sudo apt install -y chrony curl wget unzip net-tools
sudo systemctl enable chrony
On the user's LOCAL machine:
cat >> ~/.ssh/config << 'EOF'
Host {nickname}
HostName {SERVER_IP}
User {username}
IdentityFile ~/.ssh/{nickname}_key
IdentitiesOnly yes
EOF
Tell user: Теперь подключайся командой ssh {nickname} -- без пароля и IP.
Connect as new user and run quick audit:
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.
All commands from here use ssh {nickname} -- the shortcut configured in Part 1.
3x-ui install script requires root. Run with sudo:
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 echo 'n' answers "no" to port customization prompt -- a random port and credentials will be generated.
Note: Do NOT use sudo bash <(curl ...) -- process substitution does not work with sudo (file descriptors are not inherited).
IMPORTANT: Capture the output! It contains:
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:
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.
BBR (Bottleneck Bandwidth and RTT) dramatically improves TCP throughput, especially on lossy links -- critical for VPN performance.
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:
ssh {nickname} "sysctl net.ipv4.tcp_congestion_control net.core.default_qdisc"
Expected: net.ipv4.tcp_congestion_control = bbr, net.core.default_qdisc = fq.
Makes server invisible to ping scans:
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:
ping -c 2 -W 2 {SERVER_IP}
Expected: no response (timeout).
Go to Step 17A.
Go to references/vless-tls.md.
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:
shop.finn-auto.fi) is ideal -- nobody filters it, and it's in the same subnetDownload and run Reality Scanner against the /24 subnet:
Remote mode (Claude Code on user's laptop):
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):
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
Note: The commands are identical — Local mode simply runs without the ssh {nickname} wrapper since Claude Code is already on the VPS. GitHub releases use non-standard arch names (64 instead of amd64, arm64-v8a instead of arm64). The case block maps them. The file | grep ELF 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.
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:
shop.finn-auto.fi, portal.company.de) -- ideal, not filtered by DPIgithub.com, twitch.tv) -- acceptable but less idealAVOID these as SNI:
www.google.com, www.microsoft.com, googletagmanager.com -- commonly blacklisted by DPI, people in Amnezia chats report these stop workingHow 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 /23 (512 IPs):
Remote mode:
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:
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
If still nothing, use www.yahoo.com 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.
Save the best SNI for the next step.
Pre-check: Verify port 443 is not occupied by another service (some providers pre-install apache2/nginx):
ssh {nickname} "ss -tlnp | grep ':443 '"
If something is listening on 443, stop and disable it first (e.g., sudo systemctl stop apache2 && sudo systemctl disable apache2). Otherwise the VLESS inbound will silently fail to bind.
3x-ui has an API. Since v2.8+, the installer auto-configures SSL, so the panel runs on HTTPS. Use -k to skip certificate verification (self-signed cert on localhost).
First, get session cookie:
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:
ssh {nickname} "sudo /usr/local/x-ui/bin/xray-linux-* x25519"
This outputs two lines: PrivateKey = private key, Password = public key (confusing naming by xray). Save both.
Generate UUID for the client:
ssh {nickname} "sudo /usr/local/x-ui/bin/xray-linux-* uuid"
Generate random Short ID:
ssh {nickname} "openssl rand -hex 8"
Create the inbound:
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).
If API fails, user can access panel in browser:
ssh -L {panel_port}:127.0.0.1:{panel_port} {nickname}
Then open in browser: https://127.0.0.1:{panel_port}/{web_base_path} (browser will warn about self-signed cert -- accept it)
Guide user through the UI:
Get the client connection link from 3x-ui API:
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:
Скопируй всё ниже и вставь в любой LLM (ChatGPT, Claude) чтобы получить чистую ссылку:
Убери все переносы строк и лишние пробелы из этой ссылки, выдай одной строкой:
{VLESS_LINK}
Also save the link to a file for easy access:
ssh {nickname} "echo '{VLESS_LINK}' > ~/vpn-link.txt"
Tell the user: Ссылка также сохранена в файл ~/vpn-link.txt
Cleanup session cookie:
ssh {nickname} "rm -f /tmp/3x-cookie"
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
After user connects via Hiddify, verify:
ssh {nickname} "sudo x-ui status && ss -tlnp | grep -E '443|{panel_port}'"
This step generates a comprehensive guide file with all credentials and instructions, then finalizes SSH key-based access.
22R-1: Generate guide file locally
Use the Write tool to create ~/vpn-{nickname}-guide.md on the user's local machine. Use the Guide File Template below, substituting all {variables} with actual values.
Tell user: Методичка сохранена в ~/vpn-{nickname}-guide.md — там все пароли, доступы и инструкции.
22R-2: Final lockdown — fail2ban + SSH
Verify SSH key access works:
ssh {nickname} "echo 'SSH key access OK'"
If successful, install fail2ban and lock SSH:
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'
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:
ssh {nickname} "grep -E 'PermitRootLogin|PasswordAuthentication' /etc/ssh/sshd_config && sudo systemctl status fail2ban --no-pager -l && echo 'Lockdown OK'"
In Local mode, Claude Code runs on the server. SSH lockdown was skipped (Step 7), so password auth still works. The flow:
Use the Write tool to create /home/{username}/vpn-guide.md on the server. Use the Guide File Template below, substituting all {variables} with actual values.
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.
Tell the user:
Теперь создай SSH-ключ на своём компьютере.
Есть два варианта:
Вариант А: Следуй инструкциям из раздела "SSH Key Setup" в методичке.
Вариант Б (автоматический): Установи Claude Code на ноутбуке
(https://claude.ai/download) и скинь ему файл vpn-guide.md --
он сам всё настроит по инструкциям из раздела "Instructions for Claude Code".
После создания ключа отправь публичный ключ на сервер (следующий шаг).
Tell the user:
Отправь публичный ключ на сервер (из терминала на ноутбуке):
scp ~/.ssh/{nickname}_key.pub {username}@{SERVER_IP}:~/
Пароль: {sudo_password}
Wait for user confirmation before proceeding.
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
Tell user to test from their laptop:
Проверь подключение с ноутбука:
ssh -i ~/.ssh/{nickname}_key {username}@{SERVER_IP}
Должно подключиться без пароля.
Wait for user confirmation that SSH key works before proceeding!
Only after user confirms key-based login works!
Install fail2ban:
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
Lock SSH:
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:
grep -E "PermitRootLogin|PasswordAuthentication" /etc/ssh/sshd_config
sudo systemctl status fail2ban --no-pager
Expected: PermitRootLogin no, PasswordAuthentication no, fail2ban active.
Tell user to verify SSH still works from laptop:
Проверь, что SSH-ключ всё ещё работает:
ssh {nickname}
Если подключился — всё настроено!
Tell the user:
Последний шаг! Добавь на ноутбуке в файл ~/.ssh/config:
Host {nickname}
HostName {SERVER_IP}
User {username}
IdentityFile ~/.ssh/{nickname}_key
IdentitiesOnly yes
Теперь подключайся просто: ssh {nickname}
rm -f /home/{username}/vpn-guide.md
Tell user: Методичка удалена с сервера. Убедись, что она сохранена на твоём компьютере.
Generate this file using the Write tool, substituting all {variables} with actual values collected during setup.
# Методичка VPN-сервера — {nickname}
Дата создания: {current_date}
## 1. Подключение к серверу
| Параметр | Значение |
|----------|----------|
| IP | `{SERVER_IP}` |
| Пользователь | `{username}` |
| Пароль sudo | `{sudo_password}` |
| SSH-ключ | `~/.ssh/{nickname}_key` |
| Быстрое подключение | `ssh {nickname}` |
## 2. Панель 3x-ui
| Параметр | Значение |
|----------|----------|
| URL | `https://127.0.0.1:{panel_port}/{web_base_path}` |
| Логин | `{panel_username}` |
| Пароль | `{panel_password}` |
Доступ через SSH-туннель:
```
ssh -L {panel_port}:127.0.0.1:{panel_port} {nickname}
```
Затем открой: `https://127.0.0.1:{panel_port}/{web_base_path}`
## 3. VPN-подключение
| Параметр | Значение |
|----------|----------|
| Протокол | VLESS Reality |
| Порт | 443 |
| SNI | `{best_sni}` |
| Клиент | Hiddify |
Ссылка VLESS:
```
{VLESS_LINK}
```
## 4. Настройка SSH-ключа
Если у тебя ещё нет SSH-ключа, следуй инструкциям для своей ОС:
### macOS / Linux
```bash
# Создать ключ
ssh-keygen -t ed25519 -C "{username}@{nickname}" -f ~/.ssh/{nickname}_key -N ""
# Отправить публичный ключ на сервер
scp ~/.ssh/{nickname}_key.pub {username}@{SERVER_IP}:~/
# Установить права
chmod 600 ~/.ssh/{nickname}_key
# Добавить в SSH-конфиг
cat >> ~/.ssh/config << 'SSHEOF'
Host {nickname}
HostName {SERVER_IP}
User {username}
IdentityFile ~/.ssh/{nickname}_key
IdentitiesOnly yes
SSHEOF
# Проверить подключение
ssh {nickname}
```
### Windows (PowerShell)
```powershell
# Создать ключ
ssh-keygen -t ed25519 -C "{username}@{nickname}" -f $HOME\.ssh\{nickname}_key -N '""'
# Отправить публичный ключ на сервер
scp $HOME\.ssh\{nickname}_key.pub {username}@{SERVER_IP}:~/
# Добавить в SSH-конфиг
Add-Content $HOME\.ssh\config @"
Host {nickname}
HostName {SERVER_IP}
User {username}
IdentityFile ~/.ssh/{nickname}_key
IdentitiesOnly yes
"@
# Проверить подключение
ssh {nickname}
```
Примечание: `chmod` не нужен на Windows. SSH использует ACL автоматически.
## 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.
## 6. Статус безопасности
| Параметр | Статус |
|----------|--------|
| Вход под root | Отключён |
| Вход по паролю | Отключён |
| Файрвол UFW | Включён (SSH, 80, 443) |
| fail2ban | Включён (3 попытки → бан 24ч) |
| Усиление ядра | Включено (sysctl) |
| BBR | Включён |
| ICMP (ping) | Отключён |
## 7. Решение проблем
| Проблема | Решение |
|----------|---------|
| Connection refused | `ssh {nickname} "sudo x-ui status"` — перезапусти если остановлен |
| Permission denied (publickey) | Проверь путь и права ключа: `ls -la ~/.ssh/{nickname}_key` |
| Host key verification failed | `ssh-keygen -R {SERVER_IP}` и переподключись |
| Панель недоступна | Используй SSH-туннель (см. раздел 2) |
| VPN не подключается | Неверный SNI или сервер лежит — проверь `sudo x-ui log` |
| Забыл пароль панели | `ssh {nickname} "sudo x-ui setting -reset"` |
## 8. Инструкции для Claude Code
Этот раздел для автоматической настройки через Claude Code на твоём ноутбуке.
Скопируй всё ниже и вставь в Claude Code на ноутбуке.
---
**ЗАДАЧА: Настроить SSH-ключ и завершить настройку безопасности VPN-сервера**
Данные сервера:
- SERVER_IP: {SERVER_IP}
- USERNAME: {username}
- PASSWORD: {sudo_password}
- NICKNAME: {nickname}
Шаги:
**Часть А: Установка sshpass (нужен для автоматической передачи пароля)**
1. Определи ОС и установи sshpass:
- macOS: `brew install hudochenkov/sshpass/sshpass`
- Linux (Debian/Ubuntu): `sudo apt install -y sshpass`
**Часть Б: Создание и установка SSH-ключа**
2. Создай SSH-ключ: `ssh-keygen -t ed25519 -C "{username}@{nickname}" -f ~/.ssh/{nickname}_key -N ""`
3. Установи ключ на сервере одной командой:
```
sshpass -p '{sudo_password}' ssh-copy-id -i ~/.ssh/{nickname}_key.pub -o StrictHostKeyChecking=accept-new {username}@{SERVER_IP}
```
4. Проверь вход по ключу (должен работать БЕЗ пароля):
```
ssh -i ~/.ssh/{nickname}_key {username}@{SERVER_IP} "echo 'SSH key OK'"
```
5. Добавь SSH-конфиг:
```
cat >> ~/.ssh/config << 'EOF'
Host {nickname}
HostName {SERVER_IP}
User {username}
IdentityFile ~/.ssh/{nickname}_key
IdentitiesOnly yes
EOF
```
6. Проверь подключение через конфиг: `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'
```
8. Заблокируй парольный вход и 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'
```
9. Проверь что SSH-ключ всё ещё работает после блокировки:
```
ssh {nickname} "grep -E 'PermitRootLogin|PasswordAuthentication' /etc/ssh/sshd_config && sudo systemctl status fail2ban --no-pager && echo 'Сервер полностью защищён!'"
```
10. Скажи пользователю: "Готово! SSH-ключ настроен, fail2ban установлен, парольный вход отключён. Подключайся: ssh {nickname}"
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
Все пароли, инструкции и команды в одном файле
| 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 | ssh-keygen -R {SERVER_IP} then reconnect |
| x-ui install fails | sudo apt update && sudo apt install -y curl tar |
| Panel not accessible | Use SSH tunnel: ssh -L {panel_port}:127.0.0.1:{panel_port} {nickname} |
| 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: sudo x-ui status |
| Forgot panel password | sudo x-ui setting -reset |
| SCP fails (Windows) | Install OpenSSH: Settings → Apps → Optional Features → OpenSSH Client |
| SCP fails (connection refused) | Check UFW allows SSH: sudo ufw status, verify sshd running |
| BBR not active after reboot | Re-check: sysctl net.ipv4.tcp_congestion_control -- re-apply if needed |
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 version
まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Security audit, hardening, threat modeling (STRIDE/PASTA), Red/Blue Team, OWASP checks, code review, incident response, and infrastructure security for any project.
日本語の概要は準備中です。原文の説明を表示しています。
Guides the creation of agile user stories and Gherkin feature files. Use when the user wants to create a user story, write acceptance criteria, define Gherkin scenarios, or author BDD feature files. This should trigger for requests such as Create a user story; Write a user story; I need to write a user story. Part of cursor-rules-java project
日本語の概要は準備中です。原文の説明を表示しています。
Facilitates conversational discovery to create Architectural Decision Records (ADRs) for non-functional requirements using the ISO/IEC 25010:2023 quality model. Use when the user wants to document quality attributes, NFR decisions, security/performance/scalability architecture, or design systems with measurable quality criteria. This should trigger for requests such as Create ADR for Non-functional requirements; Document Non-functional requirements; Capture Non-functional requirements; Generate Non-functional requirements in an ADR. Part of cursor-rules-java project
日本語の概要は準備中です。原文の説明を表示しています。
Run a health check on an existing project: dependency audit, security scan, test runner detection, CI/CD evaluation, and missing configuration analysis. Maps the three execution gates (pre/in/post) from /10x-bootstrapper to an assessment framework for existing codebases. Reads optional context/foundation/stack-assessment.md from /10x-stack-assess to focus checks on identified gaps. Writes context/foundation/health-check.md with findings, prioritized fixes, and an agent-readiness verdict. Use when the user has an existing project and wants to verify its health before working with an agent. Trigger phrases: "health check", "check my project", "audit my project", "is my project healthy", "sprawdź projekt", "audyt projektu", "health-check", "project health". Use AFTER /10x-stack-assess (brownfield chain), BEFORE agent onboarding (m1-l4).
日本語の概要は準備中です。原文の説明を表示しています。
You MUST use this when building projects end-to-end. Orchestrates all 12 team roles — automatically switches between CTO, architect, PM, engineers, SRE, security, DBA, QA, and EM based on the current phase of work. Starts with brainstorming before any implementation.
日本語の概要は準備中です。原文の説明を表示しています。
Use when you need to add or configure Maven plugins in your pom.xml — including quality tools (enforcer, surefire, failsafe, jacoco, pitest, spotbugs, pmd), security scanning (OWASP), code formatting (Spotless), version management, container image build (Jib), build information tracking, and benchmarking (JMH) — through a consultative, modular step-by-step approach that only adds what you actually need. This should trigger for requests such as Add Maven plugins in pom.xml; Improve Maven plugins in pom.xml. Part of cursor-rules-java project
日本語の概要は準備中です。原文の説明を表示しています。