Base hardening
Updates, baseline tools, key-only SSH, a UTF-8 locale, and automatic security updates on a fresh Debian box.
Names and addresses are placeholders. The list says what each one stands for.
What it does here
The first login does the dull work everything later assumes: current packages, sudo, key-only SSH, and a locale mosh will accept. Find the box's address with ip a on its console and connect with ssh youruser@<box-ip>.
Canonical setup
Update everything, put your key on the box, turn off password logins, and let security updates install themselves.
sudo apt update && sudo apt full-upgrade -yssh-copy-id youruser@<box-ip>sudo dpkg-reconfigure -plow unattended-upgradesIn this build
- Baseline packages include tmux, mosh and partedMinimal Debian ships none of them, and later cards need all three.
- SSH hardening in a drop-inA file in
sshd_config.dkeeps the change apart from the package's own config. - UTF-8 locale confirmedmosh won't start without one.
- Timezone setUse your own;
timedatectl list-timezoneslists them. - Plain OpenSSH as the way inNot Tailscale SSH, which breaks mosh. See the Tailscale card.
sudo apt install -y sudo curl wget git vim htop ca-certificates \
gnupg lsb-release unattended-upgrades ufw tmux mosh partedsudo tee /etc/ssh/sshd_config.d/10-hardening.conf >/dev/null <<'EOF'
PasswordAuthentication no
PermitRootLogin no
EOF
sudo systemctl restart sshlocale # should show en_US.UTF-8
sudo dpkg-reconfigure locales # if not: generate and select it
sudo timedatectl set-timezone Region/City # e.g. Europe/BerlinOptional: Avahi makes the box answer to devbox.local on the home network. Minimal Debian leaves mDNS out. MagicDNS does the same job from any network, so skip this if you'll always use the tailnet.
sudo apt install -y avahi-daemon libnss-mdns
sudo systemctl enable --now avahi-daemonSeams
Where this meets the rest of the build. Each one leads with what you will actually see.
Symptommosh-server needs a UTF-8 native locale to run
This is the most common mosh failure. Generate and select en_US.UTF-8 with dpkg-reconfigure locales, then reconnect.
Symptomerror opening terminal: xterm-ghostty
The box doesn't have Ghostty's terminfo entry. For this session, export TERM=xterm-256color. To fix it for good, run infocmp -x xterm-ghostty | ssh youruser@devbox -- tic -x - from your own machine, then reconnect.
Symptomdevbox.local stops resolving once UFW is on
mDNS uses UDP 5353, which the firewall blocks. Allow it with sudo ufw allow 5353/udp, or use the MagicDNS name. .local only ever works on the same network.
Symptoma fresh login fails, and the session that worked is closed
Keep your current session open after restarting ssh. Test a new login in a second terminal before closing the first.
Verify
sudo sshd -T | grep -E 'passwordauthentication|permitrootlogin' # both no
locale | head -1 # LANG=en_US.UTF-8
systemctl is-enabled unattended-upgrades # enabled- 17 Oct 2026First written. Verified on Debian 13.6.