We provisioned a fresh Ubuntu VPS last month for a test. No website, no applications, no DNS pointing to it - just a blank server with a public IP address. Within the first 24 hours, it received 2,847 SSH brute force login attempts from 14 different countries. The top attacker tried 600 different username/password combinations in under an hour. This wasn't targeted. Nobody knew that server existed. Automated bots scan every IPv4 address continuously, probing for unsecured machines to compromise.
Your brand new VPS is a target from the moment it comes online. The default configuration most providers ship is functional, not secure. Root login enabled, password authentication on, no firewall, no intrusion detection. It's the digital equivalent of leaving your front door open in a busy city and hoping nobody walks in.
Here's what we do in the first 30 minutes of every VPS we provision - and what you should do too.
Minute 0-5: Create a Non-Root User
The root account has unlimited power. Every automated attack targets it by name. Step one is creating a regular user account and giving it sudo privileges.
adduser deploy
usermod -aG sudo deploy
Replace "deploy" with whatever username you prefer - just not "admin," "user," or "test," which are also commonly targeted. From this point forward, you'll log in as this user and use sudo for administrative tasks.
Test the new account by opening a second SSH session and logging in as the new user before proceeding. Never lock yourself out of root access until you've confirmed the new user works.
Minute 5-12: SSH Key Authentication
Password authentication is the single biggest vulnerability on a fresh VPS. Even strong passwords are vulnerable to brute force at the scale these bots operate. SSH keys are exponentially more secure - a 4096-bit RSA key would take billions of years to crack.
Generate Keys on Your Local Machine
If you don't already have an SSH key pair, generate one on your local computer (not the server):
ssh-keygen -t ed25519 -C "your-email@example.com"
Ed25519 keys are shorter, faster, and more secure than RSA. If you need compatibility with older systems, use ssh-keygen -t rsa -b 4096 instead.
Copy the Public Key to the Server
ssh-copy-id deploy@your-server-ip
Or manually create the authorized_keys file:
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
# Paste your public key into this file:
nano /home/deploy/.ssh/authorized_keys
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh
Lock Down SSH Configuration
Now edit the SSH daemon configuration:
sudo nano /etc/ssh/sshd_config
Change or add these lines:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
PermitRootLogin no blocks direct root login entirely. PasswordAuthentication no disables password-based login - only keys work. MaxAuthTries 3 limits failed attempts per connection.
Critical: Before restarting SSH, verify you can log in with your key in a separate terminal session. Then restart:
sudo systemctl restart sshd
We've seen people lock themselves out of their own servers by restarting SSH before testing key access. Don't be that person. Always keep an existing session open as a safety net.
Change the SSH Port
Default SSH runs on port 22. Moving it won't stop a determined attacker, but it eliminates 90%+ of automated bot traffic - most bots only scan port 22.
In the same sshd_config:
Port 2222
Use any port between 1024 and 65535 that isn't used by another service. We typically use something in the 20000-50000 range. Restart SSH again and update your connection commands:
ssh -p 2222 deploy@your-server-ip
Minute 12-18: Firewall Setup
A firewall ensures only the traffic you explicitly allow reaches your server. UFW (Uncomplicated Firewall) comes pre-installed on Ubuntu and is straightforward to configure.
# Allow your custom SSH 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
Important: Allow your SSH port before enabling UFW, or you'll lock yourself out immediately. We've had clients call us in a panic because they enabled UFW before adding an SSH rule. Don't learn this lesson the hard way.
For servers that don't need web traffic (database servers, internal tools), only allow SSH and the specific ports your application requires. The default deny policy blocks everything else.
Check the status:
sudo ufw status verbose
For CentOS/RHEL systems, use firewalld instead:
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
Minute 18-24: Fail2ban
Even with key-only authentication on a non-standard port, some bots will find you and keep trying. Fail2ban monitors log files and automatically bans IP addresses that show malicious patterns.
sudo apt install fail2ban -y
Create a local configuration file (never edit the main config - it gets overwritten on updates):
sudo nano /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
banaction = ufw
[sshd]
enabled = true
port = 2222
logpath = %(sshd_log)s
maxretry = 3
bantime = 86400
This configuration bans any IP that fails SSH authentication 3 times within 10 minutes, blocking them for 24 hours (86400 seconds). The default ban for other services is 1 hour.
Start and enable fail2ban:
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Check active bans:
sudo fail2ban-client status sshd
On our managed servers, fail2ban bans an average of 40-60 unique IPs per day. On servers still running SSH on port 22 with password auth, that number can exceed 500. It's a war of attrition that you automate or lose.
Minute 24-28: Automatic Security Updates
Vulnerabilities in system packages get discovered regularly. Waiting for a human to manually install security patches is a window of opportunity for attackers. Automatic security updates close that window.
On Ubuntu/Debian:
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure -plow unattended-upgrades
Verify the configuration:
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
Ensure these lines are uncommented:
"${distro_id}:${distro_codename}-security";
For email notifications when updates are applied (recommended so you know what changed):
Unattended-Upgrade::Mail "your-email@example.com";
On CentOS/RHEL, use dnf-automatic:
sudo dnf install dnf-automatic -y
sudo systemctl enable --now dnf-automatic-install.timer
A word of caution: automatic updates for security patches are almost always safe. Automatic updates for all packages can occasionally break things - a PHP minor version update, a MySQL configuration change. We recommend automating security updates only and handling everything else in scheduled maintenance windows.
Minute 28-30: Disable Unused Services and Final Checks
Find and Stop Unnecessary Services
sudo systemctl list-units --type=service --state=running
Review every running service. A typical fresh VPS might have services you don't need: Postfix (if you're not sending email from this server), snapd (if you don't use snap packages), rpcbind (NFS-related, rarely needed on a web server). Disable what you don't use:
sudo systemctl disable --now rpcbind
sudo systemctl disable --now snapd
Every running service is a potential attack vector. Fewer services mean a smaller attack surface.
Verify Open Ports
sudo ss -tlnp
This shows all listening TCP ports. You should only see your custom SSH port and any services you intentionally configured. If something unexpected is listening, investigate immediately.
Set Up Basic Log Monitoring
At minimum, know where your logs are and check them periodically:
/var/log/auth.log- authentication attempts (SSH, sudo)/var/log/syslog- general system messages/var/log/ufw.log- firewall blocked connections/var/log/fail2ban.log- banned IPs and trigger events
For serious monitoring, install a log aggregation tool or ship logs to an external service. But for the first 30 minutes, just knowing these files exist and checking them is a good start.
Beyond the First 30 Minutes
These steps handle the most critical attack vectors, but security is ongoing. In the days following initial setup, you should also:
- Configure file integrity monitoring (AIDE or OSSEC) to alert you if system files change unexpectedly
- Set up regular backups with off-server storage - a compromised server with good backups is recoverable; one without backups might not be
- Install and configure a web application firewall (ModSecurity or similar) if you're running web applications
- Implement log shipping to an external monitoring service so that if the server is compromised, the attacker can't erase the evidence
- Schedule quarterly security audits to review access, update configurations, and check for new vulnerabilities
Why Managed VPS Exists
Everything in this guide takes about 30 minutes if you know what you're doing. If you're doing it for the first time, budget two to three hours and expect to troubleshoot at least one lockout.
More importantly, this is day-one security. A VPS needs ongoing attention - monitoring for anomalies, responding to new CVEs, updating configurations as best practices evolve, checking that backups actually work (not just that they run). Most business owners don't have time for this, and most in-house developers have other priorities.
This is exactly why we offer managed VPS hosting. Every server we provision goes through this hardening process and more. We monitor 24/7, apply patches, manage backups, and respond to incidents. Our clients get the performance and control benefits of a VPS without needing to become Linux sysadmins.
But if you prefer to manage your own server - and many technically inclined business owners do - this guide gives you a solid foundation. The first 30 minutes matter more than any other 30 minutes in your server's life. Don't skip them.