Mmcp.market

vps-security-hardening skill

by kevinnft·kevinnft/ai-agent-skills·14 stars·MIT

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

C60/100content scan

Is the vps-security-hardening skill safe?

Read the findings before you install it. We read 2 files in the folder on 2026-09-28.

  • highSKILL.md:33

    Reads credential files (SSH keys, cloud or package-manager tokens) that a skill has no normal reason to touch.

    ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N '' -C "user@machine"
  • mediumSKILL.md:131

    Edits shell startup files, cron or launch agents, so something runs again after the skill is done.

    sudo systemctl enable fail2ban

Install the vps-security-hardening skill

A skill is a folder. Copy it into your agent's skills folder and the agent loads it when the task matches its description.

git clone --depth 1 https://github.com/kevinnft/ai-agent-skills.git /tmp/ai-agent-skills
mkdir -p ~/.claude/skills
cp -r /tmp/ai-agent-skills/skills/devops/vps-security-hardening ~/.claude/skills/vps-security-hardening
available in every project

In the Claude apps, zip the folder and upload it from the Skills settings. The folder on GitHub

The instructions your agent would load

SKILL.md as published, without the frontmatter. Read it on GitHub

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
  1. Login to VPS via web console (provider dashboard → Console/Terminal)
  1. 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
  1. 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
  1. SSH in with password, add your key
  2. 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
  1. Check listening ports
sudo ss -tulpn
   sudo netstat -tulpn
  1. 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
  1. Check user accounts
cat /etc/passwd | grep -E '/bin/(bash|sh)$'
   sudo lastlog
  1. 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

More skills from kevinnft/ai-agent-skills

  • Aaddyosmani-tddDrives development with tests. Use when implementing any logic, fixing any bug, or changing any behavior. Use when you need to prove that code works, when a bug report arrives, or when you're about to modify existing functionality.
  • AairtableAirtable REST API via curl. Records CRUD, filters, upserts.
  • Aapi-and-interface-designGuides stable API and interface design. Use when designing APIs, module boundaries, or any public interface. Use when creating REST or GraphQL endpoints, defining type contracts between modules, or establishing boundaries between frontend and backend.
  • Aapi-monitoring-botsBuild monitoring bots that poll APIs and send notifications on state changes (new listings, price alerts, status updates)
  • Aapple-notesManage Apple Notes via memo CLI: create, search, edit.
  • Aapple-remindersApple Reminders via remindctl: add, list, complete.
  • Aarchitecture-diagramDark-themed SVG architecture/cloud/infra diagrams as HTML.
  • AarxivSearch arXiv papers by keyword, author, category, or ID.
  • Aascii-artASCII art: pyfiglet, cowsay, boxes, image-to-ascii.
  • Aascii-videoASCII video: convert video/audio to colored ASCII MP4/GIF.
  • AaudiocraftAudioCraft: MusicGen text-to-music, AudioGen text-to-sound.
  • CaxolotlAxolotl: YAML LLM fine-tuning (LoRA, DPO, GRPO).

All agent skills → · MCP servers