Engineering in practice

Deploying on Debian without fear

13 October 2026 · 8 min read

The Baseline: Treating Infrastructure as Predictable Code

When setting up a new production Debian 12 server, manual configuration through terminal history is an anti-pattern. If you set up a server by memory, you will inevitably forget a step: omitting a firewall rule, leaving SSH password login enabled, or misconfiguring timezone synchronizations.

Deploying on Debian without fear requires a deterministic, idempotent hardening baseline. Here is the exact blueprint codified inside debian-bootstrap.


1. Privileged User Separation: Stop Using Root

The moment a virtual private server (VPS) boots, create an unprivileged operational account with sudo permissions and install your authorized public SSH keys:

# Create deploy user
adduser --gecos "" deploy
usermod -aG sudo deploy

# Copy authorized SSH keys from root
mkdir -p /home/deploy/.ssh
cp /root/.ssh/authorized_keys /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys

2. Hardening SSH Without Getting Locked Out

Edit /etc/ssh/sshd_config.d/hardening.conf (or /etc/ssh/sshd_config) to enforce key-only authentication:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
X11Forwarding no
MaxAuthTries 4

The Critical Safety Step: Before restarting or reloading the SSH daemon, always validate the configuration syntax:

sudo sshd -t

If sshd -t outputs any errors, fix them before reloading! Never close your existing active SSH terminal session until you have successfully tested a new SSH connection in a separate terminal window.


3. Restrictive Firewall (UFW) with Default-Deny

Configure Uncomplicated Firewall (UFW) with a default-deny policy, explicitly allowing only required ports:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp comment 'SSH'
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
sudo ufw --force enable

4. Intrusion Prevention & Unattended Security Updates

Brute-force automated bots scan internet IP ranges continuously. Mitigate this with two essential packages:

sudo apt update && sudo apt install -y fail2ban unattended-upgrades

# Enable automatic critical security patches
sudo dpkg-reconfigure -plow unattended-upgrades

# Start and enable fail2ban
sudo systemctl enable --now fail2ban

5. Virtual Memory (Swap) & Clock Synchronization

Even on servers with adequate RAM, having 2GB to 4GB of swap space acts as a vital safety buffer against unexpected memory spikes, preventing the Linux kernel OOM killer from abruptly terminating your database or API processes:

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

# Tune kernel swappiness to favor physical RAM
sudo sysctl vm.swappiness=10
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.d/99-swap.conf

Finally, ensure precise clock synchronization using systemd-timesyncd:

sudo timedatectl set-ntp true
sudo timedatectl set-timezone UTC

With these automated steps in place, any new Debian instance can be transformed from a raw virtual machine into an audited, secure production platform in under five minutes.