Attack surfaces keep growing. The servers I worked with last year had fewer exposed services, simpler authentication paths, and smaller software stacks than what infrastructure teams manage today. Threat actors automate reconnaissance at scale now, scanning entire IPv4 ranges in hours and exploiting unpatched CVEs within days of disclosure.
You need a repeatable hardening process. These nine steps form the baseline security posture I recommend for any production Linux server in 2026, whether you're running a single VPS or a fleet of application hosts.
1. Lock down SSH immediately
SSH is the front door. Disable password authentication entirely and rely only on key pairs.
Edit /etc/ssh/sshd_config and enforce these lines:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
Port 2289
AllowUsers deploy admin
Changing the default port from 22 to something higher cuts automated bot scans by more than half in my experience. The AllowUsers directive whitelists specific accounts, so even if an attacker guesses a valid username, SSH won't honor the attempt unless that user is listed.
Restart SSH after changes:
sudo systemctl restart sshd
Test your new config from a second terminal session before closing your current connection. If you lock yourself out, you'll need console access through your hosting control panel.
2. Configure a host-based firewall
Every server should run a firewall that defaults to DENY and explicitly permits only the ports you need. UFW on Ubuntu and Debian makes this simple.
Install and enable UFW:
sudo apt install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 2289/tcp comment 'SSH'
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
sudo ufw enable
For CentOS, Rocky, or AlmaLinux, use firewalld:
sudo firewall-cmd --set-default-zone=drop
sudo firewall-cmd --zone=public --add-port=2289/tcp --permanent
sudo firewall-cmd --zone=public --add-service=http --permanent
sudo firewall-cmd --zone=public --add-service=https --permanent
sudo firewall-cmd --reload
Audit open ports quarterly. Every listening service is a potential entry point.
3. Enable automatic security updates
Manual patching doesn't scale. Automate updates for security packages at minimum, and schedule full system updates during maintenance windows.
On Debian and Ubuntu, install unattended-upgrades:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Edit /etc/apt/apt.conf.d/50unattended-upgrades to enable automatic reboots if needed:
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";
For RHEL-family distros, enable dnf-automatic:
sudo dnf install dnf-automatic
sudo systemctl enable --now dnf-automatic.timer
Configure /etc/dnf/automatic.conf to apply security updates:
[commands]
upgrade_type = security
apply_updates = yes
Log all updates and monitor for failures. A botched kernel update that breaks boot is better caught early.
4. Deploy fail2ban for brute-force protection
Even with SSH keys, you'll see login attempts. Fail2ban watches log files and temporarily bans IPs after repeated failures.
Install fail2ban:
sudo apt install fail2ban # Debian/Ubuntu
sudo dnf install fail2ban # RHEL/Rocky/Alma
Create /etc/fail2ban/jail.local:
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
[sshd]
enabled = true
port = 2289
logpath = /var/log/auth.log
Restart and verify:
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
You can add jails for HTTP services, mail servers, or any daemon that logs authentication events. Check /var/log/fail2ban.log to confirm it's catching attacks.
5. Harden kernel parameters with sysctl
The Linux kernel exposes hundreds of tunables. A few settings significantly improve security with zero performance cost.
Edit /etc/sysctl.conf or create /etc/sysctl.d/99-security.conf:
# Disable IP forwarding
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0
# Enable SYN cookies
net.ipv4.tcp_syncookies = 1
# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
# Ignore source-routed packets
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
# Log martian packets
net.ipv4.conf.all.log_martians = 1
# Disable ICMP echo for the host
net.ipv4.icmp_echo_ignore_all = 0
# Protect against time-wait assassination
net.ipv4.tcp_rfc1337 = 1
Apply immediately:
sudo sysctl -p
These controls close off classes of spoofing and redirection attacks that older servers were vulnerable to by default.
6. Run a host-based intrusion detection system
Firewalls block traffic, but HIDS monitors file integrity, processes, and rootkit signatures. AIDE and OSSEC both work well.
Install AIDE:
sudo apt install aide
sudo aideinit
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
Schedule daily checks via cron:
0 2 * * * /usr/bin/aide --check | mail -s "AIDE Report" [email protected]
AIDE will alert you when critical binaries, config files, or libraries change unexpectedly. That's your early warning for compromised packages or backdoors.
For deeper inspection, deploy OSSEC with centralized log aggregation if you manage multiple hosts. OSSEC correlates events across your fleet and flags suspicious patterns like privilege escalation attempts or unusual network connections.
7. Enforce least privilege with sudo policies
Never log in as root. Create individual user accounts and grant elevated permissions only when needed.
Add a user and allow specific commands:
sudo adduser deploy
sudo usermod -aG sudo deploy # Debian/Ubuntu
sudo usermod -aG wheel deploy # RHEL/Rocky/Alma
For granular control, edit /etc/sudoers with visudo:
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl reload php8.2-fpm
This lets the deploy user restart web services without a password prompt, but nothing else. Audit sudo logs in /var/log/auth.log or /var/log/secure regularly.
What about container and orchestration security?
If you run Docker or Kubernetes, treat the host OS as a critical boundary. Harden it with the steps above, then layer container-specific controls on top.
For Docker:
- Run the daemon in rootless mode where possible.
- Use
--read-onlyand--tmpfsfor ephemeral containers. - Scan images with Trivy or Clair before deployment.
- Limit container capabilities with
--cap-drop=ALLand add back only what's required.
Kubernetes demands Pod Security Standards, Network Policies, and RBAC audits. The host hardening checklist still applies to your worker nodes.
8. Centralize and monitor logs
Logs are forensic gold. Ship them off the host so an attacker can't cover their tracks by deleting local files.
Install rsyslog or syslog-ng and forward to a remote collector:
# /etc/rsyslog.d/50-remote.conf
*.* @@log-collector.example.com:514
Restart rsyslog:
sudo systemctl restart rsyslog
For smaller setups, configure logrotate to compress and retain logs for at least 90 days. Check /etc/logrotate.d/ for per-service configs.
Integrate with a SIEM or log analysis platform if budget allows. Real-time alerting on failed auth attempts, privilege escalations, or outbound connections to known malicious IPs gives you response time measured in minutes, not days.
9. Implement a backup and disaster recovery plan
Security controls reduce risk but don't eliminate it. A compromise or hardware failure will happen eventually.
Automate daily backups of:
- Application data and databases
- Configuration files in
/etc - Home directories for service accounts
- SSL/TLS certificates and private keys
Store backups off-site, encrypted, and test restoration quarterly. A backup you've never restored is just wishful thinking.
For VPS environments, snapshot the entire disk weekly. Most hosting providers offer API-driven snapshot automation.
# Example with DigitalOcean CLI
doctl compute droplet snapshot create <droplet-id> --snapshot-name "weekly-backup-$(date +%F)"
Document your restore process. Under pressure, you won't remember every step.
Start with SSH and the firewall
You don't need to implement all nine steps in one sitting. Harden SSH and enable your firewall first—those two alone block the majority of opportunistic attacks. Then add automated patching, fail2ban, and intrusion detection over the following week.
Document every config change in version control or a runbook. When you build your next server, you'll have a tested playbook to follow. Security is a process, not a one-time checklist.
