ZyVOP Logo
Content That Connects
SeriesAI NewsWhy ZyVOPJoin Discord
LoginGet Started
ZyVOP Logo
Content That Connects

The Developer Publishing Hub. Write once, cross-post to Dev.to, Medium, Hashnode, WordPress & Bluesky with automated canonical source tags and zero paywalls.

Content

  • Categories
  • Tags
  • Badges
  • Leaderboard
  • Write Article
  • Newsletter

Company

  • About Us
  • Why ZyVOP
  • Developer API & CLI
  • Write for Us
  • Contact

Connect

  • Privacy Policy
  • Terms of Service
  • Cookie Policy
  • DMCA Policy
  • Code of Conduct

© 2026 ZyVOP. Developer Publishing Hub.

Zero paywalls · Full content ownership
All systems operational
HomeThe 15-Minute VPS Security Masterclass: Lock Down Your Linux Server

The 15-Minute VPS Security Masterclass: Lock Down Your Linux Server

A Practical Beginner-to-Advanced Guide to Hardening Your Linux VPS Against Hackers, Bots, Malware, and Zero-Day Threats

ZyVOP
ZyVOP
Senior Developer
May 22, 2026
4 min read
The 15-Minute VPS Security Masterclass: Lock Down Your Linux Server
#Linux Security#Server Hardening#SSH Security#VPS Security#Fail2Ban#UFW Firewall#Ubuntu Security
👍1

You spin up a new VPS. The provider sends you root credentials. You SSH in and get straight to deploying your app because that is the exciting part.

Meanwhile, bots have already tried to log into your server 400 times while you were setting up your repo.

This is not paranoia. Run grep "Failed password" /var/log/auth.log | wc -l on any unprotected server that has been live for more than 24 hours. The number will be uncomfortable.

Securing a VPS is not complicated. It takes about 15 minutes, you do it once, and then you stop worrying about a category of problems that has ended real companies. Here is the complete checklist.


Step 1 — Create a Non-Root User (Do This First)

Never run anything as root day-to-day. Create a user immediately after first login.

# As root
adduser yourname
usermod -aG sudo yourname

# Switch to the new user and test sudo
su - yourname
sudo apt update

Step 2 — Set Up SSH Key Authentication

Password-based SSH logins will be disabled entirely. First, set up key-based auth so you do not lock yourself out.

On your local machine:

# Generate a key if you don't already have one
ssh-keygen -t ed25519 -C "[email protected]"

# Copy public key to your server
ssh-copy-id yourname@your-server-ip

Or manually:

# On the server, as yourname
mkdir -p ~/.ssh
chmod 700 ~/.ssh

# Paste your public key into this file
nano ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Test that key-based login works before disabling passwords:

# From a new terminal on your local machine — confirm this works
ssh yourname@your-server-ip

Step 3 — Harden SSH Config

sudo nano /etc/ssh/sshd_config

Change or add these lines:

# Disable root login
PermitRootLogin no

# Disable password authentication (keys only)
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no

# Change the default port (reduces noise from bots)
Port 2222

# Only allow specific users
AllowUsers yourname

# Reduce login grace time
LoginGraceTime 20

# Disable X11 forwarding unless you need it
X11Forwarding no

Restart SSH — do not close your current session first:

sudo systemctl restart sshd

Open a new terminal and test logging in with the new port:

ssh -p 2222 yourname@your-server-ip

Once confirmed, close the old session.


Step 4 — Configure UFW (Uncomplicated Firewall)

sudo apt install ufw -y

# Deny everything by default
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow SSH on your new port
sudo ufw allow 2222/tcp

# Allow web traffic
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Enable the firewall
sudo ufw enable

# Verify
sudo ufw status verbose

If you need other ports (e.g. Postgres from a specific IP only):

# Only allow Postgres from a specific trusted IP
sudo ufw allow from 203.0.113.0 to any port 5432

Never expose Postgres, Redis, or any database port to 0.0.0.0. Ever.


Step 5 — Install Fail2Ban

Fail2Ban watches your auth logs and automatically bans IPs that fail login attempts repeatedly.

sudo apt install fail2ban -y

# Create a local override config (never edit jail.conf directly)
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local

Find and update the [sshd] section:

[sshd]
enabled = true
port    = 2222
filter  = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime  = 3600
findtime = 600

Start and enable:

sudo systemctl enable fail2ban
sudo systemctl start fail2ban

# Check it's working
sudo fail2ban-client status sshd

Step 6 — Automatic Security Updates

You want security patches applied without having to remember to do it manually.

sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure --priority=low unattended-upgrades

Edit the config to be explicit:

sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

Uncomment and verify these lines are present:

Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
};

Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Mail "[email protected]";

Set it to run daily:

sudo nano /etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

Step 7 — Set Up a Basic Audit Log

Install auditd to track file and system changes you care about:

sudo apt install auditd -y
sudo systemctl enable auditd
sudo systemctl start auditd

# Watch for changes to sensitive files
sudo auditctl -w /etc/passwd -p wa -k passwd_changes
sudo auditctl -w /etc/ssh/sshd_config -p wa -k ssh_config_changes
sudo auditctl -w /var/log/auth.log -p ra -k auth_log_reads

# Make rules persistent
sudo nano /etc/audit/rules.d/hardening.rules

Add:

-w /etc/passwd -p wa -k passwd_changes
-w /etc/shadow -p wa -k shadow_changes
-w /etc/ssh/sshd_config -p wa -k sshd_config
-w /etc/sudoers -p wa -k sudoers_changes

Step 8 — Disable Unused Services

Check what is listening on your server:

sudo ss -tulpn

For every service you do not recognize or need, stop and disable it:

sudo systemctl stop <service-name>
sudo systemctl disable <service-name>

Common ones you probably do not need on a fresh VPS: cups (printing), avahi-daemon (network discovery), bluetooth.


Step 9 — Set Up Logwatch or Similar Alerting

Install logwatch to get a daily email digest of anything suspicious:

sudo apt install logwatch -y

# Test it
sudo logwatch --output stdout --format text --range today

Configure for daily emails:

sudo nano /etc/cron.daily/00logwatch
#!/bin/bash
/usr/sbin/logwatch --output mail --mailto [email protected] --detail high

Step 10 — The Quick Sanity Check

After everything is set up, run through this:

# 1. Confirm root login is disabled
ssh root@your-server-ip -p 2222  # Should be refused

# 2. Confirm UFW is active
sudo ufw status

# 3. Confirm Fail2Ban is running
sudo fail2ban-client status

# 4. Check what ports are open externally
nmap -p- your-server-ip  # Install nmap locally

# 5. Check for failed login attempts
sudo grep "Failed password" /var/log/auth.log | tail -20

# 6. Check for successful logins (verify only yours)
sudo last | head -20

What This Does Not Cover

This guide handles the basics that catch the overwhelming majority of attacks targeting VPS instances. What it does not cover — and what matters at the next level:

  • SSL certificate management (use Certbot with Let's Encrypt; automate renewal)

  • Container security if you are running Docker (AppArmor profiles, non-root containers, no --privileged)

  • Application-level secrets management (use environment variables or a secrets manager, never hardcode credentials)

  • Database hardening (separate Postgres post incoming)

A hardened VPS is not invulnerable. It is significantly less interesting to attackers than the unprotected one next door. In practice, that is usually enough.

Comments (0)

Login to post a comment.

ZyVOP
ZyVOP

Founder of Zyvop 🚀 | Building AI-driven tools & premium insights for software engineers, CTOs, and tech leaders. Obsessed with automating workflows and exploring the frontier of AI.

Subscribe to ZyVOP's Newsletter

More from ZyVOP

View profile

Debian Adopts "Responsible Use of Generative AI" After Nine-Way Condorcet Vote

Debian's General Resolution 2026-002 closed on August 28 with "Responsible Use of Generative AI" beating eight rival proposals, including a Social Contract ban, by a clear Condorcet margin, per the project secretary's published beat matrix.

3 minAug 30

How I Built a Real-Time Developer Trend Radar Into My SEO Growth Engine

An AI-powered content intelligence system that streams live developer conversations from Hacker News, Dev.to, Google Search, and GitHub — and turns them into ready-to-write blog opportunities with one click.

12 minAug 29

Qwen3.8-Flash-Next Cost Efficiency, OpenExecutive Satire, and Multi-Vector Retrieval Advances

This week's digest covers Qwen3.8-Flash-Next's push for ultimate cost-efficiency, the viral OpenExecutive project, and the technical release of MultiVectorEncoder in Sentence-Transformers v6.0.

4 minAug 28

Anthropic’s Pricing Shock, Granite 4.2 Open‑Source Leap, and AI‑Powered Security & Policy Shifts

From Anthropic’s flagship model losing steam to IBM’s 512 K‑token Granite 4.2, plus a new wave of AI‑driven security exploits and policy alarms, this week’s digest maps the technical and market forces you need to act on now.

3 minAug 26

Introducing Questions and Discussions: A New Way to Connect!

We are thrilled to announce a major update to how you can interact and share content on our platform! Up until now, sharing your thoughts meant writing a standa...

2 minAug 1