What to do in the first half hour on a fresh Ubuntu or Debian server. SSH keys, firewall, fail2ban, automatic updates, swap and a first backup.
You bought the VPS, the root password landed in your inbox, you’re excited. Bad news: from the moment your server hits the internet, bots from every corner of the world start knocking on its SSH door. Don’t believe me? Check journalctl -u ssh in a few hours. Login attempts as root don’t trickle in one by one, they scroll by in pages.
Good news: nearly all of those bots are looking for easy prey. Close a few doors in the first half hour and you drop off their list. The commands here are for Ubuntu and Debian; on another distribution the logic is the same, only the package manager changes.
Short answer: update the system, create your own user, log in over SSH with keys only, disable root and password logins, open only the ports you need, turn on automatic security updates and take the first backup. The rest is detail.
1. Update first
Provider images are often weeks or months old. First job:
apt update && apt full-upgrade -y
If the kernel was updated, the file /var/run/reboot-required appears. If it’s there, reboot now: rebooting while nothing runs on the server costs nothing.
2. Don’t live as root, create your own user
Root can do anything, accidents included. Create a user with sudo rights for daily work:
adduser semih
usermod -aG sudo semih
3. SSH keys: give up on passwords
Generate a key pair on your own computer and copy the public key to the server:
ssh-keygen -t ed25519 -C "laptop"
ssh-copy-id semih@SERVER_IP
Now the most important rule: without closing the session you already have open, try ssh semih@SERVER_IP in a new terminal. Don’t move on until you’ve seen that the key works and sudo runs. Locking yourself out of your own server is the classic accident on this list.
4. Harden SSH
A separate file is cleaner than editing the main config. There’s a small, sneaky trap here: when OpenSSH sees the same option in several places, it uses the first value it reads, and it reads the files in sshd_config.d in alphabetical order. Some cloud images leave password login on in 50-cloud-init.conf. Start your file name with 00- and your settings are read first:
# /etc/ssh/sshd_config.d/00-hardening.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
Check the syntax before applying, restart the service, then look at what’s actually in effect:
sudo sshd -t && sudo systemctl restart ssh
sudo sshd -T | grep -E "permitrootlogin|passwordauthentication"
Moving SSH off port 22 cuts the noise in your logs, but it isn’t a security measure. The real protection is having password login switched off.
5. Firewall: open only what you need
ufw ships with Ubuntu; on Debian, install it with apt install ufw. Order matters: allow SSH before you enable the firewall:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80,443/tcp
sudo ufw enable
A warning if you use Docker: ports that Docker publishes can bypass ufw rules. A database container started with -p 3306:3306 may be open to the internet even though ufw says it’s closed. Bind services that only the server itself should reach as -p 127.0.0.1:3306:3306.
6. fail2ban: make door-rattlers wait
With password login off, bots can’t get in anyway; here fail2ban mostly cuts noise and wasted resources. Still, it takes a minute:
sudo apt install fail2ban
# /etc/fail2ban/jail.local
[sshd]
enabled = true
maxretry = 5
bantime = 1h
On systems that don’t keep an auth.log, like Debian 12, add backend = systemd to the same section. Check the status with sudo fail2ban-client status sshd.
7. Let security updates arrive on their own
You won’t log in every morning to check for updates. Nobody does. Let the system handle it:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
This installs security updates only. Major upgrades of PHP or your database stay under your control, as they should.
8. Time zone and clock
If the time in your logs doesn’t match your own, you’ll look in the wrong place when hunting a 3 a.m. error:
sudo timedatectl set-timezone Europe/Istanbul
timedatectl
Use your own zone, of course. The output should say System clock synchronized: yes; SSL certificates and two-factor codes both depend on the correct time.
9. A small swap for a small server
On a server with 1 or 2 GB of RAM, a composer install or a large backup job can exhaust memory. Linux then kills a process, and the one it kills is usually the database. A small swap file turns that sudden crash into a slowdown:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Swap is no substitute for RAM. If the server is swapping all the time, that’s not a tuning problem, it’s a signal to upgrade.
10. First backup, first day
Putting backups off until “the site goes live” is the most expensive delay there is. Keep the rule simple: the database dump and uploaded files go somewhere off the server, every day. Your provider’s snapshots are nice, but if something happens to the provider account, the backup goes with it.
And write this sentence down somewhere: an untested backup isn’t a backup, it’s a hope. Once a month, restore it on an empty machine and see that it actually works.
Checklist
| Step | Command or file | Why |
|---|---|---|
| Update | apt full-upgrade |
Closes known holes |
| User | adduser, usermod -aG sudo |
No daily work as root |
| SSH key | ssh-copy-id |
Makes password guessing pointless |
| SSH config | 00-hardening.conf |
Turns off root and password login |
| Firewall | ufw |
Only 22, 80 and 443 stay open |
| fail2ban | jail.local |
Makes brute-forcers wait |
| Auto updates | unattended-upgrades |
Security patches don’t wait for you |
| Clock | timedatectl |
Logs and certificates see the right time |
| Swap | /swapfile |
Prevents sudden crashes when memory fills |
| Backup | Off-server, daily | Insurance for the bad day |
That’s it. Half an hour later you have a server that sits in the “not worth the effort” part of the bots’ lists. Where to look when it slows down one day is a separate post.
If you’d rather hand server setup or a migration to someone, write to me through the quote form.