You just purchased a shiny new VPS from DigitalOcean, Hetzner, Vultr, or any cloud provider. Your terminal is staring back at you with a blinking cursor. The next ten minutes are the most critical — they determine whether your server becomes a hardened fortress or an open door for attackers.
Every day, automated bots scan millions of IP addresses looking for freshly provisioned servers with default configurations. Within minutes of your VPS going live, SSH brute-force attempts begin. This guide walks you through the essential first steps to lock down your Ubuntu server, step by step, command by command.
According to security research, a new public-facing server receives its first automated attack within 30 seconds to 5 minutes of going online. Do not leave your server in its default state.
Step 1: Log In via SSH for the First Time
Your hosting provider gave you an IP address and root credentials (either a password or an SSH key). Open your terminal and connect:
The authenticity of host '203.0.113.50' can't be established.
ED25519 key fingerprint is SHA256:xR4j...
Are you sure you want to continue connecting (yes/no)? yes
[email protected]'s password: ********
Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-51-generic x86_64)
root@vps:~#
You are now logged in as root. This is both powerful and dangerous — every command you run has unlimited access to the system. Our first priority is to reduce our exposure by creating a dedicated user account.
Step 2: Change the Root Password
Many providers send the root password in plain text via email. Change it immediately to something strong and unique:
New password: ********
Retype new password: ********
passwd: password updated successfully
Use a password manager to generate a random 20+ character password. You will rarely need to type this — SSH keys are your primary authentication method.
Step 3: Create a New Sudo User
Running everything as root is a recipe for disaster. A mistyped destructive command could wipe your entire system. Create a regular user with sudo privileges instead:
Adding user 'deploy' ...
Adding new group 'deploy' (1001) ...
Adding new user 'deploy' (1001) with group 'deploy' ...
Creating home directory '/home/deploy' ...
New password: ********
Full Name []: Deploy User
root@vps:~# usermod -aG sudo deploy
# No output = success
root@vps:~# id deploy
uid=1001(deploy) gid=1001(deploy) groups=1001(deploy),27(sudo)
Now verify that your new user can actually use sudo. Open a new terminal tab (keep your root session open as a backup) and test:
[email protected]'s password: ********
deploy@vps:~$ sudo whoami
[sudo] password for deploy: ********
root
Your new user has full sudo access. From this point forward, use
deploy for daily operations and only switch to root when absolutely necessary.
Step 4: Set Up SSH Key Authentication
Passwords are vulnerable to brute-force attacks. SSH keys are cryptographically secure and effectively impossible to guess. On your local machine (not the server), generate an SSH key pair:
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/you/.ssh/id_ed25519): [Enter]
Enter passphrase (empty for no passphrase): ********
Your identification has been saved in /home/you/.ssh/id_ed25519
Your public key has been saved in /home/you/.ssh/id_ed25519.pub
local$ ssh-copy-id [email protected]
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s)
Number of key(s) added: 1
Test that key-based login works before changing any SSH configuration:
Enter passphrase for key '/home/you/.ssh/id_ed25519': ********
deploy@vps:~$ # No password prompt means key auth is working!
Step 5: Disable Password Authentication
Now that SSH keys work, disable password login entirely. This is the single most impactful security change you can make:
# Find and change these lines:
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin prohibit-password
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
deploy@vps:~$ sudo systemctl restart sshd
Before restarting SSH, open a second terminal and verify you can still log in with your SSH key. If you lose access, you will need to use your provider's console access to fix the configuration.
Step 6: Configure UFW Firewall
A firewall is your server's front door. By default, Ubuntu does not enable UFW (Uncomplicated Firewall), leaving all ports open. Let us fix that:
Default incoming policy changed to 'deny'
deploy@vps:~$ sudo ufw default allow outgoing
Default outgoing policy changed to 'allow'
deploy@vps:~$ sudo ufw allow 22/tcp comment 'SSH'
Rule added
deploy@vps:~$ sudo ufw allow 80/tcp comment 'HTTP'
Rule added
deploy@vps:~$ sudo ufw allow 443/tcp comment 'HTTPS'
Rule added
deploy@vps:~$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed (y|n)? y
Firewall is active and enabled on system startup
deploy@vps:~$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere # SSH
80/tcp ALLOW IN Anywhere # HTTP
443/tcp ALLOW IN Anywhere # HTTPS
Here is what each rule does and why it matters:
| Port | Protocol | Purpose | Why Open |
|---|---|---|---|
| 22 | TCP | SSH | Remote server access |
| 80 | TCP | HTTP | Web traffic + Let's Encrypt validation |
| 443 | TCP | HTTPS | Encrypted web traffic |
If you change your SSH port (e.g., to 2222), make sure to
sudo ufw allow 2222/tcp before enabling UFW, or you will lock yourself out immediately.
Step 7: Enable Automatic Security Updates
Unpatched vulnerabilities are one of the top attack vectors. Ubuntu's unattended-upgrades package automatically installs security patches:
Reading package lists... Done
unattended-upgrades is already the newest version (2.9.1+nmu4ubuntu1).
deploy@vps:~$ sudo dpkg-reconfigure -plow unattended-upgrades
# Select "Yes" to enable automatic updates
deploy@vps:~$ cat /etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
For additional control, you can configure what gets updated by editing /etc/apt/apt.conf.d/50unattended-upgrades. The default settings update security packages only, which is the safest option for production servers.
Step 8: Set Timezone and Hostname
Correct time is essential for log analysis, SSL certificates, cron jobs, and debugging. Set your timezone and a meaningful hostname:
deploy@vps:~$ timedatectl
Local time: Mon 2026-03-17 10:30:00 UTC
Universal time: Mon 2026-03-17 10:30:00 UTC
RTC time: Mon 2026-03-17 10:30:00
Time zone: UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active
deploy@vps:~$ sudo hostnamectl set-hostname web1.example.com
deploy@vps:~$ hostname
web1.example.com
Using UTC on servers eliminates daylight saving time confusion, makes log correlation across multiple servers easier, and is the industry standard for production environments. Your application can convert to local time for users.
Step 9: Create a Swap File
Many VPS instances come with limited RAM and no swap. If your server runs out of memory, the kernel's OOM killer will terminate processes randomly — often killing your database or web server. A swap file provides breathing room:
deploy@vps:~$ sudo chmod 600 /swapfile
deploy@vps:~$ sudo mkswap /swapfile
Setting up swapspace version 1, size = 2 GiB
deploy@vps:~$ sudo swapon /swapfile
# Make it permanent
deploy@vps:~$ echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
# Optimize swap behavior
deploy@vps:~$ sudo sysctl vm.swappiness=10
deploy@vps:~$ echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
deploy@vps:~$ free -h
total used free shared buff/cache available
Mem: 1.9Gi 312Mi 1.2Gi 1.0Mi 420Mi 1.4Gi
Swap: 2.0Gi 0B 2.0Gi
The recommended swap size depends on your RAM:
| Server RAM | Recommended Swap | Use Case |
|---|---|---|
| 1 GB | 2 GB | Budget VPS, WordPress |
| 2 GB | 2 GB | Small apps, static sites |
| 4 GB | 2-4 GB | Medium web apps |
| 8+ GB | 2-4 GB | Safety net only |
Step 10: Install Essential Tools
Install the utilities you will need for day-to-day server management:
curl wget git htop iotop ncdu tree \
fail2ban logwatch net-tools \
build-essential software-properties-common
Reading package lists... Done
Setting up fail2ban (1.1.0-1) ...
Setting up logwatch (7.9-1) ...
Here is what each package provides:
Monitoring
- htop — interactive process viewer
- iotop — disk I/O monitor
- ncdu — disk usage analyzer
Security
- fail2ban — bans IPs after failed logins
- logwatch — daily log summary emails
- ufw — already installed above
Utilities
- curl / wget — HTTP requests and downloads
- git — version control
- tree — directory visualization
Development
- build-essential — gcc, make, etc.
- software-properties-common — PPA management
- net-tools — ifconfig, netstat
Quick Setup for Fail2Ban
Fail2Ban monitors log files for suspicious activity and automatically bans offending IP addresses. The default configuration protects SSH:
deploy@vps:~$ sudo nano /etc/fail2ban/jail.local
# Add under [DEFAULT]:
bantime = 3600
findtime = 600
maxretry = 3
deploy@vps:~$ sudo systemctl enable --now fail2ban
Created symlink ... fail2ban.service.
deploy@vps:~$ sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| |- Total failed: 0
| `- File list: /var/log/auth.log
`- Actions
|- Currently banned: 0
|- Total banned: 0
`- Banned IP list:
The Complete 10-Minute Checklist
Here is every step in order with approximate time estimates:
30s
30s
1m
2m
1m
1m
1m
30s
1m
2m
Bonus: Quick Security Audit After Setup
Once everything is configured, run this quick audit to verify your setup:
deploy@vps:~$ sudo sshd -T | grep -E 'passwordauth|permitroot|pubkey'
passwordauthentication no
permitrootlogin prohibit-password
pubkeyauthentication yes
# Check firewall status
deploy@vps:~$ sudo ufw status numbered
Status: active
To Action From
[ 1] 22/tcp ALLOW IN Anywhere
[ 2] 80/tcp ALLOW IN Anywhere
[ 3] 443/tcp ALLOW IN Anywhere
# Check for listening services
deploy@vps:~$ sudo ss -tulnp
Netid State Recv-Q Send-Q Local Address:Port Process
tcp LISTEN 0 128 0.0.0.0:22 sshd
# Check swap
deploy@vps:~$ swapon --show
NAME TYPE SIZE USED PRIO
/swapfile file 2G 0B -2
# Check automatic updates
deploy@vps:~$ systemctl is-enabled unattended-upgrades
enabled
What About Changing the SSH Port?
Many guides recommend changing the default SSH port from 22 to something like 2222 or 2847. This is "security through obscurity" — it reduces log noise from automated bots but does not stop a determined attacker. Here is a balanced view:
| Approach | Pros | Cons | Verdict |
|---|---|---|---|
| Keep port 22 | Simple, standard, no firewall confusion | More bot traffic in logs | Fine with keys + fail2ban |
| Change to custom port | Reduces 99% of automated scans | Must remember the port, update scripts | Nice to have |
If you do change the port, update both UFW and your SSH config:
deploy@vps:~$ sudo sed -i 's/^#Port 22/Port 2847/' /etc/ssh/sshd_config
deploy@vps:~$ sudo systemctl restart sshd
deploy@vps:~$ sudo ufw delete allow 22/tcp
# Test with: ssh -p 2847 [email protected]
Next Steps After the First 10 Minutes
Your server is now reasonably secure for a fresh installation. Depending on your use case, your next steps will be:
For Web Hosting
- Install Nginx or Apache
- Install PHP and configure PHP-FPM
- Install MySQL or PostgreSQL
- Set up Let's Encrypt SSL
- Configure virtual hosts
For Application Deployment
- Install Docker and Docker Compose
- Set up a reverse proxy
- Configure CI/CD pipelines
- Set up monitoring
- Configure log aggregation
Or Skip Everything: Install Panelica
Everything in this guide — and much, much more — is automated by Panelica. Instead of spending 10 minutes on basic setup (and hours on the follow-up configuration), you can have a production-ready server in about 3 minutes:
____ _ _
| _ \ __ _ _ __ ___| (_) ___ __ _
| |_) / _` | '_ \ / _ \ | |/ __/ _` |
| __/ (_| | | | | __/ | | (_| (_| |
|_| \__,_|_| |_|\___|_|_|\___\__,_|
Installing Panelica Server Management Panel...
[1/20] Configuring system...
[2/20] Setting up PostgreSQL 17...
[3/20] Setting up MySQL 8...
...
[20/20] Starting all services...
Panelica installed successfully!
Panel URL: https://203.0.113.50:8443
Username: root
Password: [generated-password]
With Panelica installed, you get out of the box:
20 Managed Services
- Nginx + Apache (dual-stack)
- PHP 8.1 through 8.4 with per-user FPM pools
- MySQL 8 + PostgreSQL 17
- Redis 7 for caching
- BIND DNS server
- Postfix + Dovecot email
5-Layer Security
- Cgroups v2 resource isolation
- Namespace isolation (PID + Mount)
- SSH chroot jails
- Per-user PHP-FPM with open_basedir
- Unix permission enforcement (home 700)
Automation
- Automatic SSL with Let's Encrypt
- 9-step domain provisioning
- Backup and restore
- Fail2Ban + ModSecurity WAF
Management
- Web-based file manager
- Multi-user RBAC (Root/Admin/Reseller/User)
- Docker container management
- Cloudflare DNS integration
The initial VPS setup described in this guide is just the beginning. Installing, configuring, and maintaining Nginx, PHP, databases, email, DNS, backups, and security normally takes hours of manual work and ongoing maintenance. Panelica handles all of it through a modern web interface with one-click management.