Hardening Linux Servers: A Practical Security Checklist
Deploying a Linux server to the public internet means it will be scanned and attacked by automated bots within minutes. Securing your infrastructure is not a one-time task, but following a strict baseline hardening checklist mitigates the vast majority of automated attacks.
Here is a practical guide to securing a production Linux server.
1. Secure SSH Access
SSH is the front door to your server. Securing it is priority number one.
Edit /etc/ssh/sshd_config:
Disable Password Authentication: Force the use of cryptographic SSH keys.
PasswordAuthentication no
Disable Root Login: Never log in directly as root. Log in as a standard user and use sudo or su.
PermitRootLogin no
Change the Default Port (Optional): While security by obscurity isn’t true security, changing the port from 22 to something like 2222 drastically reduces the noise from automated script kiddies in your auth logs.
Port 2222
Restart the SSH service after making changes: sudo systemctl restart sshd.
2. Implement Fail2Ban
Even with keys only, bots will hammer your SSH port. fail2ban monitors log files for repeated failed authentication attempts and dynamically adds iptables or nftables rules to block the attacker’s IP address.
Install it:
sudo apt install fail2ban
It requires almost no configuration out of the box to protect SSH, but it can be easily extended to protect Nginx, Apache, and Postfix.
3. Configure a Strict Firewall
Adopt a “default deny” posture. Block everything, and only explicitly allow the ports you need.
Using ufw (Uncomplicated Firewall) on Ubuntu:
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH (use your custom port if changed)
sudo ufw allow 22/tcp
# Allow HTTP/HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Enable the firewall
sudo ufw enable
4. Principle of Least Privilege
Ensure users and applications only have the permissions they absolutely need.
- Use sudo diligently: Do not use
rootfor daily tasks. Give users specificsudopermissions via/etc/sudoers.d/rather than blanket access. - Service Accounts: Do not run web servers or databases as root. Nginx should run as
www-data, PostgreSQL aspostgres. If a service is compromised, the attacker only gains the privileges of that specific user.
5. Automated Security Updates
Unpatched software is the primary vector for system compromises. Configure your system to install security updates automatically.
On Debian/Ubuntu, configure unattended-upgrades:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Ensure that it is configured to only install security updates automatically, to prevent unexpected feature changes from breaking your applications.
6. Kernel Hardening and SELinux/AppArmor
AppArmor / SELinux
Do not disable SELinux or AppArmor. These Mandatory Access Control (MAC) systems provide a massive layer of security. They confine applications; even if an attacker finds an exploit in Nginx, SELinux prevents Nginx from reading files in /etc or executing a shell.
Kernel Parameters (sysctl)
Harden the network stack against common attacks like SYN floods and spoofing by adding these to /etc/sysctl.d/99-security.conf:
# Ignore ICMP broadcast requests (prevent smurf attacks)
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Enable TCP SYN Cookie Protection
net.ipv4.tcp_syncookies = 1
# Disable IP source routing
net.ipv4.conf.all.accept_source_route = 0
# Protect against IP spoofing
net.ipv4.conf.all.rp_filter = 1
Apply with sudo sysctl -p.
Conclusion
Security is an ongoing process of risk management. By enforcing key-based authentication, running a strict firewall, and isolating services, you eliminate the low-hanging fruit and make your server a significantly harder target for adversaries.