---
name: VPN Security Check
slug: vpn-security-check
category: DevOps
description: VPN Security Check audits a VPN server’s hardening over SSH, including SSH, firewall, fail2ban, Xray, and secret handling. Use it after deployment or when you want a security review.
github: "https://github.com/Sergei-thinker/vpn-setup/tree/master/.claude/skills/vpn-security-check"
language: Shell
stars: 181
forks: 25
install: "npx degit https://github.com/Sergei-thinker/vpn-setup/tree/master/.claude/skills/vpn-security-check ~/.claude/skills/vpn-security-check"
installs_to: ~/.claude/skills/vpn-security-check
source_path: .claude/skills/vpn-security-check/SKILL.md
collection_size: 4
category_size: 1044
collection_url: "https://dirskills.com/collections/Sergei-thinker/vpn-setup"
added: 2026-09-07T05:20:20.110Z
last_synced: 2026-09-07T05:20:20.110Z
canonical_url: "https://dirskills.com/skills/vpn-security-check"
---

# VPN Security Check

VPN Security Check audits a VPN server’s hardening over SSH, including SSH, firewall, fail2ban, Xray, and secret handling. Use it after deployment or when you want a security review.

**Install:**

```bash
npx degit https://github.com/Sergei-thinker/vpn-setup/tree/master/.claude/skills/vpn-security-check ~/.claude/skills/vpn-security-check
```

## README

# VPN Infrastructure Security Audit

Checks that the VPN server is properly hardened. All checks run via `ssh_exec.py` — no additional tools needed.

## When to Use

- User asks about security: "check security", "is my VPN safe"
- After initial deployment (offer proactively)
- User has security concerns
- Periodic security checkup

## The Iron Law

```
EVERY CHECK MUST RUN A COMMAND. NO ASSUMPTIONS.
```

"quick-rebuild.sh enables the firewall" is not evidence that the firewall is active. Run the check.

## Security Checks

Run ALL checks in order. Report each as PASS/FAIL/WARN with evidence.

### 1. SSH Hardening

**1a. SSH Port**

Command: `python ssh_exec.py exec "grep -E '^Port ' /etc/ssh/sshd_config"`

| Result | Rating |
|--------|--------|
| Port != 22 (e.g., 49152) | PASS |
| Port 22 | FAIL — TSPU scans and blocks port 22 to foreign IPs. Change with: `python ssh_exec.py exec "sed -i 's/^Port 22/Port 49152/' /etc/ssh/sshd_config && systemctl restart sshd"` |

**1b. Root Password Login**

Command: `python ssh_exec.py exec "grep -E '^PasswordAuthentication' /etc/ssh/sshd_config"`

| Result | Rating |
|--------|--------|
| PasswordAuthentication no | PASS |
| PasswordAuthentication yes | WARN — Key-only auth is more secure. Note: some beginners use password auth intentionally. Inform, don't force change |
| Not set (commented out) | WARN — defaults to yes on most distros |

### 2. Firewall

**2a. UFW Status**

Command: `python ssh_exec.py exec "ufw status verbose"`

| Result | Rating |
|--------|--------|
| Status: active, rules for 443/8443/2053/SSH port | PASS |
| Status: inactive | FAIL — `python ssh_exec.py exec "ufw --force enable"` |
| Active but missing expected ports | WARN — check if needed ports are open |

**2b. Open Ports (reality check)**

Command: `python ssh_exec.py exec "ss -tnlp | grep -E 'LISTEN' | awk '{print \$4, \$6}'"`

Verify only expected services are listening:
- xray on 443, 8443, 2053 (VPN)
- x-ui panel (some high port)
- sshd on configured port
- nginx on 80 (camouflage)

Any unexpected service = WARN

### 3. Intrusion Prevention

**3a. fail2ban**

Command: `python ssh_exec.py exec "systemctl is-active fail2ban && fail2ban-client status sshd 2>/dev/null | grep -E 'Currently|Total'"`

| Result | Rating |
|--------|--------|
| active + shows ban stats | PASS |
| inactive or not installed | FAIL — `python ssh_exec.py exec "apt install -y fail2ban && systemctl enable --now fail2ban"` |

### 4. VPN Service Security

**4a. 3X-UI Panel Access**

Command: `python ssh_exec.py exec "grep -E 'webPort|webBasePath' /etc/x-ui/x-ui.db 2>/dev/null || echo 'db not readable as text'"`

Check:
- Panel is on non-standard port (not 80, 443, 8080, 2053)
- Panel base path is randomized (not `/` or `/panel`)

If DB not readable as text, try: `python ssh_exec.py exec "x-ui settings show 2>/dev/null || echo 'cannot read settings'"`

| Result | Rating |
|--------|--------|
| Non-standard port + randomized path | PASS |
| Default port or path = "/" | WARN — Panel is discoverable. Suggest changing via `x-ui settings` |

**4b. Xray Running with Expected Config**

Command: `python ssh_exec.py exec "xray version 2>/dev/null || /usr/local/x-ui/bin/xray-linux-amd64 version 2>/dev/null"`

| Result | Rating |
|--------|--------|
| Version >= 24.x | PASS |
| Old version | WARN — Update with `python ssh_exec.py update-xray` |

### 5. Camouflage

**5a. Nginx Responding**

Command: `python ssh_exec.py exec "curl -s -o /dev/null -w '%{http_code}' http://localhost:80"`

| Result | Rating |
|--------|--------|
| 200 | PASS — Camouflage page is active |
| Connection refused / other | WARN — Without nginx, port scanners see an unusual server profile |

### 6. Secrets Management

**6a. .env Not in Git**

Command (local): Check `.gitignore` includes `.env` AND `git ls-files .env` returns nothing

| Result | Rating |
|--------|--------|
| .env is gitignored and not tracked | PASS |
| .env is tracked in git | CRITICAL FAIL — `git rm --cached .env` immediately. Credentials are exposed! |

**6b. Credentials File Permissions (on server)**

Command: `python ssh_exec.py exec "ls -la /root/vpn-credentials.txt 2>/dev/null || echo 'not found'"`

| Result | Rating |
|--------|--------|
| Permissions -rw------- (600) or not found | PASS |
| World-readable (644, 755, etc.) | WARN — `python ssh_exec.py exec "chmod 600 /root/vpn-credentials.txt"` |

### 7. System Updates

Command: `python ssh_exec.py exec "apt list --upgradable 2>/dev/null | tail -n +2 | wc -l"`

| Result | Rating |
|--------|--------|
| 0 or <5 pending updates | PASS |
| 5+ pending security updates | WARN — `python ssh_exec.py exec "apt update && apt upgrade -y"` |

## Report Format

Present as a security scorecard (in Russian):

```
Аудит безопасности VPN-сервера:

  SSH:
    1a. SSH-порт:              [PASS/FAIL]
    1b. Парольная авторизация: [PASS/WARN]
  
  Firewall:
    2a. UFW:                   [PASS/FAIL]
    2b. Открытые порты:        [PASS/WARN]
  
  Защита от вторжений:
    3a. fail2ban:              [PASS/FAIL]
  
  VPN-сервис:
    4a. Панель 3X-UI:          [PASS/WARN]
    4b. Версия Xray:           [PASS/WARN]
  
  Камуфляж:
    5a. Nginx:                 [PASS/WARN]
  
  Секреты:
    6a. .env в git:            [PASS/CRITICAL]
    6b. Файл credentials:     [PASS/WARN]
  
  Обновления:
    7.  Системные:             [PASS/WARN]

Итого: X/10 проверок пройдено
```

For each FAIL/WARN: provide the specific fix command.
For CRITICAL: fix immediately before continuing.

## Communication Rules

- Communicate in **Russian**
- Run every check — do not skip "because the deploy script handles it"
- If a check fails, provide the exact fix command
- Do not alarm the user unnecessarily — WARN is informational, FAIL needs action, CRITICAL needs immediate action
- Remind user this is an infrastructure audit, not a guarantee of anonymity (VPN protects from censorship, not from targeted surveillance)
