Hardening Debian for Privacy and Security: Part 2 March 28, 2026
This guide is a continuation of the first hardening guide. If you have not worked through that one first, start there. Everything in this article assumes you have already implemented LUKS, UFW, AppArmor, MAC address randomization, dnscrypt-proxy, auditd, and Firejail.
This guide goes deeper. The first guide covered your baseline perimeter. This one covers active monitoring, integrity verification, behavioral controls, and hardening the browser and sudo chain—the areas where a sophisticated attacker or a persistent piece of malware will attempt to survive after your perimeter is breached.
The same disclaimer applies: this is not professional advice. You are responsible for your own machine and anything that happens on it. This guide is not sufficient to protect you from a well-resourced state actor. For that, see the companion military-level hardening guide.
Active Intrusion Detection (fail2ban)
Fail2ban monitors your system logs in real time and automatically bans IP addresses that show signs of brute-force attacks. It works by watching log files for repeated authentication failures and then issuing temporary iptables/nftables bans against the offending address.
sudo apt install fail2ban
Create a local override configuration file so your settings survive package updates:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Edit /etc/fail2ban/jail.local and set these values under [DEFAULT]:
bantime = 1h
findtime = 10m
maxretry = 5
If you have SSH exposed, ensure the SSH jail is enabled:
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(syslog_backend)s
Start and enable the service:
- Standard Debian/Ubuntu (systemd):
sudo systemctl enable --now fail2ban - MX Linux (SysVinit):
sudo service fail2ban start
To check the current state of all active jails:
sudo fail2ban-client status
sudo fail2ban-client status sshd
File Integrity Monitoring (AIDE)
A sophisticated attacker who gains a foothold on your system will attempt to modify system binaries, configuration files, or cron jobs to establish persistence. Without a file integrity monitor, you have no way to know this has happened.
AIDE (Advanced Intrusion Detection Environment) takes a cryptographic snapshot of your filesystem at a known-good state and alerts you when any monitored file changes.
sudo apt install aide
Initialize the baseline database immediately after a clean installation. This process scans your entire system and will take several minutes:
sudo aideinit
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
To run a manual integrity check against the baseline:
sudo aide --check
AIDE is only useful if it runs regularly and you actually read the output. Add a daily cron job to automate checks:
sudo crontab -e
Add the following line to run a check every night at 2 AM and email the output to root:
0 2 * * * /usr/bin/aide --check | /usr/bin/mail -s "AIDE Daily Report" root
Critical: The database at /var/lib/aide/aide.db must be initialized on a system you trust to be clean. If you initialize it after a compromise, the compromised files will be recorded as the baseline. After any intentional system update, re-initialize the database:
sudo aideinit
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
Outbound Application Firewall (OpenSnitch)
UFW controls which inbound connections are accepted by your machine. It does almost nothing to control which applications on your machine are allowed to make outbound connections. A piece of malware, a compromised application, or a data-hungry proprietary tool can freely phone home to external servers because outbound traffic is allowed by default.
OpenSnitch is a Linux application firewall that intercepts every outbound connection attempt and enforces per-application rules. Every application must be explicitly permitted to access the network.
sudo apt install opensnitch
Start the daemon and its GUI:
- Standard Debian/Ubuntu (systemd):
sudo systemctl enable --now opensnitch - MX Linux (SysVinit):
sudo service opensnitch start
Launch the GUI:
opensnitch-ui
When an application attempts an outbound connection for the first time, OpenSnitch will intercept it and display a dialog asking you what to do: allow once, deny once, allow permanently for this application and destination, or deny permanently. Build your ruleset through normal usage over a few days.
What to watch for: Any application making outbound connections to addresses you do not recognize, connecting to unusual ports, or connecting at unusual times (especially while the application is idle). These are indicators of telemetry, beaconing, or active exfiltration.
Rootkit Detection (rkhunter)
A rootkit is a category of malware specifically designed to hide itself from normal detection tools—including ps, ls, and netstat. Rootkit hunters use alternative detection methods: known signature databases, hidden file detection, and behavioral checks.
sudo apt install rkhunter
Update the signature database and run an initial scan:
sudo rkhunter --update
sudo rkhunter --check
Review the output carefully. Many initial warnings on a fresh system are false positives related to expected Debian configurations. Read each one and verify before dismissing. On subsequent runs, new warnings are meaningful.
Add a weekly automated scan to cron:
sudo crontab -e
0 3 * * 0 /usr/bin/rkhunter --check --skip-keypress --report-warnings-only | /usr/bin/mail -s "rkhunter Weekly Report" root
/proc Filesystem Hardening
The /proc virtual filesystem exposes live kernel and process information. By default, it is readable by any unprivileged user on the system. This allows local scripts or compromised applications to enumerate running processes, read their memory maps, and extract environment variables—including secrets passed to processes at startup.
Remount /proc with the hidepid=2 option, which restricts each user to seeing only their own processes:
Add the following to /etc/fstab:
proc /proc proc defaults,nosuid,nodev,noexec,hidepid=2 0 0
Apply immediately without rebooting:
sudo mount -o remount,hidepid=2 /proc
Note for MX Linux users: Some system tools (particularly those run by the messagebus user for D-Bus) may need exemption from hidepid=2. If you encounter issues with system services after applying this, you can create a process group exemption by adding gid=proc to the mount options and adding the relevant service user to the proc group. Check /var/log/syslog for permission errors if anything breaks.
Two-Factor Authentication for sudo
The sudo command is the most common privilege escalation path on a Linux workstation. By default, it requires only your user password. An attacker or a piece of malware with access to your user session can invoke sudo using only the password stored in your session cache.
Adding TOTP (Time-based One-Time Password) as a second factor for sudo means that even if an attacker has your password, they still cannot escalate privileges without access to your TOTP device (typically a smartphone running an authenticator app like Aegis on Android).
Install the PAM TOTP module:
sudo apt install libpam-google-authenticator
Run the setup wizard as your normal user (not as root):
google-authenticator
Answer y to time-based tokens. Scan the QR code with your authenticator app and save the emergency backup codes somewhere physically secure. Answer y to the subsequent configuration questions to apply the recommended security settings.
Edit the PAM sudo configuration:
sudo nano /etc/pam.d/sudo
Add the following line at the top of the file:
auth required pam_google_authenticator.so
Test immediately in a separate terminal session before closing your current one. Invoke sudo ls in the test session and confirm you are prompted for both your password and your TOTP code. If something goes wrong and you lock yourself out of sudo, you will need single-user mode or a live USB to recover.
Hardened Browser Configuration (arkenfox user.js)
Firefox's default settings leak significant information even after disabling the telemetry checkboxes. The arkenfox user.js project is a curated, heavily documented Firefox configuration file that applies hundreds of privacy and security settings that are not exposed in the standard settings UI.
Clone the project and apply it to your Firefox profile:
git clone https://github.com/arkenfox/user.js.git
cd user.js
Find your Firefox profile directory:
ls ~/.mozilla/firefox/
Copy user.js into your profile folder (replace xxxxxxxx.default-release with your actual profile name):
cp user.js ~/.mozilla/firefox/xxxxxxxx.default-release/user.js
Restart Firefox. The settings are applied on every launch from the user.js file, so they will survive Firefox updates and profile resets.
What this changes: arkenfox disables WebGL (a GPU fingerprinting vector), enforces strict first-party isolation, disables all forms of prefetching and speculative connection, hardens the referrer policy, and eliminates dozens of telemetry endpoints not reachable through the standard settings UI.
Compatibility: Some sites will break. arkenfox provides a user-overrides.js mechanism for site-specific exceptions that survives updates. Maintain a separate clean Firefox profile for sites that require relaxed settings.
TPM-Backed LUKS (Passwordless but Secure Full Disk Encryption)
Standard LUKS requires you to type your passphrase at every boot—which is good security but can be inconvenient. More importantly, it provides no protection against an attacker who learns your passphrase and steals your physical drive, because there is nothing binding the encryption to your specific hardware.
If your machine has a TPM 2.0 chip (most hardware manufactured after 2017 does), you can bind your LUKS decryption key to the TPM, which stores it in hardware and only releases it if the machine boots in an unmodified, trusted state. An attacker who removes your drive and puts it in another machine cannot decrypt it—the TPM is not present.
Install the required tools:
sudo apt install tpm2-tools clevis-tpm2 clevis-luks clevis-initramfs
Bind your LUKS volume to the TPM (replace /dev/sda3 with your actual LUKS partition—check with lsblk):
sudo clevis luks bind -d /dev/sda3 tpm2 '{"pcr_ids":"0,7"}'
pcr_ids 0 and 7 bind the key to the firmware state and Secure Boot state, respectively. If either changes (a firmware update, a tampered bootloader, or Secure Boot being disabled), the TPM will refuse to release the key.
Rebuild the initramfs to include the Clevis unlock hook:
sudo update-initramfs -u
You will still be prompted for your passphrase as a fallback if the TPM check fails. Do not remove your manual passphrase—it is your recovery mechanism.
Memory Protection Verification
Several kernel memory hardening features—ASLR, stack canaries, NX-bit enforcement—should be active by default on modern Debian. Verify they are actually on rather than assuming:
# ASLR should return 2 (full randomization)
cat /proc/sys/kernel/randomize_va_space
# Kernel pointer leak protection should return 2
cat /proc/sys/kernel/kptr_restrict
# dmesg restriction should return 1 or higher
cat /proc/sys/kernel/dmesg_restrict
If any of these return lower values than expected, add the corrected values to /etc/sysctl.conf:
kernel.randomize_va_space = 2
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
Apply: sudo sysctl -p
Latest posts
- Hardening Debian to Military Standards March 28, 2026
- Hardening Debian for Privacy and Security: Part 2 March 28, 2026
- systemd is trash, here's why March 28, 2026
- Japanese hyperpop March 27, 2026
- Harden your Raspberry Pi March 27, 2026
- Using a local server as source of truth for your time sync March 27, 2026