Debian / Ubuntu Setup¶
This page covers machine-level setup for Debian-based distributions — primarily Ubuntu (the most common developer-facing Debian derivative) with notes for vanilla Debian where behavior differs. It is the prerequisite to the Onboarding Runbook.
Ubuntu's defaults are more developer-friendly out of the box than Fedora's (codecs are offered during install, drivers are detected automatically), but its snap strategy creates friction that this page addresses directly.
Post-install checklist (first boot)¶
# 1. System update
sudo apt update && sudo apt upgrade -y
# 2. Install basic tools immediately (needed for everything else)
sudo apt install -y curl wget git software-properties-common
# 3. Firmware updates (Ubuntu)
sudo fwupdmgr get-devices
sudo fwupdmgr refresh --force
sudo fwupdmgr get-updates
sudo fwupdmgr update
# 4. Reboot (kernel updates, firmware)
sudo reboot
apt configuration¶
apt's defaults are reasonable. Two additions improve the developer experience:
Parallel downloads¶
Create /etc/apt/apt.conf.d/99parallel:
Automatic security updates¶
Ubuntu enables unattended-upgrades for security by default. Verify
it is active:
On vanilla Debian, this is not enabled by default — install and configure it explicitly.
Backports (Debian only)¶
Vanilla Debian's stable repositories ship older tool versions. Enable backports for access to newer packages without switching to testing:
# /etc/apt/sources.list.d/backports.list
echo "deb http://deb.debian.org/debian $(lsb_release -cs)-backports main" | \
sudo tee /etc/apt/sources.list.d/backports.list
sudo apt update
Install specific packages from backports with:
The snap problem¶
Ubuntu ships Firefox, Thunderbird, and increasingly other GUI applications as snaps. For development tools, snaps introduce three problems:
- Startup latency — snap applications decompress on launch. First launch of a snap app after boot takes 3-10 seconds.
- Sandbox restrictions — snaps cannot access arbitrary host paths
without manual interface connections. This breaks tools that need to
see
~/.config,/tmp, or project directories outside$HOME. - PATH and socket isolation — snap-installed tools cannot see mise shims, the Podman socket, or SSH agent sockets without per-snap configuration.
The framework's position: remove snap versions of developer tools and install native .deb packages or upstream binaries.
Replacing snap Firefox (Ubuntu)¶
# Remove snap Firefox
sudo snap remove firefox
# Install Mozilla's official PPA
sudo add-apt-repository ppa:mozillateam/ppa
# Pin PPA version over snap
echo '
Package: *
Pin: release o=LP-PPA-mozillateam
Pin-Priority: 1001
' | sudo tee /etc/apt/preferences.d/mozilla-firefox
# Prevent apt from re-installing the snap transitional package
echo 'Package: firefox*
Pin: release o=Ubuntu
Pin-Priority: -1
' | sudo tee -a /etc/apt/preferences.d/mozilla-firefox
sudo apt update
sudo apt install firefox
Preventing snap reinstallation¶
Ubuntu's ubuntu-desktop metapackage can pull snap packages back in
during upgrades. Create a preference that blocks the snap transitional
packages:
Pragmatism over purity
This framework does not advocate removing snapd entirely. Snap is fine for consumer applications (Slack, Spotify, Discord) where sandbox isolation is a benefit. The guidance is specific: development tools that need host integration should not be snaps.
Multimedia codecs¶
Ubuntu offers restricted extras during installation. If skipped:
For hardware-accelerated video:
# Intel
sudo apt install intel-media-va-driver-non-free
# AMD
sudo apt install mesa-va-drivers
# NVIDIA (if using proprietary driver)
sudo apt install nvidia-vaapi-driver
Filesystem and storage¶
Enable fstrim for SSDs¶
ext4 considerations¶
Ubuntu defaults to ext4 (not Btrfs like Fedora). ext4 is stable and
fast with no special developer-facing tuning needed. If using Btrfs
(Debian installer offers it, Ubuntu does not by default), see the
Fedora page's Btrfs section — the same chattr +C guidance for
container storage applies.
Firewall¶
Ubuntu ships with ufw (Uncomplicated Firewall) — a frontend to
iptables/nftables. It is installed but not enabled by default on
desktop Ubuntu. Enable it:
sudo ufw enable
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Verify
sudo ufw status verbose
Common developer additions:
# Allow a dev server from LAN
sudo ufw allow 3000/tcp
# Allow SSH (if doing remote development on this machine)
sudo ufw allow ssh
# Remove when done
sudo ufw delete allow 3000/tcp
# Check rules
sudo ufw status numbered
On vanilla Debian, ufw is available but not pre-installed:
AppArmor¶
Ubuntu uses AppArmor (not SELinux) as its mandatory access control framework. Like the Fedora page's SELinux guidance: leave it enabled. Do not disable AppArmor to fix a development problem.
# Check status
sudo aa-status
# See recent denials
sudo dmesg | grep -i apparmor
# Set a profile to complain mode (logging without enforcement)
sudo aa-complain /usr/bin/some-program
# Re-enable enforcement
sudo aa-enforce /usr/bin/some-program
Container interaction: Podman on Ubuntu works with AppArmor's default
policies. Unlike SELinux's :z/:Z suffix requirement on Fedora,
bind mounts in Podman on Ubuntu/Debian work without special labeling
in most cases.
Systemd services for development¶
SSH agent as a user service¶
Identical to the Fedora setup — see the Onboarding Runbook for the full systemd unit.
Podman socket¶
systemctl --user enable --now podman.socket
export DOCKER_HOST="unix://${XDG_RUNTIME_DIR}/podman/podman.sock"
Journal size management¶
Edit /etc/systemd/journald.conf:
GNOME desktop tuning¶
Ubuntu ships GNOME on Wayland (with modifications). The framework's assumption of GNOME, why, and what changes if you run KDE/Sway instead are covered in the Fedora page's GNOME note; it applies identically here. The same tuning as Fedora applies:
# Key repeat speed
gsettings set org.gnome.desktop.peripherals.keyboard delay 200
gsettings set org.gnome.desktop.peripherals.keyboard repeat-interval 25
# Caps Lock as Ctrl
gsettings set org.gnome.desktop.input-sources xkb-options "['caps:ctrl_modifier']"
# Disable hot corner
gsettings set org.gnome.desktop.interface enable-hot-corners false
# Font rendering
gsettings set org.gnome.desktop.interface font-antialiasing 'rgba'
gsettings set org.gnome.desktop.interface font-hinting 'slight'
Ubuntu-specific: minimize button¶
Ubuntu's GNOME adds a minimize button by default. If using a tiling workflow or keyboard-driven window management, remove it:
Power management (laptops)¶
# TLP for advanced power management
sudo apt install tlp tlp-rdw
sudo systemctl enable --now tlp
# Ubuntu uses power-profiles-daemon by default; TLP replaces it
sudo systemctl mask power-profiles-daemon
For ThinkPads:
Developer prerequisites¶
Install before running bootstrap.sh:
sudo apt install \
zsh git curl wget \
build-essential cmake pkg-config \
libssl-dev zlib1g-dev libreadline-dev \
libffi-dev libyaml-dev \
libsqlite3-dev libpq-dev \
jq \
libsecret-tools \
podman buildah skopeo \
shellcheck
fd and bat naming quirk — sidestepped entirely
Debian/Ubuntu ship fd as fdfind and bat as batcat due to
package-name conflicts. This framework never hits that: fd and
bat are mise-managed (aqua-backed GitHub release binaries), so
they arrive under their real names. If you ever install the apt
versions instead, you will need fd=fdfind / bat=batcat
aliases yourself — the framework does not ship them.
Why each group:
- zsh, git, curl, wget — framework hard dependencies.
- build-essential, cmake, pkg-config, lib*-dev — build toolchain for native extensions. Without these, compiling Ruby, Python C extensions, and Node native addons fails.
- jq — pre-mise CLI dependency (also mise-managed later; see the
overlap note below).
bat,fd,ripgrep,fzf, anddirenvare deliberately NOT in this list — they are declared in mise's[tools]with aqua-backed resolution and arrive withmise bootstrap; their shell wiring iscommand -vguarded. - libsecret-tools — provides
secret-tool, used by thekeychain_getshell function. - podman, buildah, skopeo — container toolchain. Note: on older Ubuntu (22.04), Podman may need the Kubic repository for a current version.
Deliberate overlap with mise [tools], and two gaps
jq, shellcheck, zsh, and libsecret-tools are also
declared in the mise config and will be managed by mise after
mise bootstrap — mise's shims sit earlier on PATH, so the
mise-managed versions win from then on. The apt copies cover the
window before mise exists. Two tools deserve the same treatment
but have unreliable apt package names across releases, so they are
not in the list above:
gh— worth installing beforemise bootstrapif your release ships it (sudo apt install gh, or GitHub's own apt repo):gh auth loginraises the GitHub API limit from 60 to 5000 requests/hour, and mise'sgithub:backend and attestation checks spend that budget during the bootstrap itself.git-delta— git's configured pager. Until mise deliversdelta, paged git commands fail; either install it if your release has it, or ride out the few minutes betweenbootstrap.shandmise bootstrapwithgit -c core.pager=less <cmd>.
- shellcheck — shell script static analysis for pre-commit hooks.
Podman version (Ubuntu 22.04)¶
Ubuntu 22.04's default Podman package is old (3.4.x). Historically the
fix was the Kubic (devel:kubic:libcontainers) OBS repository —
but that project has been discontinued and its repos are gone, so
the old kubic instructions no longer work. On 22.04 today, either:
- upgrade to Ubuntu 24.04+ (ships Podman 4.9.x — current enough for
rootless networking and
podman composewith a provider), or - use a maintained alternative (the
podmanPPA / static builds), or build from source.
# Ubuntu 24.04+ : Podman 4.9.x is in the default repos, no extra setup.
sudo apt install podman
podman --version
Do not copy the old download.opensuse.org/.../kubic/... source lines
— they 404.
VS Code installation¶
Do not use the snap version of VS Code. Install from Microsoft's apt repository:
Microsoft now recommends the deb822 .sources format (easier to audit
and remove than the legacy one-line .list), with the key under
/usr/share/keyrings:
wget -qO- https://packages.microsoft.com/keys/microsoft.asc | \
gpg --dearmor | sudo tee /usr/share/keyrings/microsoft.gpg > /dev/null
sudo tee /etc/apt/sources.list.d/vscode.sources > /dev/null <<'EOF'
Types: deb
URIs: https://packages.microsoft.com/repos/code
Suites: stable
Components: main
Architectures: amd64,arm64,armhf
Signed-By: /usr/share/keyrings/microsoft.gpg
EOF
sudo apt update
sudo apt install code
After this page¶
Proceed to the Onboarding Runbook for framework
installation (bootstrap.sh, mise, SSH keys, git identity).