07 December 2025

Debian + Fluxbox Setup (2025 refresh)

— Testing Rolling, Anti-Cinnamon Guardrails

This is a 2025 refresh of my Debian + Fluxbox notes, updated specifically for Debian Testing (rolling). The major addition this year is a set of guardrails to prevent Cinnamon from being installed during upgrades or via meta/task packages, plus a pre-flight step that removes Cinnamon if it already snuck in.

What’s new in this 2025 Testing update

  • Targets Debian Testing (rolling) rather than a fixed stable snapshot.
  • Pre-guardrail cleanup: detect and purge Cinnamon if present.
  • Two-layer anti-Cinnamon safety:
    • Hard APT pin refuses Cinnamon and its task/meta packages.
    • Lean APT defaults disable automatic Recommends/Suggests to prevent surprise DE pulls.
  • Audio modernized: media keys now use wpctl (PipeWire-native), not amixer.
  • Completes the daily-driver baseline: adds CUPS and a Debian-repo browser.

Assumptions

  • Fresh minimal install of Debian Testing.
  • You want Xorg + Fluxbox (not a full desktop environment).
  • You want NetworkManager to own networking.
  • You want a clean, stable lightweight workflow even as Testing evolves.

Install command

Save the script below as debian-fluxbox-setup-testing-2025.sh, then run:

sudo bash debian-fluxbox-setup-testing-2025.sh <username>

One-shot script (2025 Testing rolling)

#!/usr/bin/env bash
###############################################################################
# Debian Testing (rolling) + Fluxbox single-shot setup (2025)
#
# PURPOSE
#   Build a lean, predictable Fluxbox desktop on Debian *Testing* while
#   preventing Cinnamon from being installed now or later, and while using
#   PipeWire-native media keys (wpctl).
#
# BACKGROUND / DESIGN INTENT
#   - Testing is great, but sometimes upgrade churn or meta/task packages can
#     unexpectedly pull in a full desktop environment. You specifically saw
#     Cinnamon being installed and causing issues.
#   - This script adds guardrails and also performs a pre-flight cleanup:
#       1) Detect and remove Cinnamon if it already exists.
#       2) Apply permanent blocks against Cinnamon packages.
#       3) Reduce surprise pulls by disabling auto Recommends/Suggests.
#
# WHAT THIS SCRIPT DOES (STEP-BY-STEP)
#   1) Enable strict shell safety options.
#   2) Validate we are root and a target user exists.
#   3) (Optional hint) Warn if /etc/os-release doesn’t say “testing”.
#   4) Pre-guardrail cleanup:
#        - Detect Cinnamon packages.
#        - Purge task/meta and cinnamon* packages if present.
#        - Autoremove orphaned dependencies.
#   5) Create APT guardrails:
#        a) Disable automatic Recommends/Suggests.
#        b) Pin/ban Cinnamon packages with Pin-Priority -1.
#   6) apt-get update.
#   7) Install a minimal graphical stack:
#        - Xorg + xinit + utilities
#        - Fluxbox + fonts
#   8) Install day-to-day tools:
#        - NetworkManager + nm-applet
#        - Thunar + automount helpers
#        - arandr, numlockx
#        - blueman, cbatticon
#   9) Install audio stack:
#        - PipeWire + WirePlumber + pavucontrol + optional pasystray
#  10) Install printing:
#        - cups + cups-client (+ optional system-config-printer)
#  11) Install a browser from Debian repos:
#        - chromium and/or firefox-esr (whichever is available)
#  12) Enable NetworkManager.
#  13) Rewrite /etc/network/interfaces to loopback-only so NM owns NICs.
#  14) Create user Fluxbox config:
#        - menu
#        - keys (with wpctl volume keys)
#        - startup
#        - .xinitrc
#  15) Post-run verification summary.
#
# HOW TO RUN
#   sudo bash debian-fluxbox-setup-testing-2025.sh <username>
#
# HOW TO UNDO GUARDRAILS (IF YOU EVER WANT TO)
#   sudo rm /etc/apt/apt.conf.d/99lean-desktop
#   sudo rm /etc/apt/preferences.d/no-cinnamon.pref
#
###############################################################################

set -euo pipefail

###############################################################################
# Resolve target username.
###############################################################################
USER_NAME="${1:-${SUDO_USER:-}}"

if [[ -z "${USER_NAME}" ]]; then
  echo "Usage: sudo bash $0 <username>"
  exit 1
fi

###############################################################################
# Root check.
###############################################################################
if [[ "$(id -u)" -ne 0 ]]; then
  echo "Please run as root (use sudo)."
  exit 1
fi

###############################################################################
# User existence check.
###############################################################################
if ! id "${USER_NAME}" >/dev/null 2>&1; then
  echo "User '${USER_NAME}' does not exist."
  exit 1
fi

USER_HOME="$(eval echo "~${USER_NAME}")"

###############################################################################
# Non-fatal OS hint.
###############################################################################
if [[ -r /etc/os-release ]]; then
  if ! grep -qiE 'testing' /etc/os-release; then
    echo "[!] /etc/os-release does not appear to say 'testing'."
    echo "    Continuing anyway (you may be on a testing-derived snapshot)."
  fi
fi

###############################################################################
# Pre-guardrail cleanup: detect and remove Cinnamon if present.
###############################################################################
echo "[*] Checking for existing Cinnamon install..."

CINN_PKGS_INSTALLED="$(
  dpkg -l 2>/dev/null | awk '{print $2}' | \
    grep -E '^cinnamon($|-)|^task-cinnamon-desktop$|^cinnamon-desktop-environment$' || true
)"

if [[ -n "${CINN_PKGS_INSTALLED}" ]]; then
  echo "[!] Cinnamon-related packages detected:"
  echo "${CINN_PKGS_INSTALLED}" | sed 's/^/    - /'

  echo "[*] Purging Cinnamon-related packages..."
  apt-get purge -y \
    task-cinnamon-desktop \
    cinnamon-desktop-environment \
    'cinnamon*' || true

  echo "[*] Autoremoving orphaned dependencies..."
  apt-get autoremove -y || true

  echo "[*] Cinnamon removal complete."
else
  echo "[*] No Cinnamon packages detected."
fi

###############################################################################
# APT guardrails to prevent Cinnamon and reduce surprise DE pulls.
###############################################################################
echo "[*] Creating APT guardrails..."

cat > /etc/apt/apt.conf.d/99lean-desktop <<'EOF'
APT::Install-Recommends "false";
APT::Install-Suggests "false";
EOF

cat > /etc/apt/preferences.d/no-cinnamon.pref <<'EOF'
Package: cinnamon
Pin: release *
Pin-Priority: -1

Package: cinnamon-*
Pin: release *
Pin-Priority: -1

Package: task-cinnamon-desktop
Pin: release *
Pin-Priority: -1

Package: cinnamon-desktop-environment
Pin: release *
Pin-Priority: -1
EOF

###############################################################################
# Update package index after guardrails are in place.
###############################################################################
echo "[*] Updating apt..."
apt-get update

###############################################################################
# Install Xorg + Fluxbox core.
###############################################################################
echo "[*] Installing Xorg + Fluxbox core..."
apt-get install -y \
  xorg \
  xinit \
  x11-xserver-utils \
  xterm \
  fluxbox \
  fonts-dejavu-core

apt-get install -y xbacklight || true

###############################################################################
# Networking: NetworkManager + applet.
###############################################################################
echo "[*] Installing NetworkManager..."
apt-get install -y network-manager

echo "[*] Installing NetworkManager GUI applet/tools..."
apt-get install -y network-manager-gnome || true

apt-get install -y nm-tray || true

###############################################################################
# File manager + display + input utilities.
###############################################################################
echo "[*] Installing file manager and desktop utilities..."
apt-get install -y \
  thunar \
  thunar-volman \
  arandr \
  numlockx

###############################################################################
# Bluetooth + battery tray.
###############################################################################
echo "[*] Installing Bluetooth and battery trays..."
apt-get install -y \
  blueman \
  cbatticon

###############################################################################
# Audio: PipeWire + WirePlumber + control UI.
###############################################################################
echo "[*] Installing PipeWire stack..."
apt-get install -y \
  pipewire-audio \
  wireplumber \
  pavucontrol || true

apt-get install -y pasystray || true

###############################################################################
# Printing: CUPS.
###############################################################################
echo "[*] Installing printing stack (CUPS)..."
apt-get install -y \
  cups \
  cups-client || true

apt-get install -y system-config-printer || true

###############################################################################
# Browser(s) from Debian repos.
###############################################################################
echo "[*] Installing browser(s)..."
apt-get install -y chromium || true
apt-get install -y firefox-esr || true

###############################################################################
# Enable NetworkManager service now and on boot.
###############################################################################
echo "[*] Enabling NetworkManager service..."
systemctl enable --now NetworkManager

###############################################################################
# Make /etc/network/interfaces loopback-only for clean NM ownership.
###############################################################################
echo "[*] Setting /etc/network/interfaces to loopback-only (NM-friendly)..."

if [[ -f /etc/network/interfaces ]]; then
  cp -a /etc/network/interfaces "/etc/network/interfaces.bak.$(date +%Y%m%d%H%M%S)"
fi

cat > /etc/network/interfaces <<'EOF'
# NetworkManager-friendly baseline.
# Loopback only.
source /etc/network/interfaces.d/*

auto lo
iface lo inet loopback
EOF

###############################################################################
# User-level Fluxbox configuration directory.
###############################################################################
echo "[*] Creating Fluxbox config skeleton for ${USER_NAME}..."

install -d -m 0755 "${USER_HOME}/.fluxbox"
chown -R "${USER_NAME}:${USER_NAME}" "${USER_HOME}/.fluxbox"

###############################################################################
# Fluxbox menu.
###############################################################################
if [[ ! -f "${USER_HOME}/.fluxbox/menu" ]]; then
  cat > "${USER_HOME}/.fluxbox/menu" <<'EOF'
[begin] (fluxbox)
  [exec] (Terminal) {xterm}
  [exec] (File Manager) {thunar}
  [exec] (Web Browser - Chromium) {chromium}
  [exec] (Web Browser - Firefox ESR) {firefox-esr}
  [exec] (Network Connections) {nm-connection-editor}
  [exec] (Display Settings) {arandr}
  [exec] (Audio Control) {pavucontrol}
  [exec] (Printers) {system-config-printer}
  [submenu] (System)
    [exec] (Reconfigure) {fluxbox-remote reconfigure}
    [exec] (Restart) {fluxbox-remote restart}
    [exec] (Logout) {fluxbox-remote exit}
  [end]
[end]
EOF
fi

###############################################################################
# Fluxbox keybindings.
###############################################################################
if [[ ! -f "${USER_HOME}/.fluxbox/keys" ]]; then
  cat > "${USER_HOME}/.fluxbox/keys" <<'EOF'
# Basic Fluxbox keybindings

Mod1 Tab :NextWindow (workspace=[current])
Mod1 Shift Tab :PrevWindow (workspace=[current])

Mod1 F4 :Close

Mod1 z :RootMenu
Mod1 Shift z :HideMenus

Mod1 x :ExecCommand xterm

Control Shift n :ExecCommand chromium --incognito

XF86MonBrightnessUp :ExecCommand /usr/bin/xbacklight -inc 5
XF86MonBrightnessDown :ExecCommand /usr/bin/xbacklight -dec 5

XF86AudioLowerVolume :ExecCommand wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
XF86AudioRaiseVolume :ExecCommand wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+
XF86AudioMute :ExecCommand wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
EOF
fi

###############################################################################
# Fluxbox startup file.
###############################################################################
cat > "${USER_HOME}/.fluxbox/startup" <<'EOF'
#!/bin/sh

xset -b

command -v numlockx >/dev/null 2>&1 && numlockx on &

command -v nm-applet >/dev/null 2>&1 && nm-applet &
command -v blueman-applet >/dev/null 2>&1 && blueman-applet &
command -v cbatticon >/dev/null 2>&1 && cbatticon &
command -v pasystray >/dev/null 2>&1 && pasystray &

command -v fbsetbg >/dev/null 2>&1 && fbsetbg -l &

xterm -geometry 120x55+0+0 &

exec /usr/bin/fluxbox
EOF

chmod +x "${USER_HOME}/.fluxbox/startup"

###############################################################################
# .xinitrc for startx-based sessions.
###############################################################################
if [[ ! -f "${USER_HOME}/.xinitrc" ]]; then
  cat > "${USER_HOME}/.xinitrc" <<'EOF'
#!/bin/sh
exec startfluxbox
EOF
  chmod +x "${USER_HOME}/.xinitrc"
fi

chown -R "${USER_NAME}:${USER_NAME}" \
  "${USER_HOME}/.fluxbox" \
  "${USER_HOME}/.xinitrc"

###############################################################################
# Post-run verification.
###############################################################################
echo
echo "=================================================================="
echo "[*] Post-run verification"
echo "=================================================================="

echo
echo "[1/7] Cinnamon packages installed (should be none):"
if dpkg -l | awk '{print $2}' | grep -qE '^cinnamon($|-)|^task-cinnamon-desktop$|^cinnamon-desktop-environment$'; then
  echo "  [!] Cinnamon packages still present:"
  dpkg -l | awk '{print $2}' | grep -E '^cinnamon($|-)|^task-cinnamon-desktop$|^cinnamon-desktop-environment$'
else
  echo "  [✓] none"
fi

echo
echo "[2/7] APT policy for cinnamon (expect Pin-Priority -1):"
apt-cache policy cinnamon 2>/dev/null || echo "  (package not visible in current cache)"

echo
echo "[3/7] APT guardrail files:"
ls -l /etc/apt/apt.conf.d/99lean-desktop /etc/apt/preferences.d/no-cinnamon.pref

echo
echo "[4/7] CUPS packages:"
dpkg -l | awk '{print $2}' | grep -E '^cups$|^cups-client$' || echo "  (cups not installed)"

echo
echo "[5/7] Browser packages:"
dpkg -l | awk '{print $2}' | grep -E '^chromium$|^firefox-esr$' || echo "  (no Debian-repo browser installed)"

echo
echo "[6/7] PipeWire control tool (wpctl):"
command -v wpctl >/dev/null 2>&1 && echo "  [✓] found at: $(command -v wpctl)" || echo "  [!] wpctl not found"

echo
echo "[7/7] wpctl status (may be minimal pre-login):"
if command -v wpctl >/dev/null 2>&1; then
  sudo -u "${USER_NAME}" wpctl status 2>/dev/null || echo "  (no active user PipeWire session yet)"
else
  echo "  (skipped)"
fi

echo
echo "[✓] Setup complete."
echo
echo "Next steps:"
echo "  - Log in as ${USER_NAME}"
echo "  - If not using a display manager, run: startx"
echo "  - Use nm-applet to join Wi-Fi"
echo
echo "Guardrails installed:"
echo "  - /etc/apt/preferences.d/no-cinnamon.pref"
echo "  - /etc/apt/apt.conf.d/99lean-desktop"
echo
echo "To re-enable Recommends/Suggests globally:"
echo "  sudo rm /etc/apt/apt.conf.d/99lean-desktop"
echo
echo "To remove the Cinnamon block:"
echo "  sudo rm /etc/apt/preferences.d/no-cinnamon.pref"
echo "=================================================================="

Additional software (optional, still fits the Fluxbox ethos)

If you want parity with the older “daily driver” list, these still pair nicely with a lightweight setup:

  • Document/PDF: evince
  • Media: vlc
  • Office: libreoffice
  • Locking: xtrlock
  • Optical: xfburn (if you still burn discs)
  • Scanning: simple-scan (if you need it)
  • E-books: calibre

Why I’m comfortable with these guardrails

  • Testing changes quickly. The pin ensures Cinnamon can’t be reintroduced via drift.
  • Lean APT defaults reduce surprises. Install “nice-to-haves” explicitly, when you want them.
  • You can disable this any time. Removing two small files restores default behavior.

Quick troubleshooting

  • Wi-Fi not showing up? Confirm your interfaces aren’t declared in /etc/network/interfaces beyond loopback and that NetworkManager is enabled.
  • wpctl keys not working on first boot? Log into Fluxbox once so your user PipeWire session is active; then test again.
  • Printing not detected? Install model-specific drivers if needed and confirm CUPS is running.

No comments:

Post a Comment