Most server hardening guides stop at firewalls, fail2ban, and disabling root login. You've done that already. The real vulnerabilities live deeper—in syscall access, kernel parameters, filesystem mount options, and the audit pipeline. I've spent years responding to intrusions that bypassed the standard playbook, and the patterns are clear: attackers probe for weak entropy, abuse SUID binaries, and exploit overly permissive syscalls. Here are eight advanced hardening moves that close those gaps.
1. Lock down syscalls with seccomp profiles
Seccomp filters which system calls a process can make. Most services need fewer than fifty syscalls, but by default every process can invoke all three hundred-plus. That's a massive attack surface.
Create a seccomp profile for your web server or application. For systemd services, add this to the unit file:
[Service]
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources @obsolete
SystemCallErrorNumber=EPERM
The @system-service group allows common syscalls. The second line denies privileged operations, resource manipulation, and obsolete calls. Test carefully—if the service breaks, check journalctl -xe for denied syscalls and whitelist only what's necessary.
For containers, seccomp is even more important. Default Docker profiles are permissive. Generate a minimal profile with docker run --security-opt seccomp=profile.json and iterate until the container runs cleanly.
2. Harden mount options on every filesystem
Default mount options allow execution, device files, and SUID binaries everywhere. Lock them down per partition.
Edit /etc/fstab and add restrictive flags:
/dev/sda2 /tmp ext4 defaults,nodev,nosuid,noexec 0 2
/dev/sda3 /var ext4 defaults,nodev 0 2
/dev/sda4 /home ext4 defaults,nodev,nosuid 0 2
noexecprevents execution from/tmpand/var/tmp, common staging grounds for exploits.nosuiddisables SUID bit respect, blocking privilege-escalation binaries.nodevdenies device file interpretation.
After editing, remount with mount -o remount /tmp. Check with mount | grep tmp. If an application breaks, identify which binary needs execution and move it or create a narrower exception.
3. Restrict kernel pointers and symbols
Kernel address leaks make exploitation easier. Two sysctl settings hide them.
sysctl -w kernel.kptr_restrict=2
sysctl -w kernel.dmesg_restrict=1
The first hides kernel pointers even from root. The second restricts dmesg to CAP_SYSLOG, blocking unprivileged users from reading kernel logs that often leak addresses. Add both to /etc/sysctl.d/99-hardening.conf to persist across reboots.
Check with sysctl kernel.kptr_restrict. You'll still see 0000000000000000 in /proc/kallsyms, which is correct.
4. Tune entropy availability for cryptographic operations
Low entropy delays TLS handshakes and key generation, but it also creates weaker random numbers. Many VPS platforms provide poor entropy by default.
Check available entropy:
cat /proc/sys/kernel/random/entropy_avail
If it's consistently below 1000, install haveged or rng-tools. Haveged uses CPU timing jitter as an entropy source:
apt install haveged
systemctl enable haveged
After starting, entropy should stabilize above 2000. For cloud instances with virtio-rng, load the kernel module and point rngd at it:
modprobe virtio_rng
rngd -r /dev/hwrng
Don't rely on /dev/urandom alone for long-term keys. Generate them on a local machine with good entropy and upload securely.
5. Enable and tune auditd for forensic visibility
If an intrusion happens, you need to know what changed. Auditd logs syscalls and file access. Most servers either don't run it or log too much, filling disks.
Install and start:
apt install auditd audispd-plugins
systemctl enable auditd
Add targeted rules in /etc/audit/rules.d/hardening.rules:
# Watch authentication files
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k privilege
# Monitor privilege escalation attempts
-a always,exit -F arch=b64 -S setuid -S setgid -S setreuid -S setregid -k privilege_escalation
# Track network configuration changes
-w /etc/hosts -p wa -k network_config
-w /etc/sysconfig/network -p wa -k network_config
Reload with augenrules --load. Query logs with ausearch -k identity. In production I rotate audit logs daily and keep 30 days compressed. Disk is cheap; knowing when /etc/shadow was modified is priceless.
6. Isolate services with mandatory access control
Even if an attacker compromises a service, MAC systems like AppArmor or SELinux contain the damage. Most distributions ship with them installed but in permissive mode or with minimal profiles.
For AppArmor (Debian/Ubuntu), check status:
aa-status
If profiles exist but are in complain mode, enforce them:
aa-enforce /etc/apparmor.d/usr.sbin.nginx
Create custom profiles with aa-genprof. Run the service, exercise all features, then review and approve the generated policy. It's tedious but catches lateral movement.
For SELinux (RHEL/CentOS), verify enforcing mode:
getenforce
If it returns Permissive, edit /etc/selinux/config and set SELINUX=enforcing, then reboot. After enabling, watch for denials in /var/log/audit/audit.log and use audit2allow to create targeted policies. Don't disable SELinux to fix an application; fix the policy instead.
7. Restrict core dumps and process tracing
Core dumps can leak secrets and credentials in memory. Disable them for all users:
echo '* hard core 0' >> /etc/security/limits.conf
sysctl -w fs.suid_dumpable=0
sysctl -w kernel.core_pattern=|/bin/false
The first line sets a hard limit. The second prevents SUID programs from dumping. The third redirects dumps to /bin/false. For debugging, enable dumps temporarily for a single user, not system-wide.
Restrict ptrace to prevent process inspection:
sysctl -w kernel.yama.ptrace_scope=2
This blocks ptrace entirely except for children of a process. Debuggers still work, but an attacker can't attach to running processes to scrape memory.
8. Filter link-local and martian packets at the NIC
Most servers accept packets from link-local addresses (169.254.0.0/16) and other invalid sources. That creates side channels for local attacks and helps attackers map the network.
Add these to /etc/sysctl.d/99-network.conf:
# Drop martian packets
net.ipv4.conf.all.log_martians=1
net.ipv4.conf.default.log_martians=1
net.ipv4.conf.all.rp_filter=1
net.ipv4.conf.default.rp_filter=1
# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects=0
net.ipv4.conf.default.accept_redirects=0
net.ipv6.conf.all.accept_redirects=0
net.ipv6.conf.default.accept_redirects=0
# Ignore source-routed packets
net.ipv4.conf.all.accept_source_route=0
net.ipv4.conf.default.accept_source_route=0
net.ipv6.conf.all.accept_source_route=0
net.ipv6.conf.default.accept_source_route=0
Apply with sysctl -p /etc/sysctl.d/99-network.conf. Martian logs will appear in dmesg if attacks occur.
For link-local specifically, add an iptables rule:
iptables -A INPUT -s 169.254.0.0/16 -j DROP
This matters most in cloud environments where metadata services live at 169.254.169.254 and SSRF attacks try to reach them.
Bonus: rotate and limit log files aggressively
Logs grow without bounds, filling disks and slowing searches. Configure logrotate for every service.
Create /etc/logrotate.d/custom:
/var/log/myapp/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 www-data adm
sharedscripts
postrotate
systemctl reload myapp > /dev/null 2>&1 || true
endscript
}
This keeps two weeks of logs, compresses old ones, and signals the service to reopen files. For audit logs, increase retention but keep compression.
If disk fills anyway, attackers sometimes exploit that to disable logging. Monitor disk usage with df -h in cron and alert below 20% free.
What about intrusion detection?
Host-based IDS like AIDE or Tripwire catch file changes but generate noise. I run AIDE weekly and store the database off-host so an attacker can't tamper with it.
Initialize:
apt install aide
aideinit
cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
Check for changes:
aide --check
Exclude noisy paths like /var/log in /etc/aide/aide.conf. Review output carefully—legitimate package updates will show changes, but unauthorized modifications stand out.
For real-time monitoring, auditd is lighter and more actionable.
FAQ
Does seccomp break application compatibility?
Yes, if you're too aggressive. Start with @system-service and expand only when the service fails. Check logs for denied syscalls.
Can I use all these on a cPanel server?
Most will work. Avoid changing mount options on cPanel-managed partitions. Seccomp and sysctl settings are safe. Test in staging first.
How do I know which syscalls to allow?
Run strace -c on the service to see syscall frequency. Whitelist the top twenty and test. Tools like systemd-analyze security also suggest filters.
Will AppArmor or SELinux slow down my server?
The overhead is negligible—usually under 1%. The real cost is policy creation time. Once policies are correct, performance is fine.
Should I enable all sysctl settings at once?
No. Apply in groups, reboot, and test. A typo in sysctl can prevent boot. Keep a rescue console open.
Where to start
If you implement only two, choose auditd and seccomp. Auditd tells you what happened after an incident. Seccomp prevents many incidents from succeeding in the first place. Mount options come third—they're simple and catch a category of exploits that other tools miss.
Don't treat hardening as one-time work. New services need new seccomp profiles. New vulnerabilities need updated sysctls. Schedule quarterly reviews and check your audit logs monthly. The servers that stay secure are the ones where hardening is routine, not a project.
![Advanced Server Security Hardening Checklist: 8 Moves [2026]](/images/blog/advanced-server-security-hardening-checklist-8-moves-2026.jpg)