You just rented your first VPS. Maybe it's from Hetzner, DigitalOcean, or some random provider you found on LowEndBox. It doesn't matter where you got itâwhat matters is what you do with it now.
A fresh VPS is like a blank canvas. It's also like a house with the doors unlocked. The moment you spin it up, bots are already scanning it, trying default passwords, looking for weaknesses. I've watched failed login attempts on a fresh server go from zero to thousands per day within hours.
This guide walks you through hardening a Debian VPS from scratch. We'll cover everything from basic updates to kernel hardening, SSH security, firewall configuration, and automated security updates. By the end, you'll have a server that can defend itself against the automated junk that's constantly probing every IP on the internet.
What We'll Cover
- 1. Update Your System
- 2. Configure Swap
- 3. Set Up UFW Firewall
- 4. Create a Non-Root User
- 5. Harden SSH
- 6. Install Fail2ban
- 7. Kernel Hardening
- 8. Automatic Security Updates
- 9. Log Monitoring
- 10. Secure File Permissions
- 11. Disable Core Dumps
- 12. Disable Unnecessary Services
- 13. Cleanup
- 14. Install a Web Server (Optional)
- 15. Set Up a Tor Onion Site (Optional)
1. Update Your System
First things first. When you get a fresh VPS, the first thing you should do is update everything. I don't care if the provider says "pre-configured" or "latest image"âyou update anyway. Security patches come out constantly, and your first job is to install them.
sudo apt update
sudo apt upgrade -y
The apt update part refreshes your package listsâit tells your server what's available. Then apt upgrade actually installs the new versions. The -y flag just answers "yes" to all prompts automatically.
2. Configure Swap
Swap is like virtual RAMâit's disk space that your server uses when it runs out of actual memory. Even if you have plenty of RAM, having swap configured prevents your server from crashing when something unexpectedly eats memory. It's a safety net.
Let's check if you already have swap:
sudo swapon --show
If that shows nothing, you need to create swap. A good rule of thumb is to have swap equal to your RAM, or at least 2GB if you have less than that:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
Now we make it permanent so it comes back after a reboot:
sudo cp /etc/fstab /etc/fstab.bak
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
3. Set Up UFW Firewall
A firewall is your first line of defense. It decides what can come into your server and what can't. We're going to use UFW (Uncomplicated Firewall)âit's exactly what it sounds like: a simple interface to the complex iptables firewall built into Linux.
The strategy is simple: block everything by default, then explicitly allow only what you need.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw --force enable
sudo ufw status
Let's break this down:
deny incomingâ Block everything coming in unless we explicitly allow itallow outgoingâ Let your server make outgoing connections freelyallow OpenSSHâ We need SSH to still work, or we'd lock ourselves out!
4. Create a Non-Root User
You're probably tempted to just use root for everything. Don't. Root is the administrator accountâit can do literally anything, including destroying your entire server with one command. That's dangerous in two ways: you could accidentally break something, and if someone compromises root, they own everything.
Create a regular user instead:
sudo adduser yourname
Follow the prompts. Pick a strong password (I'll explain why we still need passwords even though we're disabling them later).
Now give this user sudo accessâthat means they can run commands as root when needed:
sudo usermod -aG sudo yourname
The -aG means "append to group" and sudo is the group that allows administrative commands.
5. Harden SSH
SSH (Secure Shell) is how you connect to your server remotely. By default, it's set up pretty loosely. We're going to lock it down hard:
- Disable root login â Never allow root to log in directly
- Disable password authentication â Only allow SSH keys
- Use SSH keys â Much more secure than passwords
- Change the SSH port â Optional, but reduces automated attack noise
First, you need to set up SSH key-based authentication. On your local machine (not the server):
ssh-keygen -t ed25519
ssh-copy-id yourname@your-server-ip
If you're on Windows or want more options, check out the GPG guideâyou can actually use GPG keys for SSH authentication too.
Now let's harden SSH on the server. We'll create a configuration file that overrides the defaults:
sudo nano /etc/ssh/sshd_config.d/custom.conf
Paste in these settings (change port 2222 to whatever you want, or use 22):
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
X11Forwarding no
AllowTcpForwarding no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
Port 2222
Save and exit (Ctrl+X, then Y, then Enter in nano). Then restart SSH:
sudo systemctl restart ssh
If you changed the port, remember to specify it when connecting:
ssh -p 2222 yourname@your-server-ip
sudo ufw allow 2222/tcp
6. Install Fail2ban
Fail2ban is beautiful in its simplicity. It watches your logs for failed login attempts, and when some IP tries and fails too many times, it bans them automatically. It's like having a bouncer who throws out troublemakers before they can cause problems.
sudo apt install -y fail2ban
Now configure it. We'll create a local configuration that overrides the defaults:
sudo nano /etc/fail2ban/jail.local
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
[sshd]
enabled = true
port = 2222
Adjust the port number if you changed SSH from the default. This config says: ban anyone who fails to log in 5 times within 10 minutes for 1 hour.
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Check if it's running:
sudo fail2ban-client ping
If it replies "pong", you're good. You can see banned IPs with:
sudo fail2ban-client status sshd
7. Kernel Hardening
The Linux kernel is the core of your operating system. We can tune it with sysctl settings to be more secure against network attacks. This is the "hardening" partâmaking the OS itself more defensive.
sudo nano /etc/sysctl.d/99-custom.conf
# Prevent SYN flood attacks
net.ipv4.tcp_syncookies = 1
# Prevent IP spoofing
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Don't accept source routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
# Ignore broadcast pings (prevents ping floods)
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Don't accept ICMP redirects (security risk)
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
# Log suspicious packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
Save and apply these settings:
sudo sysctl -p /etc/sysctl.d/99-custom.conf
8. Automatic Security Updates
You won't remember to log in and run apt update every week. That's okayâlet the server do it automatically. We'll use Debian's unattended-upgrades package.
sudo apt install -y unattended-upgrades
Configure it:
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
"${distro_id}:${distro_codename}-updates";
};
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-RebootTime "02:00";
This tells the server to automatically install security updates and reboot at 2 AM if needed (kernel updates often require a reboot).
9. Log Monitoring
You can't watch your server 24/7. But you can get daily summaries of what's happening. Logwatch parses your system logs and emails you a digest.
sudo apt install -y logwatch
Create a cron job to run it daily:
sudo nano /etc/cron.daily/logwatch
#!/bin/sh
/usr/sbin/logwatch --output mail --mailto root --detail high
sudo chmod 755 /etc/cron.daily/logwatch
.forward file in /root/ with your email address.
10. Secure File Permissions
Linux file permissions determine who can read, write, or execute files. We need to lock down sensitive directories, especially SSH keys.
sudo chmod 700 /root
sudo chmod 700 /home/*/.ssh 2>/dev/null
sudo chmod 600 /home/*/.ssh/authorized_keys 2>/dev/null
This ensures:
- Only root can access /root
- Only the owner can access their .ssh directory
- Only the owner can read their authorized_keys file
11. Disable Core Dumps
When a program crashes, it can dump its memory contents to a file. That memory might contain passwords, keys, or other sensitive data. We should disable this.
sudo nano /etc/security/limits.conf
Add at the bottom:
* soft core 0
* hard core 0
Also add to the kernel hardening file:
sudo echo "fs.suid_dumpable = 0" >> /etc/sysctl.d/99-custom.conf
sudo sysctl -p /etc/sysctl.d/99-custom.conf
12. Disable Unnecessary Services
Every running service is a potential attack vector. If you're not using something, turn it off. This reduces your attack surface.
sudo systemctl stop cups bluetooth avahi-daemon
sudo systemctl disable cups bluetooth avahi-daemon
What these are:
- cups â Print service. Unless you have a printer connected, you don't need this.
- bluetooth â Almost nobody needs this on a headless server.
- avahi-daemon â Service discovery. Useful on a local network, but not on a public server.
13. Cleanup
Let's clean up unused packages and free some disk space:
sudo apt autoremove -y
sudo apt autoclean
autoremove removes packages that were installed as dependencies but are no longer needed. autoclean clears the apt package cache.
14. Install a Web Server (Optional)
If you're hosting a website, you'll need a web server. I prefer nginx for its performance, but Apache is also fine. Let's install nginx:
sudo apt install -y nginx
sudo ufw allow 'Nginx Full'
sudo systemctl enable nginx
sudo systemctl start nginx
The firewall rule allows both HTTP (port 80) and HTTPS (port 443) traffic.
If you prefer Apache instead:
sudo apt install -y apache2
sudo a2enmod ssl rewrite headers
sudo ufw allow 'Apache Full'
sudo systemctl enable apache2
sudo systemctl start apache2
15. Set Up a Tor Onion Site (Optional)
Want to host your site anonymously? A Tor onion site lets visitors access your site without either of you revealing your IP addresses. It's the ultimate in privacy hosting.
Check out my Build an Onion Site tutorial for the full walkthrough.
<meta http-equiv="onion-location" content="http://your-onion-address.onion/path/to/page.html" />Each page needs its own meta tag pointing to the corresponding onion page. Tor Browser will show a purple onion icon in the address bar when it detects this.
That's ItâYour Server Is Hardened
You now have a VPS that:
- Has all security updates installed automatically
- Uses a firewall to block unauthorized access
- Requires SSH keys (not passwords) to log in
- Automatically bans attackers with Fail2ban
- Has kernel-level protections against network attacks
- Sends you daily log summaries
- Keeps sensitive data locked down with proper permissions
This is the foundation. From here, you can host websites, run Docker containers, set up databases, or whatever else you need your server to do.
Remember: security isn't a one-time thing. Keep an eye on those logwatch emails. Update your server regularly. Monitor fail2ban to see who's trying to get in. The automation handles a lot, but you're still the one watching the house.
The revolution will not be proprietary.