Customer subdomains can plant cookies on your login site — the `__Host-` prefix stops it

If you host anything customer-controlled under your own domain (say alice.app.example.com) and run your sign-in or billing site on another subdomain (billing.example.com), those customers can set cookies on your billing site. A cookie with Domain=example.com goes to every host under example.com. Signing your cookies doesn't help, because the attacker doesn't need to forge anything.

The attack is login CSRF by "cookie tossing". The attacker signs in to your site and copies their own valid, signed session cookie. A page on their subdomain sends:

Set-Cookie: session=<attacker's valid value>; Domain=example.com; Path=/

A victim opens that page, then visits your billing site. The browser sends the attacker's cookie, so the victim is signed in as the attacker, and whatever they buy is credited to the attacker's account. Having their own session doesn't reliably protect them either: the browser sends both cookies with the same name, and many parsers keep whichever comes last.

Picking a different hostname doesn't help while both hosts share the same registrable domain. The fix is one prefix on the cookie name:

Set-Cookie: __Host-session=<value>; Path=/; Secure; HttpOnly; SameSite=Lax

Browsers only accept a __Host- cookie that has Secure, has Path=/, and has no Domain attribute. It can only be set by the exact host that receives it, so a sibling subdomain can't create or overwrite it. Read and clear the cookie under the same prefixed name. Since the prefix needs Secure, keep an unprefixed name for plain-http local development.

The stronger, structural fix is to serve customer content from a separate registrable domain, the way GitHub uses githubusercontent.com, or to get that domain listed on the Public Suffix List. Either way, cookies stop crossing the boundary at all. __Host- is the change you can ship today.

ssh host 'cmd' Can't Find Your Tool? Set PATH in ~/.pam_environment

ssh vm 'mytool --version' returns command not found while ssh vm followed by the same command works. The tool is installed, the interactive shell is fine — the difference is which startup files the command actually gets.

ssh vm 'command -v mytool'   # nothing, or only /usr/bin tools
ssh -t vm                     # interactive: mytool is right there

sshd runs a remote command as $SHELL -c 'cmd'. That shell is neither login nor interactive, so on Debian it reads neither ~/.profile (login only) nor ~/.bashrc (which returns at its case $- in *i*) ;; *) return;; esac guard). The session keeps sshd's stock PATH=/usr/local/bin:/usr/bin:/bin:/usr/games. Anything you installed to ~/.local/bin — cargo, pipx, uv tool, most Rust and Python tool installers — is invisible. Chasing it in ~/.bashrc won't work, because ~/.bashrc is not read at all.

The fix that survives every session type is PAM, not shell config. /etc/pam.d/sshd already has a pam_env.so user_readenv=1 line, and pam_env re-reads ~/.pam_environment on every session — no sshd edit, no restart:

cat > ~/.pam_environment <<'EOF'
PATH=/home/you/.local/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
EOF
chmod 600 ~/.pam_environment
ssh vm 'command -v mytool'   # resolves now

Two details bite here. pam_env replaces PATH rather than appending, so the file must spell out the full list, not just the directory you care about. And it must use the bare PATH=… form: PATH DEFAULT=… only applies when the variable is unset, and sshd always exports PATH, so DEFAULT would silently do nothing.

Pair it with a block at the very top of ~/.bashrc, above the non-interactive guard, for nested shells and tmux children that do source .bashrc:

for _pb in "$HOME/.local/bin" "$HOME/bin"; do
    [ -d "$_pb" ] && case ":$PATH:" in *":$_pb:"*) ;; *) PATH="$_pb:$PATH" ;; esac
done
unset _pb
export PATH

The case ":$PATH:" check keeps it idempotent, and it matters more than it looks: once pam_env supplies ~/.local/bin, Debian's own unguarded PATH="$HOME/.local/bin:$PATH" in ~/.profile appends it a second time in every login shell. Harmless, but it misleads the next person reading echo $PATH.

The one case PAM cannot cover is a fully stripped environment — env -i mytool or a systemd unit with a hardcoded PATH= — where even login, interactive and ~/.bashrc are all bypassed. There the only options are to make bash read the file (BASH_ENV=/etc/profile) or put the entry in a system directory, e.g. sudo ln -s ~/.local/bin/mytool /usr/local/bin/mytool, which is already on every default PATH.

Check what a session really sees, rather than guessing:

ssh vm 'echo $PATH; command -v mytool'
ssh vm 'bash -lc "echo $PATH; command -v mytool"'   # login shell

SSH Alias Added, Still Denied? Check the Guest's authorized_keys

A Host block only tells SSH where to connect and which key to offer. A new VM can be reachable and still return Permission denied (publickey) until the guest account trusts that public key.

First confirm the client selected the intended host, user, and identity:

ssh -G vm-alias | grep -E '^(hostname|user|identityfile) '

Then, from the VM console or hypervisor, find the account's real home instead of assuming it is /home/$USER; some Lima guests use a suffixed path:

home=$(getent passwd "$(id -un)" | cut -d: -f6)
install -d -m 700 "$home/.ssh"
cat /path/to/client_key.pub >> "$home/.ssh/authorized_keys"
chmod 600 "$home/.ssh/authorized_keys"

Only the client's .pub key belongs on the guest; keep the private key on the client. Test the complete path with:

ssh -o BatchMode=yes vm-alias 'hostname; id -un'

ssh -G validates client configuration, not server-side authorization.

Headless Wi-Fi on Ubuntu-Like Linux? Use `nmcli`

A GUI is not required to configure Wi-Fi on Ubuntu, Debian, or Linux Mint. If NetworkManager is running, nmcli can scan for networks, create a persistent connection profile, and reconnect automatically after reboot.

Scan for nearby networks:

nmcli radio wifi on
nmcli device wifi rescan
nmcli device wifi list

Connect without putting the password in shell history:

read -rsp 'Wi-Fi password: ' WIFI_PASSWORD
echo
sudo nmcli device wifi connect 'SSID_NAME' \
  password "$WIFI_PASSWORD" \
  ifname wlan0
unset WIFI_PASSWORD

Replace SSID_NAME and wlan0 with the network name and wireless interface shown by nmcli device status. NetworkManager saves the new profile and normally enables autoconnect automatically.

Verify the address, route, and connectivity:

nmcli device status
nmcli connection show
ip addr show wlan0
ip route
ping -c 3 1.1.1.1

For a hidden network, add hidden yes; for an open network, omit the password argument. Do not switch networks over SSH unless you have another way back in, because the current connection may drop immediately.

Chinese on a GUI-less Ubuntu server: fbterm for display, fcitx5+rime for input

Your server has no GUI — just the bare console TTY — and you want to read and type Chinese on it. Installing fonts does nothing: the kernel console draws with a ~256-glyph VGA font baked into the driver, so CJK renders as diamonds no matter what you install. The fix has two halves: fbterm draws text onto the framebuffer itself (display), and fcitx5 with its fbterm frontend supplies the input method (typing). Here's the whole setup, including the three gotchas that cost me an evening.

Everything below was done on Ubuntu 24.04 (Mint 22.3) over SSH; the target machine is an old laptop used headless. Swap davidwei for your user.

Display: fbterm

sudo apt install fbterm fonts-wqy-microhei
sudo usermod -aG video $USER   # needed for /dev/fb0; re-login to apply

Log in on the physical console and run fbterm — it opens a full terminal on the framebuffer using fontconfig fonts. It cannot start over SSH (no framebuffer there, and you don't need it: your SSH client renders CJK itself).

Font gotcha #1: fbterm renders TrueType fonts well but tends to clip outline fonts at the right/bottom of the character cell, and --font-width/--font-height only change the cell metrics — they don't scale the glyphs. WenQuanYi Zen Hei Mono with an 8px cell worked for me where Noto CJK and default settings clipped. Put it in ~/.fbtermrc:

font-names=WenQuanYi Zen Hei Mono
font-size=16
font-width=8
…more