Dev VM bootstrap
Info
Base OS
Ubuntu Server 26.04.1 (installed — same release as the workstation
VM, exact tool parity), minimal install, openssh-server, static
10.0.2.10/24, gw 10.0.2.2 (vpngw — not the host), interface
MTU 1200 (below the udp2tcp tunnel MTU), DNS 10.64.0.1 (Mullvad’s
in-tunnel resolver — public resolvers are hijacked at the exit; set it
in netplan post-install).
Installer creates user devvm (sudo) — that is the operator/admin
account. The agent workspace is a separate devin user created below —
deliberately no sudo, so the agent can’t escalate. Root stays locked
(installer default).
System packages
apt update
apt install -y \
git curl wget ca-certificates openssh-server \
build-essential cmake pkg-config \
python3 python3-venv \
podman uidmap slirp4netns fuse-overlayfs \
jq unzip dos2unix \
vim ranger \
&& apt autoremove -y
User
useradd -m -s /bin/bash devin
loginctl enable-linger devin # user services survive logout
usermod -aG systemd-journal devin # read journals without sudo
Rootless podman works out of the box for devin
(subuid/subgid auto-assigned). Optional but recommended:
systemctl --user --machine=devin@ enable --now podman.socket # as root; targets devin's systemd manager
# add to ~devin/.profile:
# export DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock
User-local tools (~devin/.local/bin)
su - devin
mkdir -p ~/.local/bin
# uv (python envs/tools)
curl -LsSf https://astral.sh/uv/install.sh | sh
# tldr — user-local, via uv (pipx equivalent). apt's python3-tldr also
# works but uv matches the workstation convention.
uv tool install tldr
# github cli — NOT installed: the account is suspended, remotes are
# local bare repos. Skip this on rebuilds unless GitHub comes back.
# ripgrep / fd / bat / fzf — release binaries or cargo/apt as preferred
# (workstation: rg 15.2.0, fd 10.5.0, bat 0.26.1, fzf 0.74.3).
# Not currently installed on devvm — install on demand.
Python
python3-pipdeliberately not installed — uv covers all python package/venv/tool work (a straypip installwould create an env uv can’t see).python3-devabsent too: compiling C extensions against system python fails on missingPython.h. Build under auv python install’d interpreter matching the embedder’s ABI instead — this is how YouCompleteMe’sycm_corewas built (uv python 3.14, matching vim’slibpython3.14). The ycmd server also runs under that uv interpreter — removing it breaks YCM.
devin CLI
curl -fsSL https://cli.devin.ai/install.sh | bash
# lands in ~/.local/share/devin/cli + symlink at ~/.local/bin/devin
# then: devin auth login (manual — see Credentials)
Optional (install if needed)
- Node 24 LTS — merged into
~/.localon the old VM (tarball install) - .NET SDK —
~/.dotnet - kubectl / helm / k9s / kind — only if cluster work happens here
- Dotfiles:
.bash_aliases,.vimrc,.tmux.conf— vm-bootstrap - Node 24 → enables YCM
--ts-completer; .NET →--cs-completer(re-runinstall.pyin~/.vim/plugged/YouCompleteMeunder the uv python after installing)
Credentials (manual, never scripted)
devin auth login- Operator pubkey into
~devvm/.ssh/authorized_keysand~devin/.ssh/authorized_keys— the guest never initiates outbound ssh, so it needs no keypairs of its own. - No
gh— GitHub account suspended; git remotes are local bare repos.
Post-checks
-
ssh devin@10.0.2.10viaProxyJump «HOSTNAME» -
podman run hello-world(rootless) -
devin auth statusshows logged in - Isolation re-verified from inside the VM — see dev-vm