Skip to content
Development
Skill

/vps-security-hardening

Audit and harden VPS security — fail2ban, SSH hardening, firewall setup

From plugin
ai-agent-skills
14169 skills

Claude Code

$ npx -y skills add kevinnft/ai-agent-skills --skill vps-security-hardening --agent claude-code

SKILL.md

vps-security-hardening.SKILL.md
name: vps-security-hardening
description: Audit and harden VPS security — fail2ban, SSH hardening, firewall setup
tags: [security, vps, ssh, fail2ban, linux, ubuntu]
origin: unknown
source_license: see upstream
language: en

VPS Security Hardening

Audit and harden VPS security with fail2ban (brute-force protection), SSH hardening, and optional firewall setup.

When to Use

  • New VPS setup (initial hardening)
  • Security audit requested
  • SSH brute-force attacks detected
  • User wants to "secure VPS" or "protect server"

Prerequisites: Establishing SSH Access

**Before hardening, ensure you can SSH into the VPS.**

If Password Auth is Disabled (PublicKey only)

VPS providers often disable password auth by default. You need to add your SSH key first.

Option 1: Via VPS Web Console (Recommended)

1. **Generate SSH key locally** (if not exists):

   ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N '' -C "user@machine"
   cat ~/.ssh/id_ed25519.pub

2. **Login to VPS via web console** (provider dashboard → Console/Terminal)

3. **Add public key to VPS**:

   mkdir -p ~/.ssh
   echo "ssh-ed25519 AAAA... user@machine" >> ~/.ssh/authorized_keys
   chmod 700 ~/.ssh
   chmod 600 ~/.ssh/authorized_keys

4. **Test from local machine**:

   ssh root@VPS_IP

Option 2: Via Provider Dashboard

Most providers (DigitalOcean, Vultr, Biznet, etc.) have "Add SSH Key" in dashboard:

  • Copy public key (`cat ~/.ssh/id_ed25519.pub`)
  • Paste into provider's SSH key management
  • Rebuild/restart VPS (some providers require this)

Option 3: Enable Password Auth Temporarily

**Only if web console is unavailable:**

1. Login via web console 2. Edit SSH config:

   echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config.d/99-temp-password.conf
   systemctl reload sshd

3. SSH in with password, add your key 4. Remove temp config:

   rm /etc/ssh/sshd_config.d/99-temp-password.conf
   systemctl reload sshd

Common Pitfall: sshpass with PublicKey-Only VPS

**Problem:** `sshpass -p 'password' ssh user@host` fails with "Permission denied (publickey)" even with correct password.

**Why:** VPS has `PasswordAuthentication no` in sshd_config — password auth is disabled at server level.

**Solution:** Use web console to add SSH key first (see Option 1 above).

Workflow

Phase 1: Security Audit

1. **Check running processes**

   ps aux --sort=-%mem | head -20
   systemctl list-units --type=service --state=running

2. **Check listening ports**

   sudo ss -tulpn
   sudo netstat -tulpn

3. **Check for rootkits/malware**

   # Hidden processes
   ps aux | wc -l
   ls /proc | grep -E '^[0-9]+$' | wc -l
   
   # Recent failed logins
   sudo grep "Failed password" /var/log/auth.log | tail -20

4. **Check user accounts**

   cat /etc/passwd | grep -E '/bin/(bash|sh)$'
   sudo lastlog

5. **Resource usage**

   free -h
   df -h
   uptime

Phase 2: Install fail2ban

# Install
sudo apt-get update
sudo apt-get install -y fail2ban

# Enable and start
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Phase 3: Configure fail2ban

Create `/etc/fail2ban/jail.local`:

[DEFAULT]
bantime  = 3600        # Ban for 1 hour
findtime = 600         # Count failures in last 10 minutes
maxretry = 5           # Ban after 5 failures

[sshd]
enabled = true
port    = 22
logpath = /var/log/auth.log
maxretry = 5

Restart:

sudo systemctl restart fail2ban
sudo fail2ban-client status sshd

Phase 4: SSH Hardening

Create `/etc/ssh/sshd_config.d/99-hardening.conf`:

# Disable root login
PermitRootLogin no

# Enable public key auth
PubkeyAuthentication yes

# Disable empty passwords
PermitEmptyPasswords no

# Limit auth attempts
MaxAuthTries 3

# Disable X11 forwarding
X11Forwarding no

# Disable TCP forwarding
AllowTcpForwarding no

# Disable agent forwarding
AllowAgentForwarding no

# Set login grace time
LoginGraceTime 30

# Limit sessions
MaxSessions 2

# Strong ciphers only
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com

# Strong MACs only
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com

# Strong key exchange
KexAlgorithms curve25519-sha256,diffie-hellman-group-exchange-sha256

Test and reload:

sudo sshd -t
sudo systemctl reload sshd

Phase 5: Verify

# fail2ban status
sudo fail2ban-client status sshd

# SSH config
sudo sshd -T | grep -E '(permitrootlogin|maxauthtries|x11forwarding)'

# Check banned IPs
sudo fail2ban-client get sshd banip

Important: Password vs SSH Key Decision

**DO NOT automatically disable password authentication!**

Check First

# Check if user has SSH keys
cat ~/.ssh/authorized_keys

# Check how user is currently connected
sudo grep "Accepted" /var/log/auth.log | tail -5

Decision Logic

**If user logs in with PASSWORD:**

  • ✅ Keep `PasswordAuthentication yes`
  • ✅ fail2ban provides brute-force protection
  • ⚠️ Disabling password = user gets locked out

**If user logs in with SSH KEY:**

  • ✅ Can disable `PasswordAuthentication no`
  • ✅ Maximum security (impossible to brute-force)

User Preference Handling

**CRITICAL:** If user says "keep password" or "tanpa ssh key" or similar:

  • ✅ Accept their decision
  • ✅ Explain security is already good with fail2ban
  • ❌ DO NOT keep suggesting SSH keys
  • ❌ DO NOT say "but SSH keys are better"
  • ❌ DO NOT make them feel their choice is wrong

**User knows their use case better than you:**

  • They might need portability (login from anywhere)
  • They might not want key file management
  • They might prefer convenience over maximum security
  • **Respect their decision and move on**

Pitfalls

1. Disabling Password Auth Too Early

**Problem:** User currently uses password, you disable it, user gets locked out.

**Solution:**

  • A
Read more
@kevinnft
Ships withai-agent-skills

191 attribution-first agent skills for Hermes Agent, Claude Code, Cursor — one installer, 28 categories, searchable catalog. See NOTICE for upstream attribution.

Stars on GitHub

Momentum

stars in total
14
Star history of kevinnft/ai-agent-skills on GitHub, a chart by star-history.com

Other skills on ai-agent-skills.

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills10d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc12d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react1d252k
@facebook@facebookInstall Skill

Questions about vps-security-hardening.

Which coding agents can use vps-security-hardening?
vps-security-hardening installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.