Debian & Ubuntu — Street Ops¶
Operational patterns for Debian/Ubuntu systems in production.
Day-One Server Setup (Ubuntu)¶
# 1. Update everything
sudo apt update && sudo apt upgrade -y
# 2. Set hostname
sudo hostnamectl set-hostname web01.example.com
# 3. Create ops user
sudo adduser deploy
sudo usermod -aG sudo deploy
# 4. SSH hardening
sudo sed -i 's/^#PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd
# 5. Enable firewall
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw --force enable
# 6. Enable unattended security updates
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure -plow unattended-upgrades
> **One-liner:** Unattended-upgrades is the single most important package on any internet-facing Ubuntu server. It patches known CVEs automatically. Without it, your server is vulnerable to every security advisory published after your last manual update.
# 7. Install essentials
sudo apt install -y curl wget git vim htop tmux net-tools
Emergency Package Recovery¶
# Fix broken dependencies
sudo apt --fix-broken install
# Reconfigure a broken package
sudo dpkg --configure -a
# Force reinstall a package
sudo apt install --reinstall nginx
# Remove and reinstall cleanly
sudo apt purge nginx
sudo apt install nginx
# Fix missing GPG keys
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys <KEY_ID>
> **Gotcha:** `apt-key` is deprecated since Ubuntu 22.04. Third-party repo keys should go in `/etc/apt/keyrings/` as individual `.gpg` files, referenced by `signed-by=` in the sources list. Old guides that use `apt-key add` will trigger deprecation warnings and will stop working in future releases.
# Clear apt cache (free disk space)
sudo apt clean # remove all cached .deb files
sudo apt autoclean # remove only obsolete cached .deb files
# Find package that owns a missing file
dpkg -S /path/to/file
apt-file search /path/to/file # (needs apt-file installed)
Debug clue: If
apt updatehangs or fails with "Could not resolve" errors, check/etc/resolv.conffirst. On cloud VMs, DHCP lease renewal can silently blank the nameserver entries. Also check ifsystemd-resolvedis running — on Ubuntu 18.04+,/etc/resolv.confis a symlink to the stub resolver at127.0.0.53.
APT Security Audit¶
# Check for available security updates
apt list --upgradable 2>/dev/null | grep -i security
# List packages from a specific repo
apt list --installed 2>/dev/null | grep third-party-repo
# Check package integrity
debsums -c # list changed config files
debsums -e # check only config files
# Audit installed packages for CVEs
apt install debsecan
debsecan --suite bookworm
# View package changelogs (check what changed)
apt changelog nginx
Multi-Version Management¶
# Install specific version
sudo apt install nginx=1.24.0-1ubuntu1
# Hold at current version
sudo apt-mark hold nginx
# Show available versions
apt-cache policy nginx
apt-cache madison nginx
# Show reverse dependencies (what depends on this package)
apt-cache rdepends nginx
# Simulate upgrade to see what would change
apt upgrade --simulate
Under the hood:
apt-mark holdwrites to/var/lib/apt/extended_statesand/var/lib/dpkg/status. A held package is skipped byapt upgradebut can still be explicitly installed withapt install nginx=<version>. Useapt-mark showholdto list all held packages — forgotten holds are a common reason a package stays at an old version for months.
Networking Operations¶
Netplan Quick Patterns¶
# Static IP
# /etc/netplan/01-static.yaml
network:
version: 2
ethernets:
ens160:
addresses: [192.168.1.100/24]
routes:
- to: default
via: 192.168.1.1
nameservers:
addresses: [8.8.8.8, 1.1.1.1]
# VLAN
network:
version: 2
ethernets:
ens160:
dhcp4: false
vlans:
vlan100:
id: 100
link: ens160
addresses: [10.10.100.5/24]
# Bond
network:
version: 2
ethernets:
ens160: {}
ens192: {}
bonds:
bond0:
interfaces: [ens160, ens192]
parameters:
mode: 802.3ad
lacp-rate: fast
addresses: [192.168.1.100/24]
# Always test before applying
sudo netplan try # auto-reverts in 120s
# Then if good:
sudo netplan apply
> **Remember:** Always use `netplan try` before `netplan apply` on remote servers. `try` auto-reverts after 120 seconds if you don't confirm. If you use `apply` and your config has a typo, you lose SSH access and need console access to fix it.
UFW Patterns¶
# Web server
sudo ufw allow 'Nginx Full' # 80 + 443
# Database (internal only)
sudo ufw allow from 10.0.0.0/8 to any port 5432
# Rate limit SSH (prevent brute force)
sudo ufw limit ssh
# Logging
sudo ufw logging on
sudo ufw logging medium # low/medium/high/full
# Check rules with numbers (for deletion)
sudo ufw status numbered
AppArmor Operations¶
# Quick status
sudo aa-status
# Debug: put profile in complain mode
sudo aa-complain /usr/sbin/nginx
# Test your app, then check logs
sudo journalctl | grep apparmor | tail -20
# Generate fixes from logs
sudo aa-logprof
# Back to enforce
sudo aa-enforce /usr/sbin/nginx
# Create a new profile interactively
sudo aa-genprof /usr/local/bin/myapp
# (run myapp in another terminal, then scan logs)
Kernel Management¶
# List installed kernels
dpkg -l | grep linux-image
# Check current kernel
uname -r
# Install HWE kernel (Ubuntu LTS)
sudo apt install linux-generic-hwe-22.04
# Remove old kernels (careful!)
sudo apt autoremove --purge
> **Default trap:** `apt autoremove` removes old kernels, but if something goes wrong with the current kernel after reboot, you lose your fallback. Always keep at least one previous kernel installed. Use `apt-mark hold` on the previous kernel before running autoremove.
# Pin a specific kernel version
sudo apt-mark hold linux-image-$(uname -r)
sudo apt-mark hold linux-headers-$(uname -r)
# View GRUB menu entries
grep menuentry /boot/grub/grub.cfg
# Set default kernel
sudo vim /etc/default/grub # GRUB_DEFAULT=
sudo update-grub
Debian-Specific Patterns¶
# Check Debian release info
cat /etc/debian_version
lsb_release -a
# Switch to a new Debian release (careful!)
# 1. Update sources.list to new codename
sudo sed -i 's/bullseye/bookworm/g' /etc/apt/sources.list
# 2. Update and full-upgrade
sudo apt update
sudo apt full-upgrade
# 3. Reboot
sudo reboot
# Use backports (newer packages on stable)
echo "deb http://deb.debian.org/debian bookworm-backports main" | \
sudo tee /etc/apt/sources.list.d/backports.list
sudo apt update
sudo apt install -t bookworm-backports <package>
Gotcha: When upgrading between Debian major versions (e.g., bullseye to bookworm), always use
apt full-upgrade, notapt upgrade.full-upgradecan remove packages when needed to resolve dependency changes.upgraderefuses to remove anything, which can leave your system in a broken half-upgraded state.