5 Golden Rules for Linux Server Security (Practical Guide 2026)
A Linux server exposed to the internet is scanned by automated bots within minutes of receiving a public IP address. This is not an exaggeration — it is the daily reality of anyone managing online infrastructure.
The good news is that the vast majority of successful attacks do not exploit sophisticated vulnerabilities. They exploit configurations left at their default values. Changing those defaults, methodically and in the right order, is what separates an exposed server from a protected one.
These are the 5 rules we apply to every machine we manage, from personal VPS instances to production enterprise servers. This is not theory — it is the real checklist we follow on every new deployment.
Table of Contents
- SSH: Disable Root Login
- Firewall: Deny-All Policy with UFW
- Fail2ban: Anti-Brute Force Protection
- Automatic Security Updates
- Audit Trail with auditd
- FAQ
1. SSH: Disable Root Login
SSH is the protocol that allows remote access to a Linux server. It is an indispensable tool for every system administrator — and it is also the first door every attacker tries to force open.
The reason is straightforward: on any Linux server, the root user always exists and holds maximum privileges. If an attacker gains access as root, they have full control of the machine. Eliminating this possibility from the start is the most immediate and effective measure you can take.
The correct configuration involves three changes: preventing direct login as root, disabling password authentication (replacing it with cryptographic keys, which are far more secure), and optionally changing the default listening port to reduce noise in the logs.
# /etc/ssh/sshd_config
PermitRootLogin no # No direct access as root
PasswordAuthentication no # Cryptographic keys only, no passwords
PubkeyAuthentication yes
# Recommended but optional:
Port 2222 # Non-standard port, fewer automated scans
MaxAuthTries 3 # Maximum 3 attempts per connection
LoginGraceTime 20 # Disconnects if not authenticated within 20 seconds
After saving the file, restart the service:
sudo systemctl restart sshd
⚠️ Practical warning: before closing your current session, open a second SSH connection with the new non-root user to verify everything works. This step seems obvious, but many people skip it — and locking yourself out of your own server is an experience you only want to have once.
2. Firewall: Deny-All Policy with UFW
Think of a firewall as the intercom system of an apartment building: without it, anyone can knock on any door. With a properly configured firewall, only those with a valid reason can request entry — and only at the doors you have decided to open.
The most secure strategy is called default deny: all incoming traffic is blocked by default, and only what is strictly necessary is explicitly opened. This is the opposite of how many servers are configured, where everything is open and only the most obviously problematic ports are ever closed.
UFW (Uncomplicated Firewall) is the most accessible tool for applying this logic on Debian and Ubuntu distributions:
ufw default deny incoming # Block all incoming traffic
ufw default allow outgoing # Allow outgoing connections
ufw allow 2222/tcp # SSH (port changed in step 1)
ufw allow 80/tcp # HTTP
ufw allow 443/tcp # HTTPS
ufw enable
ufw status verbose # Verify the applied configuration
For services that should only be accessible from specific IP addresses — such as a database that should never be reachable from the outside — access can be restricted further:
# Example: PostgreSQL accessible only from an authorised IP
ufw allow from 203.0.113.10 to any port 5432
This detail — restricting databases to trusted IPs — is one of the most overlooked aspects in the configurations we review. Databases are frequently publicly accessible without anyone ever having noticed.
3. Fail2ban: Anti-Brute Force Protection
Even with SSH properly configured, bots will continue attempting access. They do so automatically, continuously, across millions of servers in parallel. Fail2ban stops them in their tracks: it monitors system logs and automatically blocks IP addresses that show suspicious behaviour — such as a high number of failed login attempts in a short period of time.
In practical terms: after a configurable number of failed attempts, the IP is added to a temporary blacklist via the firewall. The bot does not even receive an error message — it is simply ignored.
# Installation
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Configuration should be done in a separate file — never modify the main configuration file, which gets overwritten with every update:
sudo nano /etc/fail2ban/jail.local
[DEFAULT]
bantime = 1h # IP remains blocked for 1 hour
findtime = 10m # Observation window: 10 minutes
maxretry = 5 # After 5 failed attempts, the ban triggers
ignoreip = 127.0.0.1/8 ::1
[sshd]
enabled = true
port = 2222 # The SSH port you configured
maxretry = 3 # Stricter on SSH: 3 attempts
bantime = 24h # Longer ban for SSH attempts
To verify everything is working and check active bans:
sudo fail2ban-client status sshd
4. Automatic Security Updates
Software vulnerabilities are not a remote possibility: they are discovered continuously, published in CVE databases, and actively exploited — often within hours of public disclosure. An unpatched system silently accumulates risk over time.
The solution is not staying up at night applying patches manually — it is automating security patches specifically, which are by definition the urgent ones, while leaving everything else to planned manual maintenance windows.
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure -plow unattended-upgrades
The wizard that opens simply asks whether you want to enable automatic security updates. The answer is yes. For those who want to dig into the configuration — email notifications, automatic reboot handling, exclusion of specific packages — the configuration file is located at /etc/apt/apt.conf.d/50unattended-upgrades and is extensively documented with inline comments.
One step that is always worth taking: test the configuration before letting it run autonomously.
sudo unattended-upgrade --dry-run --debug
The output shows exactly what would be updated without applying anything. It takes two minutes and saves you from unpleasant surprises.
5. Audit Trail with auditd
The first four rules reduce the attack surface. This one serves a different purpose: knowing what happened, when it happened, and who did it — both in the event of an incident and for regulatory compliance (GDPR, ISO 27001, PCI-DSS).
auditd is the auditing subsystem built into the Linux kernel. It records at the operating system level: access to critical files, configuration changes, commands executed with elevated privileges, and privilege escalation attempts. It is not an application log — it is a trace that operates at a deeper level, difficult to bypass or tamper with from within the system.
sudo apt install auditd -y
sudo systemctl enable auditd
sudo systemctl start auditd
Auditing rules define what to monitor. A minimal but meaningful set for any server:
# Authentication files: any change is an event worth examining
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k sudoers
# SSH configuration: unauthorised changes here are a red flag
-w /etc/ssh/sshd_config -p wa -k sshd_config
# Every command executed as root is recorded
-a always,exit -F arch=b64 -F euid=0 -S execve -k root_commands
To review the logs in a readable format:
sudo ausearch -k identity --start today # Changes to identity files today
sudo aureport --auth # Access summary
sudo aureport --summary # General activity report
Having these logs configured is not just good technical practice — in many contexts it is a regulatory requirement. And when something goes wrong, having a precise record of events dramatically reduces response and analysis time.
Summary: Hardening Checklist
| # | Rule | Priority | Complexity |
|---|---|---|---|
| 1 | Disable SSH root login + cryptographic keys | 🔴 Critical | Low |
| 2 | UFW firewall with deny-all policy | 🔴 Critical | Low |
| 3 | Fail2ban anti-brute force | 🟠 High | Low |
| 4 | Automatic security updates | 🟠 High | Low |
| 5 | Audit trail with auditd | 🟡 Medium | Medium |
These 5 rules address the most common attack vectors and represent the mandatory starting point for any server exposed to the internet. For more advanced hardening — regulated environments, critical infrastructure, or servers handling sensitive data — the path continues with CIS Benchmarks analysis, centralised secrets management, SELinux or AppArmor, IDS/IPS solutions, and SIEM platforms for event correlation.
FAQ
How do I know if my server has been compromised?
The most common signs are: sudden slowdowns with no apparent cause, anomalous network traffic, unknown users or processes active on the system, and unusual entries in authentication logs. In many cases a compromise remains silent for weeks — which is precisely why the audit trail in step 5 is so important: it allows you to reconstruct what happened even after the fact. If you have doubts about a specific server, the most prudent course of action is to request a forensic analysis before making any changes.
Does changing the SSH port actually make the server more secure?
Changing the port does not add real security — a determined attacker will perform a full port scan in seconds. The practical benefit is different: it dramatically reduces log noise by eliminating the thousands of automated attempts directed at port 22 every day. This makes it easier to spot genuinely suspicious activity. The real security of SSH comes from public key authentication, not the port number.
Is Fail2ban enough against brute force attacks?
Fail2ban is highly effective against automated scanners and low-intensity distributed attacks. For truly robust protection, however, the starting point must be public key-only authentication: if passwords are disabled, a brute force attack against credentials becomes simply irrelevant. Fail2ban and key authentication complement each other — neither replaces the other.
How often should I update a production server?
Security patches for critical vulnerabilities (those rated with a high CVSS score) should be applied within 24 to 72 hours of publication. For everything else, a weekly or biweekly maintenance window is a reasonable practice. The unattended-upgrades configuration described in this guide handles urgent patches automatically, leaving you in control of more significant system updates.
Is UFW suitable for all servers, or are there cases where it falls short?
UFW is more than adequate for the vast majority of servers: VPS instances, web servers, development environments, and small to medium infrastructure. For more complex scenarios — multi-interface networks, NAT, traffic shaping, or connection state-dependent rules — working directly with iptables or nftables is necessary. The latter offers a more modern syntax and better performance on recent kernel versions.
Are these measures enough for a server handling sensitive data?
They are a solid starting point, not a finishing line. A server that processes personal data, financial information, or operates in a regulated industry requires a more structured approach: regulatory compliance analysis, secure secrets and credentials management, regularly tested encrypted backups, active event monitoring, and periodic penetration testing. The gap between “well configured” and “secure for the specific context” is often significant.
Managing a server and not sure where the weak points are? We conduct infrastructure audits: we analyse the current configuration, identify vulnerabilities, and propose a concrete, prioritised remediation plan. Contact us
