Skip to main content
Techlogia — AI and Web Development Berlin

Learn server hardening – step by step

A freshly set-up server is an open invitation. Hardening means systematically shrinking the attack surface. Here you go through the most important steps – and run them on a real, own VM without being able to break anything real.

Updates and minimal services

The first step is always: keep the system up to date and switch off everything you don't need. Every running service is a potential door. Less is literally safer here.

Firewall with UFW

With ufw you allow only the ports that are truly needed (e.g. SSH and HTTPS) and block the rest. A correctly configured firewall is one of the most effective single measures.

Securing SSH & fail2ban

Password login off, root login off, plus fail2ban against brute force: this practically closes the most common attack path – guessing SSH credentials.

Attack surface first, tools second

Hardening is not about installing as many tools as possible but about leaving as little reachable as possible. The first move is ss -tlnp: what is listening at all, and does it need to be? A service used only locally belongs bound to 127.0.0.1 – then it is protected by its own configuration, not by a firewall rule.

Automatic security updates

Most successful attacks exploit holes that have had a patch for weeks. unattended-upgrades installs security updates without intervention. The second half matters: checking that it actually runs. An enabled but never-executed service looks exactly like a working one in the configuration.

Fewer privileges beat more rules

Every service should run under its own user and reach only what it needs. A web server running as root turns an application flaw into a full system takeover. Systemd offers switches such as ProtectSystem=strict and NoNewPrivileges=true – more effective than any extra firewall rule.

Logs are part of hardening

Hardening without logs is flying blind. journalctl -u ssh --since today shows login attempts, lastb the failed ones. If you do not know how often someone knocks, you cannot judge whether a measure works. That is why every change deserves a measurement before and after, not just a tick.

What usually goes wrong

Hardening rarely fails for lack of knowledge and mostly for lack of verification. A firewall rule is set but never tested from outside. A service is switched off and comes back on the next reboot. unattended-upgrades is installed and never runs because another package operation holds the lock. All three share one thing: the configuration looks right, and nobody checked whether it works.

The order in which you harden

Hardening has an order, and it is not arbitrary. Access first: set up keys and test them while the old route is still open. Then the attack surface: switch off what is not needed and bind locally what need not be reachable from outside. The firewall comes next, securing what is already narrow. Only at the end come tools such as intrusion detection or automatic ban lists. Starting from the other end installs guards over an open door.

Commands to try

See what is reachable from outside

$ sudo ss -tlnp$ sudo ufw status verbose$ systemctl list-units --type=service --state=running

ss -tlnp shows every listening port with its process. Anything bound to 0.0.0.0 that is not needed is the first candidate for switching off.

Firewall in the right order

$ sudo ufw default deny incoming$ sudo ufw default allow outgoing$ sudo ufw allow OpenSSH$ sudo ufw enable

The SSH rule comes BEFORE switching on. Typing ufw enable first locks you out of a remote session – the classic mistake, and it happens exactly once.

Automate updates and prove they work

$ sudo apt install unattended-upgrades$ sudo dpkg-reconfigure -plow unattended-upgrades$ sudo unattended-upgrade --dry-run -d | tail -20

The third line is the proof: it shows what the service would do. Without that rehearsal you only know it is switched on – not that it has any effect.

Make login attempts visible

$ sudo journalctl -u ssh --since today | grep -c 'Failed password'$ sudo lastb | head$ sudo journalctl -u ssh --since today | grep 'Accepted' | tail -5

The first number is your baseline. After disabling password login it must drop to zero – that is the proof of effect, not the config line.

Common error messages

Command may disrupt existing ssh connections. Proceed with operation (y|n)?
Cause: ufw enable warns because the default rule drops incoming connections – including the session you are typing in.
Fix: Cancel, set sudo ufw allow OpenSSH, then enable again. And keep a second session open.
Failed to start ssh.service: Unit ssh.service is masked.
Cause: The service was not merely stopped but masked – a state neither start nor enable can leave.
Fix: sudo systemctl unmask ssh, then enable --now.
0 upgraded, 0 newly installed — with a known open CVE
Cause: The package lists are stale. apt upgrade compares against what it last fetched, not against the server.
Fix: Always run sudo apt update first. That is why the two commands appear as a pair in every guide.
ufw: ERROR: Could not load logging rules
Cause: The kernel module for logging is missing – on some cloud kernels it is not built in.
Fix: Turn logging off with sudo ufw logging off and read along via journalctl -k instead. The rules themselves apply regardless.
Job for ssh.service failed. See "systemctl status ssh.service"
Cause: Usually a syntax error in /etc/ssh/sshd_config — a directive misspelled or set twice.
Fix: Run sudo sshd -t before every restart; it names file and line. Then reload rather than restart, so existing sessions stay open.

In five steps

  1. 01List what is listening with sudo ss -tlnp and be able to justify every entry.
  2. 02Set the firewall – allow SSH BEFORE you type ufw enable.
  3. 03Test key login, then switch off password and root login in sshd_config.
  4. 04Set up unattended-upgrades and prove it works with --dry-run.
  5. 05Verify from outside: run ss -tlnp again and try a connection to a closed port – it must fail.

What you practise

Updates & minimale DiensteUFW-FirewallSSH-Härtung & fail2ban

Have a project?

Let's bring your idea to life together. We're happy to advise you with no obligation.

Get in Touch

How do you like this page?