Run your AI assistant in a local secure container
Why shall you run your coding assistant in a container
Coding assistants have stopped being autocomplete: they now install packages, edit files and run shell commands, all with your credentials on your machine.
An agent can wipe your home directory, exfiltrate secrets, fall for prompt injection, run malicious skills, and act on irreversible operations without asking1. One may use Docker sandboxes (sbx) to run them in an isolated environment so they can work unattended. This article describes a lightweight, dependency-free alternative using only systemd, similar to the [build container][/blog/build-in-nspawn] presented earlier.
What systemd-nspawn gives you
systemd-nspawn gives you:
- an up-to-date distribution, in a chroot that systemd manages for you
- a developer environment where you can install anything you want (pip, npm...)
- easy access to the journal from the host
- a secure place for running any command without trouble
About systemd-nspawn
If you already read [Build in a systemd-nspawn container][/blog/build-in-nspawn], the procedure is quite similar.
For general information about systemd-nspawn, see:
systemd-nspawn(1)andsystemd.nspawn(5)manpages- Archlinux wiki
The container is a directory under /var/lib/machines that systemd boots. One
file controls it: the nspawn config (/etc/systemd/nspawn/<name>.nspawn).
Creation
For a Debian based distribution (host or target), follow builder
creation for usage of debootstrap.
I personally use Archlinux and opencode as coder assistant, I can use pacstrap to initialize a new Archlinux container which I call coder:
# cd /var/lib/machines
# mkdir coder
# pacstrap -K -c coder/ base base-devel opencode
The container now exists in /var/lib/machines/coder.
Users
Before using the container, set a password for root and create a normal user.
Create the user with the same uid/gid as the host account (use $ id -u ). Mine is
1337:
# cd /var/lib/machines
# systemd-nspawn -D ./coder
# passwd
# useradd -m coder -u 1337 -U -s /bin/bash
# passwd coder
# logout
Configure the mount point
Edit /etc/systemd/nspawn/coder.nspawn (the file name must match the container name in
/var/lib/machines/).
[Files]
# mount a host directory, mapping uid/gid so the mount is owned by the
# container's user instead of nobody
Bind=/home/louson/projects/publicproject:/home/coder/publicproject:idmap
Without the idmap option, the mount point is owned by the user nobody.
Network
If the host runs systemd-networkd and systemd-resolved, the network is automatic. Enable and start them:
# systemctl enable --now systemd-networkd.service
# systemctl enable --now systemd-resolved.service
Otherwise, either configure the NAT or disable virtual networking:
[Network]
# no virtual ethernet: the container shares the host network
VirtualEthernet=no
Now start and login to the container:
# machinectl start coder
# machinectl login coder
Check the network is up, and update the system.
Considerations
- Do not install
git. The coding assistant may run unfortunate git commands and destroy your history. Instead, rungitcommands from the host. - Avoid binding or installing credentials such as private ssh keys to the container, keep those confidential.
- Limit binds to what is strictly necessary. Don't include private data or NDA source code. If you need an assistant for private data, running a local model is possible.