A practical, no-fluff checklist for hardening an Ubuntu/Debian or RHEL-family server. Work through it top to bottom on a new server, or use it to audit an existing one. Items marked ★ are the ones that stop most real-world compromises.
Need this done for you? Our Linux Server Hardening & Security Audit checks every item below against CIS Benchmarks and applies the fixes with a rollback plan. Tools referenced here are in the tools directory.
1. Before you start
- Take a snapshot or full backup; confirm you can restore it
- Record the current state:
ss -tulpn,systemctl list-units --type=service --state=running,getent passwd - Keep a second SSH session open while changing SSH or firewall settings
- Set the hostname, timezone (
timedatectl set-timezone Asia/Kolkata) and enable NTP (timedatectl set-ntp true)
2. Patching ★
- Update everything:
apt update && apt full-upgrade/dnf upgrade - Enable automatic security updates (
unattended-upgradeson Debian/Ubuntu,dnf-automaticon RHEL) - Remove packages you do not need:
apt autoremove; uninstall telnet, rsh, compilers on production boxes if unused - Reboot after kernel updates; check
needrestartordnf needs-restarting
3. Accounts and privileges ★
- Create a named admin user; never log in or run services as root
- Lock the root password:
passwd -l root - Use
sudowith specific rules; avoidNOPASSWD: ALL - Review all accounts: delete or lock unused users; check for UID 0 duplicates (
awk -F: '$3==0' /etc/passwd) - Set password policy (
/etc/login.defs,pam_pwquality): min length 14, max age 90–365 days - Set shell timeout:
TMOUT=900in/etc/profile.d/timeout.sh
4. SSH ★
# /etc/ssh/sshd_config.d/99-hardening.conf
PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
MaxAuthTries 3
LoginGraceTime 30
X11Forwarding no
AllowTcpForwarding no
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers youradmin
# then: sshd -t && systemctl reload ssh- Use ed25519 keys; protect private keys with a passphrase
- Optionally change the port (reduces log noise, not a security control)
- Install fail2ban and enable the
sshdjail (bantime 1h, maxretry 5) - Check who can log in:
last -a | head,lastb | head
5. Firewall ★
- Default deny inbound, allow outbound: UFW (
ufw default deny incoming), firewalld or nftables - Open only what the server needs (22, 80, 443 for a web server); restrict SSH to your IP range where possible
- Bind databases (MySQL/PostgreSQL/Redis/Mongo) to 127.0.0.1 or a private network; never expose them publicly
- Verify from outside with
nmap -sS -Pn yourserveror Shodan/Censys
6. File system and permissions
- Mount
/tmp,/var/tmpand/dev/shmwithnoexec,nosuid,nodev - Find world-writable files:
find / -xdev -type f -perm -0002 - Review SUID/SGID binaries:
find / -xdev -perm /6000 -type f; remove the SUID bit from ones you do not need - Set
umask 027for system users; protect/etc/shadow(0640 root:shadow),/etc/ssh/*_key(0600) - Enable AIDE or Wazuh file-integrity monitoring for
/etc,/bin,/usr/bin, web roots
7. Kernel and network stack
# /etc/sysctl.d/99-hardening.conf
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.tcp_syncookies = 1
net.ipv6.conf.all.accept_redirects = 0
kernel.randomize_va_space = 2
kernel.kptr_restrict = 2
fs.protected_symlinks = 1
fs.protected_hardlinks = 1
# apply: sysctl --system- Disable IPv6 only if you truly do not use it; otherwise firewall it the same as IPv4
- Keep AppArmor (Ubuntu) or SELinux (RHEL) in enforcing mode; fix denials instead of disabling
8. Logging and monitoring ★
- Install and enable
auditdwith rules for sudo, passwd/shadow changes, and binary modifications - Ship logs off-box (rsyslog → central server, Wazuh, or a cloud log service); attackers delete local logs
- Set journald persistence and retention:
Storage=persistent,SystemMaxUse=1G - Monitor resources and uptime (Netdata, Prometheus/Grafana or Uptime Kuma); alert on disk > 85%, new listening ports, failed-login spikes
- Review logs weekly:
journalctl -p err -S -7d, fail2ban status, web server 4xx/5xx spikes
9. Web and application stack
- TLS only: redirect 80 → 443, Let’s Encrypt with auto-renewal, config from the Mozilla SSL Configuration Generator (Intermediate)
- Security headers: HSTS, Content-Security-Policy, X-Content-Type-Options, Referrer-Policy; test on securityheaders.com
- Hide versions:
server_tokens off(Nginx),ServerTokens Prod(Apache),expose_php = Off - Run apps as dedicated low-privilege users; web root owned by a deploy user, writable dirs limited to uploads/cache
- WordPress: disable file editing (
DISALLOW_FILE_EDIT), limit login attempts, keep plugins/themes updated, remove unused ones - Rate-limit login and API endpoints at the reverse proxy
10. Backups and recovery ★
- Automated daily backups (database dump + files) to a different provider or region
- Encrypt backups at rest; keep at least 7 daily + 4 weekly copies; one copy offline/immutable
- Test a restore every quarter; write down the exact restore steps
- Document the server: purpose, owner, open ports, services, backup location, contacts
11. Verify your work
- Run
lynis audit systemand aim for a hardening index above 75; fix the warnings it lists - Scan from outside with Nmap and check SSL Labs (A or better) and securityheaders.com (A)
- Re-check in 90 days; put a calendar reminder for patching and log review
This checklist is maintained by Youngster Company and reviewed against the CIS Distribution Independent Linux Benchmark. Last updated October 2026. Share it freely with attribution.
Need this done for you? Our Linux Server Hardening & Security Audit checks every item below against CIS Benchmarks and applies the fixes with a rollback plan. Tools referenced here are in the tools directory.
