You’re building a Linux server for production, and "security hardening" sounds like this nebulous, overwhelming task. Forget the abstract checklists. The real deal is about systematically closing off attack vectors, one by one, until the surface area is so small it’s practically invisible.
Let’s say you’ve just spun up a new Ubuntu 22.04 server, ready to host your critical application. Here’s how we’ll make it tougher than a blacksmith’s boot.
First, the absolute bedrock: updates. If you’re not patching regularly, you’re leaving the door wide open for known exploits.
sudo apt update && sudo apt upgrade -y
This command pulls down the latest package lists and installs all available upgrades, including security patches. It’s the digital equivalent of changing the locks on your house every morning.
Next, SSH access. This is the primary way attackers try to get in. We need to make it as difficult as possible.
Edit your SSH daemon configuration: sudo nano /etc/ssh/sshd_config.
Here’s what you change:
PermitRootLogin no: This is non-negotiable. Never allow direct root login over SSH.PasswordAuthentication no: Force the use of SSH keys.Port 2222: Change the default SSH port from 22. Pick a high, unused port (e.g., 2222, 49153). This isn’t foolproof security, but it stops 90% of automated bots scanning port 22.
After saving, restart the SSH service: sudo systemctl restart sshd.
Now, firewall rules. ufw (Uncomplicated Firewall) is your friend.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 2222/tcp # Allow SSH on our new port
sudo ufw allow http # If it's a web server (port 80)
sudo ufw allow https # If it's a web server (port 443)
sudo ufw enable
This locks down everything by default and only opens the specific ports you need. It’s like having a bouncer at the door, checking everyone’s ID.
User management: Don’t run everything as root. Create a dedicated user for your application and grant it only the necessary privileges.
sudo adduser myappuser
sudo usermod -aG sudo myappuser # Grant sudo access if needed
This principle of least privilege ensures that if your application user account is compromised, the damage is contained.
Unnecessary services. Every running service is a potential attack vector.
sudo systemctl list-units --type=service --state=running
If you see services you don’t need (e.g., apache2 if you’re using Nginx, or mysql if it’s a stateless app), disable and stop them:
sudo systemctl stop apache2
sudo systemctl disable apache2
This is like turning off the lights and locking up unused rooms in your house.
File permissions. Ensure your application files are owned by the correct user and group, and that permissions are as restrictive as possible.
sudo chown -R myappuser:myappuser /var/www/myapp
sudo chmod -R 750 /var/www/myapp
This prevents unauthorized users from reading, writing, or executing your application’s code.
Intrusion Detection System (IDS). Tools like fail2ban can automatically block IPs that show malicious activity.
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
fail2ban monitors log files (like SSH logs) for repeated failed login attempts and temporarily bans the offending IP addresses. It’s an automated security guard that spots suspicious behavior.
Kernel parameters. You can tune the kernel for security. Edit /etc/sysctl.conf:
net.ipv4.tcp_syncookies = 1 # Protect against SYN flood attacks
net.ipv4.conf.all.rp_filter = 1 # Enable reverse path filtering
net.ipv4.conf.default.rp_filter = 1 # Enable reverse path filtering
net.ipv4.conf.all.accept_source_route = 0 # Disable source routing
net.ipv6.conf.all.accept_source_route = 0 # Disable IPv6 source routing
kernel.randomize_va_space = 2 # Enable ASLR
Apply these changes with: sudo sysctl -p. This adjusts how the operating system handles network traffic and memory, making it harder for attackers to exploit vulnerabilities.
Finally, regular auditing. Set up log rotation and ensure logs are stored securely. Consider a centralized logging solution.
sudo apt install logrotate -y
This ensures that logs don’t fill up your disk and are managed properly. You can configure /etc/logrotate.conf and files in /etc/logrotate.d/ to specify how often logs should be rotated, compressed, and how many old logs to keep.
After all this, the next thing you’ll likely encounter is a permission denied error when your application tries to write to a directory it shouldn’t have access to.