Security

Server Hardening Checklist: 30 Steps to a Bulletproof Ubuntu Server

May 18, 2026

Back to Blog
A modern alternative to cPanel, Plesk and CyberPanel — isolated, secure, AI-assisted.
Start free

Why Server Hardening Is Non-Negotiable

A fresh Ubuntu server installation is designed for ease of use, not security. Default configurations prioritize compatibility over protection, leaving numerous attack surfaces exposed. Password authentication is enabled, unnecessary services run in the background, and kernel parameters are set to permissive defaults. Every one of these defaults is an invitation to attackers.

Server hardening is the systematic process of reducing the attack surface by eliminating unnecessary services, tightening configurations, and implementing multiple layers of defense. Think of it as locking not just the front door, but every window, vent, and crawlspace in your building.

Sobering Reality: The average time for a new, unhardened server to be compromised after going online is less than 24 hours. Automated scanners constantly probe every IP address on the internet, and botnets can attempt thousands of SSH login combinations per minute against default configurations.

This checklist covers 30 essential hardening steps organized by category. Not every step applies to every server, but every step should be consciously evaluated. Even implementing half of these measures puts your server leagues ahead of most.

SSH Hardening (Steps 1-8)

SSH is the most critical service on your server because it provides direct administrative access. If an attacker compromises SSH, they own your server. These first eight steps focus entirely on hardening this gateway.

1
Change the Default SSH Port

While security through obscurity is not a complete strategy, changing the SSH port from 22 to a non-standard port dramatically reduces automated brute force attempts. Most botnets only scan port 22.

# /etc/ssh/sshd_config Port 2847 AddressFamily inet
2
Disable Root Login

Never allow direct root SSH access. Create a regular user with sudo privileges, then disable root login entirely. This forces attackers to guess both a username and password.

PermitRootLogin no
3
Use Key-Based Authentication Only

SSH keys are exponentially stronger than passwords. A 4096-bit RSA key or an Ed25519 key is practically impossible to brute force. Disable password authentication entirely after setting up key access.

# Generate a strong key (on your local machine) $ ssh-keygen -t ed25519 -C "[email protected]" $ ssh-copy-id -p 2847 admin@your-server # Then in sshd_config: PasswordAuthentication no PubkeyAuthentication yes ChallengeResponseAuthentication no
4
Restrict SSH to Specific Users

Use the AllowUsers or AllowGroups directive to limit which accounts can SSH in. Even if an attacker compromises a service account, they cannot use it for SSH access.

AllowUsers admin deployer AllowGroups sshusers
5
Set Login Grace Time and Max Attempts

Limit how long a connection can stay open during authentication and how many attempts are allowed per connection.

LoginGraceTime 30 MaxAuthTries 3 MaxSessions 3 ClientAliveInterval 300 ClientAliveCountMax 2
6
Disable Empty Passwords and X11 Forwarding

Ensure no account with an empty password can log in, and disable X11 forwarding if you do not need a graphical display tunnel.

PermitEmptyPasswords no X11Forwarding no AllowTcpForwarding no AllowAgentForwarding no
7
Use Strong Ciphers and Key Exchange Algorithms

Disable weak and deprecated algorithms. Only allow modern, battle-tested ciphers.

KexAlgorithms [email protected],diffie-hellman-group16-sha512 Ciphers [email protected],[email protected] MACs [email protected],[email protected]
8
Enable Two-Factor Authentication for SSH

Add Google Authenticator (TOTP) as a second factor for SSH. Even if a key is stolen, the attacker still needs the time-based code.

$ apt install libpam-google-authenticator $ google-authenticator # /etc/pam.d/sshd — add: auth required pam_google_authenticator.so # /etc/ssh/sshd_config AuthenticationMethods publickey,keyboard-interactive

Firewall Configuration (Steps 9-12)

9
Configure nftables (or UFW) Firewall

Only allow traffic on ports that your services actually use. Block everything else by default with a deny-all incoming policy.

# UFW quick setup $ ufw default deny incoming $ ufw default allow outgoing $ ufw allow 2847/tcp comment 'SSH' $ ufw allow 80/tcp comment 'HTTP' $ ufw allow 443/tcp comment 'HTTPS' $ ufw enable
10
Rate Limit SSH Connections at the Firewall Level

Even before Fail2ban kicks in, limit SSH connection attempts at the firewall level.

$ ufw limit 2847/tcp comment 'SSH rate limit'
11
Block ICMP Timestamps and Redirect Packets

ICMP timestamps can leak server uptime information, and ICMP redirects can be used in man-in-the-middle attacks.

12
Enable SYN Flood Protection

SYN cookies protect against SYN flood attacks without consuming server resources for half-open connections.

# /etc/sysctl.conf net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syn_retries = 3 net.ipv4.tcp_synack_retries = 2

Kernel and System Hardening (Steps 13-18)

13
Harden Kernel Parameters via sysctl

The kernel has many tunable parameters that affect security. Set these in /etc/sysctl.conf or /etc/sysctl.d/99-hardening.conf.

# Disable IP forwarding (unless this is a router) net.ipv4.ip_forward = 0 net.ipv6.conf.all.forwarding = 0 # Ignore ICMP redirects net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.default.accept_redirects = 0 net.ipv6.conf.all.accept_redirects = 0 # Ignore source-routed packets net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.default.accept_source_route = 0 # Enable IP spoofing protection net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.default.rp_filter = 1 # Log suspicious packets net.ipv4.conf.all.log_martians = 1 # Disable IPv6 if not needed net.ipv6.conf.all.disable_ipv6 = 1 # Apply changes $ sysctl -p
14
Secure Shared Memory

By default, /dev/shm allows programs to execute code from shared memory, which is a common exploitation technique.

# /etc/fstab — add: tmpfs /dev/shm tmpfs defaults,noexec,nosuid,nodev 0 0
15
Mount /tmp with noexec

Prevent execution of binaries from /tmp. Many exploits download payloads to /tmp and execute them there. This simple mount option neutralizes that attack vector.

16
Enable Automatic Security Updates

Unpatched vulnerabilities are the number one cause of server compromises. Configure unattended-upgrades to install security patches automatically.

$ apt install unattended-upgrades apt-listchanges $ dpkg-reconfigure -plow unattended-upgrades # Verify configuration $ cat /etc/apt/apt.conf.d/20auto-upgrades APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Unattended-Upgrade "1";
17
Disable Unnecessary Services

Every running service is a potential attack surface. List all active services and disable everything you do not use.

# List all running services $ systemctl list-units --type=service --state=running # Disable services you don't need $ systemctl disable --now cups.service $ systemctl disable --now avahi-daemon.service $ systemctl disable --now bluetooth.service
18
Set GRUB Bootloader Password

Protect the bootloader with a password to prevent an attacker with physical or console access from modifying boot parameters (e.g., booting into single-user mode).

Intrusion Detection and Monitoring (Steps 19-24)

19
Install and Configure Fail2ban

Fail2ban monitors log files and automatically bans IPs that show malicious patterns like repeated failed login attempts.

$ apt install fail2ban # /etc/fail2ban/jail.local [DEFAULT] bantime = 3600 findtime = 600 maxretry = 5 banaction = nftables-multiport [sshd] enabled = true port = 2847 maxretry = 3 bantime = 86400
20
Install File Integrity Monitoring (AIDE)

AIDE (Advanced Intrusion Detection Environment) takes a snapshot of your filesystem and alerts you when files are modified. Essential for detecting rootkits and unauthorized changes.

$ apt install aide $ aideinit $ cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db # Run a check $ aide --check # Schedule daily checks via cron 0 4 * * * /usr/bin/aide --check | mail -s "AIDE Report" [email protected]
21
Install Rootkit Detection (rkhunter)

Rkhunter scans for known rootkits, backdoors, and local exploits. Run it regularly and after any suspicious activity.

$ apt install rkhunter $ rkhunter --update $ rkhunter --propupd $ rkhunter --check --skip-keypress
22
Configure Centralized Logging

Ensure all logs go to a central location. If an attacker compromises the server, they may try to delete local logs. Remote logging preserves the evidence.

23
Enable Audit Logging (auditd)

The Linux audit system tracks security-relevant events like file access, system calls, and user commands. This is essential for forensic analysis.

$ apt install auditd audispd-plugins # Watch sensitive files $ auditctl -w /etc/passwd -p wa -k passwd_changes $ auditctl -w /etc/shadow -p wa -k shadow_changes $ auditctl -w /etc/ssh/sshd_config -p wa -k sshd_config # Search audit logs $ ausearch -k passwd_changes
24
Monitor Login Activity

Regularly check who has logged into your server and when. Look for unusual patterns, off-hours logins, or logins from unexpected locations.

# Recent successful logins $ last -20 # Failed login attempts $ lastb -20 # Currently logged in users $ w

Access Control and Permissions (Steps 25-28)

25
Enforce Strong Password Policies

Use PAM (Pluggable Authentication Modules) to enforce minimum password length, complexity, and history requirements.

$ apt install libpam-pwquality # /etc/security/pwquality.conf minlen = 12 dcredit = -1 ucredit = -1 lcredit = -1 ocredit = -1 maxrepeat = 3 enforce_for_root
26
Restrict sudo Access

Only give sudo access to users who absolutely need it. Use visudo to configure granular permissions.

27
Set Correct File Permissions

Review and tighten permissions on critical system files. Many fresh installations have overly permissive defaults.

File/DirectoryRecommended PermissionWhy
/etc/passwd644 (root:root)Readable by all, writable only by root
/etc/shadow640 (root:shadow)Contains password hashes
/etc/ssh/sshd_config600 (root:root)SSH server configuration
/root/.ssh/700 (root:root)SSH keys directory
/root/.ssh/authorized_keys600 (root:root)Public keys for login
/etc/cron.d/700 (root:root)Cron jobs directory
/var/log/750 (root:adm)Log files
28
Enable AppArmor Profiles

AppArmor confines programs to a limited set of resources. Enable profiles for all critical services to contain potential breaches.

# Check AppArmor status $ aa-status apparmor module is loaded. 42 profiles are loaded. 38 profiles are in enforce mode. # Put a profile in enforce mode $ aa-enforce /etc/apparmor.d/usr.sbin.nginx

Network and DNS Security (Steps 29-30)

29
Configure DNS Security

Use trusted DNS resolvers and enable DNSSEC validation. Prevent DNS poisoning attacks that could redirect your server's outgoing traffic to malicious servers.

# /etc/systemd/resolved.conf [Resolve] DNS=1.1.1.1 1.0.0.1 8.8.8.8 8.8.4.4 DNSSEC=yes DNSOverTLS=yes
30
Verify Backups and Practice Recovery

The ultimate safety net is a tested backup. A backup that has never been restored is not a backup — it is a hope. Schedule regular test restores to verify your backups actually work.

The Backup Rule of 3-2-1: Keep at least 3 copies of your data, on 2 different types of media, with 1 copy stored offsite. Test your restore process at least quarterly. Document the restore procedure step by step so anyone on your team can execute it under pressure.

The Complete Checklist

#StepCategoryPriority
1Change SSH portSSHMedium
2Disable root loginSSHCritical
3Key-based auth onlySSHCritical
4Restrict SSH usersSSHCritical
5Login grace time / max retriesSSHMedium
6Disable empty passwords / X11SSHMedium
7Strong ciphers onlySSHMedium
8SSH two-factor authSSHRecommended
9Configure firewallFirewallCritical
10Rate limit SSH at firewallFirewallMedium
11Block ICMP timestampsFirewallRecommended
12SYN flood protectionKernelMedium
13Harden sysctl parametersKernelCritical
14Secure shared memoryKernelMedium
15Mount /tmp noexecKernelMedium
16Automatic security updatesSystemCritical
17Disable unused servicesSystemMedium
18GRUB bootloader passwordSystemRecommended
19Install Fail2banIDSCritical
20File integrity monitoringIDSMedium
21Rootkit detectionIDSMedium
22Centralized loggingLoggingMedium
23Audit logging (auditd)LoggingMedium
24Monitor login activityLoggingMedium
25Strong password policiesAccessMedium
26Restrict sudo accessAccessCritical
27Correct file permissionsAccessCritical
28Enable AppArmorAccessMedium
29DNS securityNetworkRecommended
30Verify backupsRecoveryCritical

How Panelica Automates Server Hardening

Panelica implements many of these hardening steps automatically during installation and through ongoing management. The 5-layer user isolation architecture (Cgroups v2, namespaces, SSH chroot, per-user PHP-FPM, Unix permissions) provides defense in depth that would take hours to configure manually.

  • 5-layer user isolation: Cgroups v2, namespaces, SSH chroot, per-user PHP-FPM pools, Unix permissions
  • ModSecurity WAF with OWASP Core Rule Set — active protection against web application attacks
  • Fail2ban with pre-configured jails for SSH, HTTP auth, and rate limiting
  • nftables firewall management with IP blocking and rule management through the panel
  • Security Advisor that runs 50+ automated checks on your server configuration
  • Automatic SSL with Let's Encrypt and Force HTTPS
  • Audit logging for all administrative actions

Server hardening is not a one-time task — it is an ongoing process. Threats evolve, new vulnerabilities are discovered, and configurations drift over time. Schedule quarterly security reviews using this checklist, keep your system updated, and monitor your logs actively. A hardened server is not impenetrable, but it makes the cost of attack far higher than the potential reward.

Security-first hosting panel

Hosting management, the modern way.

Panelica is a modern, security-first hosting panel — isolated services, built-in Docker and AI-assisted management, with one-click migration from any panel.

Zero-downtime migration Fully isolated services Cancel anytime
Share:
Isolation, native.