Skip to content

Debian Server Security – A How-To

    Running a Debian server is a powerful way to host websites, applications, or services, but with great power comes great responsibility—security is paramount. A poorly secured server can become a target for attackers, compromising data and disrupting operations. In this guide, I’ll walk you through the comprehensive steps I took to harden my Debian server, ensuring it’s locked down while maintaining functionality for SSH access, automated updates, and advanced intrusion detection. Whether you’re a seasoned sysadmin or a curious beginner, this guide will help you secure your Debian server like a pro.

    Why Server Security Matters

    Before diving into the technical details, let’s talk about why securing your server is critical. Unsecured servers are vulnerable to brute-force attacks, malware, and unauthorized access, which can lead to data breaches or service downtime. By implementing layered security measures—ranging from strong authentication to intrusion detection—you can significantly reduce these risks. My approach combines best practices with modern tools like CrowdSec and Wazuh to create a robust defense system.

    Here’s how I secured my Debian server (running Debian 12, but these steps apply to most recent versions).

    Step 1: System Updates and Non-Root User Setup

    The foundation of a secure server starts with a clean, updated system and minimizing root access.

    • Full System Update: I began by running sudo apt-get update && sudo apt-get upgrade -y to ensure all packages were up to date. This patches known vulnerabilities and keeps the system current. A quick sudo reboot ensured everything was applied cleanly.
    • Non-Root User: Using the root account for daily operations is risky, so I created a non-root user with sudo adduser <username> and assigned a strong, unique password generated by a password manager. I added this user to the sudoers file with sudo usermod -aG sudo <username> to allow administrative tasks without root login. This minimizes the attack surface if credentials are compromised.

    Step 2: Hardening SSH Access

    SSH is often the primary way to manage a server remotely, but it’s also a common target for attackers. I took several steps to lock it down:

    • Custom SSH Port: I changed the default SSH port (22) to a non-standard port (e.g., 2222) in /etc/ssh/sshd_config by setting Port 2222. This reduces automated bot scans, though it’s not a silver bullet.
    • SSH Configuration Tweaks: I edited /etc/ssh/sshd_config to include:
      • PermitRootLogin no: Disables direct root login.
      • LoginGraceTime 6: Limits login attempts to 6 seconds, thwarting slow brute-force attacks.
      • MaxAuthTries 3: Caps authentication attempts per session at 3.
      • MaxSessions 3: Restricts simultaneous connections to 3, reducing resource abuse.
      • PubkeyAuthentication yes: Enables key-based authentication for stronger security.
      • X11Forwarding no: Disables X11 forwarding, as it’s unnecessary for most servers.
    • Public Key Authentication: I generated an Ed25519 key pair on my local machine (ssh-keygen -t ed25519) and copied the public key to the server’s non-root user with ssh-copy-id <username>@<server-ip>. This eliminates reliance on passwords, which are vulnerable to brute-force attacks.
    • Two-Factor Authentication (2FA): For an extra layer of security, I installed Google Authenticator (sudo apt install libpam-google-authenticator). After running google-authenticator as the non-root user and following the setup prompts, I updated /etc/pam.d/sshd to include auth required pam_google_authenticator.so and set ChallengeResponseAuthentication yes in /etc/ssh/sshd_config. Now, SSH access requires both a private key and a time-based code from my authenticator app.

    After making these changes, I restarted the SSH service (sudo systemctl restart sshd) and tested access in a separate session to avoid lockouts.

    Step 3: Automating Updates with Unattended-Upgrades

    Keeping software patched is critical for security. I set up unattended-upgrades to automate security updates:

    • Installed the package: sudo apt install unattended-upgrades apt-listchanges.
    • Configured it with sudo dpkg-reconfigure --priority=low unattended-upgrades, enabling automatic updates.
    • Edited /etc/apt/apt.conf.d/50unattended-upgrades to prioritize security updates and enable auto-reboots at 3 AM if needed:
    "${distro_id}:${distro_codename}-security";
    "${distro_id}:${distro_codename}-updates";
    Unattended-Upgrade::Automatic-Reboot "true";
    Unattended-Upgrade::Automatic-Reboot-Time "03:00";

    Tested with sudo unattended-upgrades --dry-run to confirm it works as expected.

    Step 4: Firewall Setup with UFW

    A firewall is your server’s front-line defense. I chose UFW (Uncomplicated Firewall) for its simplicity and effectiveness:

    • Installed UFW: sudo apt install ufw.
    • Configured rules:
      • Allowed SSH on the custom port: sudo ufw allow 2222.
      • Set default policies: sudo ufw default deny incoming and sudo ufw default allow outgoing to block unsolicited inbound traffic while allowing the server to initiate connections.
    • Enabled UFW: sudo ufw enable.
    • Verified rules: sudo ufw status.

    This setup ensures only explicitly allowed traffic (like SSH) reaches the server, while outbound traffic (e.g., for updates) flows freely.

    Step 5: Intrusion Detection with CrowdSec and Firewall Bouncer

    CrowdSec is a modern, open-source intrusion detection and prevention system that leverages community-driven threat intelligence. Here’s how I set it up:

    curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash
    sudo apt install crowdsec

    Enabled and started the service: sudo systemctl enable crowdsec && sudo systemctl start crowdsec. Enrolled the instance with sudo cscli config show and added the SSH protection collection: sudo cscli collections install crowdsecurity/sshd. Integrated CrowdSec with UFW by installing the firewall bouncer:

    sudo apt install crowdsec-firewall-bouncer-iptables
    • Configured the bouncer to use UFW by editing /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml to set mode: ufw.
    • Restarted the bouncer: sudo systemctl restart crowdsec-firewall-bouncer.

    CrowdSec now monitors for suspicious activity (e.g., SSH brute-force attempts) and automatically blocks malicious IPs via UFW, leveraging its crowd-sourced ban lists for enhanced protection.

    Step 6: Monitoring with Wazuh Agent

    To keep an eye on system activity, I installed the Wazuh agent, a powerful open-source security monitoring tool:

    • Followed the official Wazuh documentation to install the agent (sudo apt install wazuh-agent after adding the Wazuh repository).
    • Configured it to connect to my Wazuh manager (you’ll need a Wazuh server set up separately).
    • Enabled and started the service: sudo systemctl enable wazuh-agent && sudo systemctl start wazuh-agent.

    Wazuh provides real-time monitoring, log analysis, and alerts for suspicious activity, complementing CrowdSec’s proactive blocking.

    Step 7: File Integrity Monitoring with AIDE

    To detect unauthorized changes to critical files, I installed AIDE (Advanced Intrusion Detection Environment):

    • Installed AIDE: sudo apt install aide.
    • Initialized the database: sudo aideinit.
    • Scheduled daily checks by adding a script to /etc/cron.daily/aide.

    AIDE creates a baseline of file checksums and alerts me if critical system files (like /etc/passwd) are modified, helping detect potential intrusions.

    Step 8: Final Touches with Sudoers

    To ensure the non-root user could perform administrative tasks securely, I added them to the sudoers file:

    sudo visudo -f /etc/sudoers.d/<username>
    <username> ALL=(ALL) NOPASSWD: /usr/sbin/reboot, /usr/bin/apt

    This approach limits sudo access to specific commands where possible, reducing the risk of accidental or malicious changes.

    Key Takeaways and Ongoing Maintenance

    Securing a Debian server is an ongoing process, not a one-time task. Here are my key takeaways:

    • Layered Security: Combining SSH hardening, 2FA, UFW, CrowdSec, Wazuh, and AIDE creates multiple layers of defense.
    • Automation: Tools like unattended-upgrades and CrowdSec reduce manual overhead while keeping the server secure.
    • Monitoring: Regular log reviews (/var/log/auth.log, CrowdSec’s cscli decisions list, and Wazuh alerts) are essential to catch issues early.
    • Testing: Always test changes (e.g., SSH or UFW rules) in a separate session to avoid lockouts.

    For ongoing maintenance, I plan to:

    • Monitor logs weekly for anomalies.
    • Run security audits with tools like lynis (sudo apt install lynis; sudo lynis audit system).
    • Stay updated on Debian security advisories (debian.org/security).

    Conclusion

    Securing a Debian server doesn’t have to be daunting. By following these steps—updating the system, hardening SSH with 2FA, setting up UFW, automating updates, and leveraging advanced tools like CrowdSec, Wazuh, and AIDE—you can build a fortress-like server that’s resilient to attacks. My setup ensures I can manage the server securely via SSH while staying protected against common threats.

    Have you secured your own server? What tools or techniques do you use? Drop a comment below or reach out to share your thoughts! For more tech tips and guides, stay tuned to my blog.

    Happy securing!

    Leave a Reply

    Your email address will not be published. Required fields are marked *