· 6 min read

Ubuntu Server Initial Setup and Security Hardening Guide

Ubuntu server initial setup and security comes down to six steps: create a non-root sudo user, log in with an SSH key, disable root and password login, turn on a firewall (UFW), add fail2ban, and enable automatic security updates. Do them in that order, on the first login, before you install anything else.

A public IPv4 address starts receiving SSH login attempts within minutes of going online. The steps below work on Ubuntu 22.04 LTS and 24.04 LTS, on a VDS, a dedicated server, or a colocated box. Commands assume a fresh install and a root login.

Step 0: Update the Base System

Before anything else, patch the system:

apt update && apt full-upgrade -y
systemctl reboot   # only if /var/run/reboot-required exists

Reconnect after the reboot if one was needed.

Step 1: Create a Non-Root User with sudo

Daily work as root is risky. A typo has no safety net, and every attacker targets the root username first.

adduser deploy
usermod -aG sudo deploy

Pick a strong password. You will still need it for sudo unless you configure passwordless sudo, which we do not recommend on internet-facing hosts.

Check that it works:

su - deploy
sudo whoami    # should print: root

Step 2: Set Up SSH Key Authentication

Do this on your local machine, not the server. Ed25519 keys are small, fast, and well supported.

ssh-keygen -t ed25519 -a 100 -C "you@laptop"
ssh-copy-id deploy@192.0.2.10

Replace 192.0.2.10 with your server's address. Without ssh-copy-id (for example on Windows), append the contents of your .pub file to /home/deploy/.ssh/authorized_keys on the server and fix permissions:

install -d -m 700 -o deploy -g deploy /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
chown deploy:deploy /home/deploy/.ssh/authorized_keys

Now open a new terminal and confirm the key login works:

ssh deploy@192.0.2.10

Keep your original root session open until the end of Step 3. If you lock yourself out, that session is your way back in.

Step 3: Disable Root Login and Password Authentication

Do not edit the main sshd_config if you can avoid it. Ubuntu reads drop-in files from /etc/ssh/sshd_config.d/, and for most options the first value found wins. Files are read in alphabetical order. Cloud images often ship a 50-cloud-init.conf that sets PasswordAuthentication yes. If your file sorts later, it will be ignored. Name yours so it sorts first:

cat > /etc/ssh/sshd_config.d/01-hardening.conf <<'EOF'
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
LoginGraceTime 30
X11Forwarding no
AllowUsers deploy
EOF

Validate the syntax and reload:

sshd -t && systemctl reload ssh

Verify the effective settings rather than trusting the file:

sshd -T | grep -Ei 'permitrootlogin|passwordauthentication|allowusers'

From a third terminal, test that ssh root@192.0.2.10 is refused and ssh deploy@192.0.2.10 still works. Only then close the original root session.

A Note on Changing the SSH Port

Moving SSH off port 22 reduces log noise but is not real security. On Ubuntu 24.04, SSH uses socket activation (ssh.socket), so a Port line in sshd_config alone may not take effect. If you change the port, test it carefully and open the new port in the firewall first. Many operators simply leave it on 22 and rely on keys plus fail2ban.

Step 4: Enable the UFW Firewall

UFW is a simple front end for nftables/iptables. The rule of thumb: deny incoming by default, then allow only what you serve. Allow SSH before enabling, or you will cut your own connection.

apt install -y ufw
ufw default deny incoming
ufw default allow outgoing
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
ufw status verbose

Only open the web ports if the server actually hosts a website. For admin access from a fixed office address, restrict SSH further:

ufw delete allow OpenSSH
ufw allow from 203.0.113.25 to any port 22 proto tcp

If IPv6 is in use, make sure IPV6=yes is set in /etc/default/ufw so the same rules apply to both stacks.

Two caveats: Docker publishes container ports by writing its own iptables rules, which can bypass UFW. Check with an external scan, not just ufw status. And UFW is a host firewall, not volumetric DDoS protection. Floods that saturate your uplink never reach the firewall in a useful way. That is a network-edge problem.

Step 5: Install and Configure fail2ban

fail2ban watches logs and temporarily bans IPs with repeated failures. With key-only SSH it is not your main defense, but it cuts log noise and stops brute-force bots from wasting resources.

apt install -y fail2ban

Never edit jail.conf. Create /etc/fail2ban/jail.local:

[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
backend  = systemd
ignoreip = 127.0.0.1/8 ::1 203.0.113.25

[sshd]
enabled = true

Setting backend = systemd matters on newer Ubuntu releases, where /var/log/auth.log may not exist unless rsyslog is installed. Add your own static admin IP to ignoreip so you do not ban yourself.

systemctl enable --now fail2ban
fail2ban-client status sshd

To unban an address:

fail2ban-client set sshd unbanip 203.0.113.25

Step 6: Turn On Automatic Security Updates

Most compromises exploit known bugs that already have patches. unattended-upgrades installs security updates automatically.

apt install -y unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades

This writes /etc/apt/apt.conf.d/20auto-upgrades:

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

Review /etc/apt/apt.conf.d/50unattended-upgrades. The default only applies the security pocket, which is the safe choice for production. Two options worth considering:

Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";

Kernel updates need a reboot to take effect. Enable automatic reboot only if the service can tolerate a short restart; otherwise schedule a maintenance window. Run a dry test:

unattended-upgrade --dry-run --debug

Optional Hardening Worth Doing

Common Mistakes and Fixes

Problem Cause Fix
Locked out after enabling UFW SSH not allowed first Use the provider console, run ufw allow OpenSSH
Password login still works Cloud-init drop-in overrides your setting Name your file 01-...conf, check with sshd -T
Permission denied (publickey) Wrong permissions on ~/.ssh chmod 700 ~/.ssh, chmod 600 authorized_keys, check ownership
fail2ban shows no sshd jail activity No auth.log Set backend = systemd
Banned your own IP No ignoreip Unban, then add your IP to ignoreip
Port change does nothing on 24.04 ssh.socket controls the listener Adjust the socket unit, or keep port 22

Verify the Result

Run a quick checklist before you call the server ready:

sshd -T | grep -Ei 'permitroot|passwordauth'
ufw status verbose
fail2ban-client status sshd
systemctl status unattended-upgrades --no-pager
ss -tulpn

From another machine, a port scan with nmap -Pn 192.0.2.10 should show only the ports you meant to open.

Where the Server Fits in a Bigger Security Picture

Host hardening covers the operating system. It does not cover attacks on the network path. If you run game servers, hosting workloads, or anything that attracts floods, you also need filtering upstream of the server. Nixcon Group LLC runs its own network (AS40368) with an İzmir, Türkiye data center and POPs in Frankfurt and Fremont, California. You can start with a virtual dedicated server and apply this guide on the first login. For traffic-level protection, see the DDoS protection and firewall options.

Finally, hardening is not a one-time task. Review journalctl -u ssh, check fail2ban stats occasionally, and reboot after kernel updates. A server you set up carefully on day one and patch automatically is far harder to compromise than one that was hardened "later".

Frequently asked questions

Should I disable root login on Ubuntu?

Yes. Create a sudo user, confirm key-based login works, then set PermitRootLogin no. This removes the most targeted username from brute-force attempts and gives you per-user audit trails through sudo.

Is UFW enough to protect my Ubuntu server?

UFW controls which ports are reachable on the host, which is an essential baseline. It does not stop volumetric DDoS floods that saturate your link, and Docker can bypass its rules. Combine it with key-only SSH, updates, and upstream filtering when needed.

Do I still need fail2ban if password login is disabled?

It is not strictly required, since attackers cannot guess a key. It still reduces log noise and load from bots, and it can protect other services such as web logins. Use backend = systemd on newer Ubuntu releases.

Is it safe to enable automatic reboots with unattended-upgrades?

It is safe if your service tolerates a brief restart. Kernel patches only apply after a reboot, so schedule one at a quiet hour, for example 04:00. For critical systems, skip auto reboot and use a planned maintenance window.

Deploy a VDS, then lock it down with this checklist.Learn more