docs(setup): add Debian 13 dev-VM setup procedure + scripts + devcontainer #220
Reference in New Issue
Block a user
Delete Branch "docs/dev-debian-vm-setup"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Adds a full Debian 13 dev-VM setup procedure (docs/setup/01-dev-debian-vm-setup.md) + 10 modular idempotent setup scripts + a systemd template + a
.devcontainer/spec, in preparation for the new dev VM (10.100.201.21) replacing the WSL-based workflow. Both IDE flows (VSCode Remote-SSH + Devcontainer) and both Node toolchains (nvm on host + devcontainer image) are available — devs pick per task.Adjacent context (does not ship here, planned follow-up):
10.100.201.10) — samedev.compose.yml, deployed by CI onmain. Doc placeholder in §8.6.apf/dotfiles) —~/.zshrc,~/.p10k.zsh,~/.tmux.confversioned.80-dotfiles.shis already structured to fall back to a~/.dotfiles/clone when present.No application-code changes. No CI gate impact (doc + scripts + devcontainer spec only).
What lands
docs/setup/01-dev-debian-vm-setup.mddocs/setup/02-wsl-terminal-setup.md01-wsl-terminal-setup.md. No content change.docs/setup/03-dev-web-stack.md02-dev-web-stack.md. No content change.docs/setup/04-angular-nx-monorepo.md03-angular-nx-monorepo.md. No content change.docs/setup/README.mddocs/setup/folder.docs/setup/scripts/lib.shapt_installskipping already-installed,ensure_lineidempotent append,confirmprompt.docs/setup/scripts/bootstrap.shdocs/setup/scripts/10-base-packages.shdocs/setup/scripts/20-zsh.shzsh-autosuggestions+zsh-syntax-highlighting. Patches~/.zshrc(theme, plugins, fzf hook).docs/setup/scripts/30-cli-tools.shbat eza fd-find ripgrep fzf zoxide ncdu keychain+jq yq httpie make tree htop tmux direnv dnsutils unzip rsync. Symlinks Debian-renamed binaries (batcat→bat,fdfind→fd) into~/.local/binso notes/aliases.zsh works as-is.docs/setup/scripts/40-node.sh.nvmrc(currently 24) + corepack enable + pnpm warmed frompackage.json#packageManager.docs/setup/scripts/50-docker.shdockergroup,docker.serviceenabled at boot. Pinned GPG key + repo line for Debian Trixie.docs/setup/scripts/60-tuning.shfs.inotify.max_user_watches=524288(Vite/Nx watch ceiling), optional 4 GB swapfile, optional hostname rename (only prompts on generic hostnames likedebian13).docs/setup/scripts/70-hardening.shallow OpenSSHonly) + unattended-upgrades on security channel + fail2ban + sshd drop-in (PermitRootLogin no,PasswordAuthentication no,AllowAgentForwarding yes). Probes before applying, validatessshd -tbefore reloading, skips cleanly if infra already locked the box down.docs/setup/scripts/80-dotfiles.shnotes/aliases.zsh→~/.oh-my-zsh/custom/aliases.zsh(backs up an existing target). Copiesnotes/gitconfig.txtto~/.gitconfig, prompts for identity, applies viagit config --global user.name/email.docs/setup/systemd/apf-portal-infra@.service./infra/local/dev.sh upat boot. Install:enable apf-portal-infra@$USER.service..devcontainer/devcontainer.jsonmcr.microsoft.com/devcontainers/typescript-node:1-24-bookworm.docker-outside-of-dockerfeature +--network=apf-portal-devso DNS topostgres/redis/otel-collectorworks.initializeCommandfails fast ifdev.sh uphasn't been run yet. Forwarded ports labelled. Six dev extensions pre-installed..devcontainer/post-create.shcorepack enable && pnpm install --frozen-lockfile.CLAUDE.mdlocal/development) + hybrid sub-mode + the two IDE flows (Remote-SSH / Devcontainer), points at the new VM setup doc and the legacy WSL doc.Key choices
↪ skipfor the no-op cases.~/.ssh/configon the workstation carriesForwardAgent yes; the VM never holds long-lived secrets. Same future pattern for GPG signing (covered in §8.5 as appendix).keychainis installed by30-cli-tools.shas a fallback for scenarios where agent forwarding is not available (CI runners, scripts).apf-portal-devCompose network.initializeCommandfails fast with a clear message if./infra/local/dev.sh uphasn't been run yet — better than puzzlingECONNREFUSEDerrors at runtime.60-tuning.shraises inotify to 524288. Default Debian limit is 8K; Vite/Nx in this monorepo blow past that. The setting is persisted in/etc/sysctl.d/99-apf-portal.confso it survives reboot.LocalForwarddirectives on 5432/6379/4317/4318 expose the VM's infra services aslocalhost:*on the workstation. Latency cost: 5-15 ms per query, fine for daily work; for long-running flows, wrap intmuxor useautossh.Notes for the reviewer
git log --followstill works because ofgit mv. Diff shows up as renames, not delete-and-add.bat eza fd-find ripgrep fzf zoxide docker keychain ncdu git.gitis installed by10-base-packages.sh(every other script needs it). Everything else lives in30-cli-tools.sh+50-docker.sh. The "fullstack-dev extras" (jq yq httpie make tree htop tmux direnv dnsutils unzip rsync) are additions I proposed in the lock-in question and that you greenlit (full scope) — easy to trim if any of them turn out to be unwanted.40-node.sh) and devcontainer in the repo. Devs can use either; both read the same.nvmrc+packageManagerpin so the version stays consistent.apf-portal-infra@.service) — install once, enable per-user (enable apf-portal-infra@$USER.service). This is the right shape for a shared VM with multiple devs eventually, even if today only one user uses it.Test plan
Manual (no automated test exists for this kind of setup work):
git clone …,./docs/setup/scripts/bootstrap.sh, answer prompts, end up with zsh + Powerlevel10k + all the requested CLI tools + Node 24 + pnpm 10.33.4 + Docker on PATH../infra/local/dev.sh upboots successfully against the VM's local docker daemon.pnpm install+pnpm exec nx run-many -t lint test --parallel=3passes on the VM.~/Works/apf_portal, runpnpm exec nx serve portal-bff, confirm reachespostgres:5432.Reopen in Container, image builds,postCreateCommandrunspnpm install, dev server reaches postgres through theapf-portal-devnetwork.pnpm exec nx serve portal-bfflocally, confirm postgres reachable vialocalhost:5432.pnpm exec prettier --checkclean on the touched markdown files.bash -n(syntax check) — verified during writing.What's next
10.100.201.21. Any friction surfaced becomes a follow-up PR (docs(setup): ...).apf/dotfiles) as a small follow-up, then teach80-dotfiles.shto prefer the dotfiles repo overnotes/.git remote set-urldoc updates here, (b)infra/gitlab-runners/replacinginfra/ci-runners.compose.yml.vm-gitlab(10.100.201.10) — CI-driven, separate PR.