LinuxIntermediate 15 min Lesson 23 of 24

Server Security

The measures that actually prevent compromise: SSH hardening, updates, least privilege, fail2ban and knowing what is exposed.

Linux · Lesson 23 of 24
0/24 done(0%)

What is it? #

Server security is mostly a small number of basic measures applied consistently, not sophisticated defences.

Most compromises come from a short list: exposed services with weak credentials, unpatched software with known vulnerabilities, over-privileged processes and leaked secrets.

The measures that address those are unglamorous: key-only SSH, automatic security updates, default-deny firewall, unprivileged service accounts and not storing secrets in code.

Defence in depth is the organising idea. Each layer assumes the one in front may fail.

Think of it like this #

Securing a building. Most break-ins are through an unlocked door or a window left open, not by defeating the alarm system.

Locking the doors, fixing the broken window and not leaving the key under the mat prevents far more than an expensive alarm does.

Simple example #

A freshly created server, publicly reachable. Within minutes automated scanners will find it. The task is to make every obvious path closed before that matters.

Code #

BASH
# 1. SSH: keys only, no root, limited users
sudo tee /etc/ssh/sshd_config.d/hardening.conf > /dev/null <<'CONF'
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
AllowUsers deploy ravi
ClientAliveInterval 300
ClientAliveCountMax 2
CONF
sudo sshd -t && sudo systemctl reload sshd     # test before reloading

# 2. Firewall: default deny
sudo ufw allow OpenSSH
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 80,443/tcp
sudo ufw enable

# 3. Automatic security updates
sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

# 4. fail2ban: temporarily block repeated failures
sudo apt install fail2ban
sudo tee /etc/fail2ban/jail.local > /dev/null <<'CONF'
[sshd]
enabled  = true
maxretry = 5
findtime = 10m
bantime  = 1h
CONF
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
BASH
# 5. Know what is exposed — audit regularly
sudo ss -tulpn | grep -v 127.0.0.1        # anything listening publicly
ps aux | awk '<span class="katex-error" title="ParseError: KaTeX parse error: Expected &#x27;}&#x27;, got &#x27;EOF&#x27; at end of input: …= &quot;root&quot; {print" style="color:#cc0000">1 == &quot;root&quot; {print</span>11}' | sort -u   # what runs as root
sudo find / -perm -4000 -type f 2>/dev/null         # setuid binaries
sudo lastb | head -20                                # failed logins
sudo grep "Accepted" /var/log/auth.log | tail -20    # successful logins
TEXT
6. The checklist that covers most of it

SSH          key-only, no root login, non-default port optional, fail2ban
updates      automatic security patches, scheduled reboots for kernel updates
firewall     default deny, only 22/80/443 open, databases bound to localhost
accounts     one unprivileged user per service, no shared logins
secrets      environment files at 600, never in git, rotated on staff changes
TLS          HTTPS everywhere, automated renewal, expiry monitoring
backups      automated, offsite, and restore-tested
logging      auth logs retained, alerts on unusual login patterns
application  input validation, parameterised queries, dependency scanning
TEXT
7. What actually gets exploited, in rough order of frequency

1. leaked or weak credentials              → keys, MFA, secret rotation
2. unpatched known vulnerabilities         → automatic updates
3. exposed services (databases, admin UIs) → firewall, bind to localhost
4. application flaws (injection, upload)   → validation, least privilege
5. supply chain (compromised dependency)   → lockfiles, scanning

How it works #

Disabling password authentication removes the entire category of brute-force login attacks. Automated scanners try thousands of password combinations against every reachable SSH port; with keys only, all of them fail immediately.

Testing the SSH configuration with sshd -t before reloading is essential, and keeping an existing session open while you verify a new one is the standard precaution against locking yourself out.

Default-deny firewalling means a service accidentally started on a public port is not reachable. It converts a potential incident into a non-event.

fail2ban watches logs and temporarily blocks addresses with repeated failures. With key-only SSH it matters less, but it also protects application login endpoints and reduces log noise.

The audit commands answer the questions that matter: what is listening publicly, what runs as root, and who has been logging in. Running them periodically catches drift — a service someone exposed for debugging and forgot.

Setuid binaries run with the owner's privileges regardless of who executes them, so an unexpected one is worth investigating.

The exploitation list is ordered by what actually happens. Credentials and unpatched software dominate, which is why the boring measures matter more than advanced ones.

Real-world use #

A new public server receives automated scans within minutes and login attempts within the hour. That is normal background noise, and the defences above make it harmless.

Secrets in git are one of the most common real incidents. Scanners monitor public repositories continuously, and a committed cloud key is typically abused within minutes. Removing it from the latest commit is not enough — it must be rotated.

Kernel updates need a reboot to take effect. Automatic patching without a reboot policy leaves you patched on disk and vulnerable in memory.

Backups are a security control, not just an operational one. Ransomware makes restore capability the difference between an incident and a catastrophe, and a backup that has never been restored is an assumption rather than a plan.

Containers change the details: the host still needs this hardening, and images need their own scanning, minimal base images and non-root users.

Common mistakes #

  • Leaving password authentication enabled on SSH.
  • Committing secrets to git and only deleting them from the latest commit rather than rotating.
  • Applying kernel updates but never rebooting.
  • Running applications as root because it was convenient during setup.
  • Backups that exist but have never been restore-tested.

Practice #

On a test server, apply the full checklist: key-only SSH with no root login, default-deny firewall, automatic security updates and fail2ban. Then run the audit commands and write down every service listening publicly and every process running as root, with a justification for each.

Quick quiz

  1. 1. What is the single most effective SSH hardening step?

  2. 2. What is the most common cause of server compromise?

  3. 3. Why is deleting a committed secret from the latest commit insufficient?

  4. 4. Why does a kernel update require a reboot?

  5. 5. What does fail2ban do?

Summary

  • Most compromises come from credentials, unpatched software and exposed services.
  • Key-only SSH, default-deny firewall and automatic updates cover most of the risk.
  • Run every service as an unprivileged user and keep secrets out of git.
  • Audit regularly: what is listening publicly and what runs as root.
  • Backups are a security control, and must be restore-tested.