If you only remember one thing, remember this: a fresh Ubuntu server is not production-ready by default. Before going live, lock down SSH, enable a firewall, install updates, reduce privileges, and make brute-force attacks expensive.
You do not need a massive enterprise checklist to be safer than most deployments. You just need the right first steps.
Step 1: Update everything first
sudo apt update && sudo apt upgrade -y
sudo apt autoremove -y
Do this before you install more services.
Step 2: Create a real sudo user
Do not work as root day to day.
adduser deploy
usermod -aG sudo deploy
Switch to that user after you confirm it works.
Step 3: Use SSH keys, not passwords
Generate a key locally if you do not already have one:
ssh-keygen -t ed25519 -C "your-email@example.com"
Then copy it to the server:
ssh-copy-id deploy@your-server-ip
Step 4: Harden SSH
Edit the SSH config:
sudo nano /etc/ssh/sshd_config
Set or confirm these values:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
Restart SSH only after verifying your key login works in another terminal:
sudo systemctl restart ssh
Step 5: Turn on the firewall
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status verbose
Only open the ports you actually need.
Step 6: Install Fail2ban
Fail2ban blocks repeated login abuse and costs almost nothing to set up.
sudo apt install -y fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Step 7: Keep software updated automatically
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
Step 8: Remove what you do not use
Every unnecessary service is another thing to maintain and another possible attack surface. If you do not need FTP, mail services, or old test tools, remove them.
Step 9: Use separate credentials for each app
Do not reuse the same password for the database, control panel, app secrets, and deployment workflow. If one thing leaks, you do not want everything else to fall with it.
Step 10: Check logs before launch
Look at the basics:
sudo journalctl -p 3 -xb
sudo tail -f /var/log/auth.log
sudo tail -f /var/log/nginx/error.log
Fast launch-day checklist
- Root SSH login disabled
- Password SSH login disabled
- Firewall enabled
- HTTPS ready
- Only required ports open
- App secrets stored safely
- Database user isolated per app
- Backups planned before traffic arrives
Security mistakes that happen all the time
- Keeping SSH password auth enabled “for later”
- Leaving the root account usable over SSH
- Opening ports during setup and forgetting to close them
- Using one database user for every project
- Launching before checking logs and HTTPS
What this checklist does not replace
This is a strong baseline, not a full security program. If you run regulated workloads, store sensitive personal data, or operate at larger scale, you will need more than this.
Useful next reads
After hardening the server, deploy your stack with How to Deploy a PHP App on Ubuntu Step by Step in 2026 or How to Deploy a Node.js App with Nginx and PM2.
Quick FAQ
Is UFW enough?
For many small and medium deployments, yes. It is a good baseline. Just keep the rule set minimal.
Should I change the SSH port?
It can reduce noise, but it is not a substitute for SSH keys and proper access control.
Do I need Fail2ban if I disabled password login?
It still helps with noisy traffic and is worth keeping on most public servers.