8.0 KiB
Moving CodeCraft to another host (Unraid)
This guide moves a running installation – Docker volume codecraft-data on the current host –
to another Docker host that keeps its data in bind mounts, for example Unraid. The script
scripts/move-server.sh does the work; this page explains what goes where, what to prepare and
how to check and roll back.
What lives where
| Part | Contents | Today (Docker volume) | On the new host |
|---|---|---|---|
| Data | database codecraft.db, config.toml (incl. API keys), daily backups |
codecraft-data:/data |
<dir>/data → /data |
| Agent installs | the agent's home /data/home: toolchains (Rust, …), pip/pipx/npm/cargo packages, downloaded programs (~/opt), caches |
inside the volume | <tools-dir>/home → /data/home |
| Users' homes | homes of sandboxed users /data/users/<name>/home (their installs, git settings) |
inside the volume | <tools-dir>/users → /data/users |
| Temporary files | /tmp of agents, builds, downloads |
container layer | <tools-dir>/tmp → /tmp |
| Workspace | your projects | WORKSPACE from .env |
--workspace path → /workspace |
| Image | the program | registry image | registry image |
The image never changes: the container runs without root (no apt, no sudo), so agents can
only install into their home directory. With --tools-dir everything agents install or
download lands on a separate disk (e.g. an SSD); the data folder keeps only the database,
configuration and backups. If the tools disk is lost, agents simply install what they need
again – nothing important is on it. (Backups contain the database and configuration, not the
agent home.)
Sizes on 2026-11-09 for orientation: agent home 2.2 GB (of which downloaded programs 1.3 GB, Rust toolchain 0.8 GB), database/config/backups about 1.2 GB.
Before you start
On the new host (Unraid):
- SSH with a key from the current host, without a password prompt. Check from the current
host:
ssh root@unraid true(no output, no question = fine). - docker, rsync and tar available (all three are on Unraid by default).
- Docker Compose is optional: without it the script starts the container with the generated
start.sh(Unraid: the "Docker Compose Manager" plugin adds Compose). - The tools disk is mounted, e.g. an SSD via Unassigned Devices under
/mnt/disks/ssd. - Registry access: the image comes from
git.familie-zink.org/zink/codecraft. If the pull is refused, rundocker login git.familie-zink.orgon Unraid once.
Decide:
| Question | Option | Example |
|---|---|---|
| Folder for data, compose file and scripts | target root@host:/dir |
/mnt/user/appdata/codecraft |
Folder for agent installs and /tmp |
--tools-dir |
/mnt/disks/ssd/codecraft |
| Your projects | --workspace |
/mnt/user/projects |
| Owner of files (the container runs as this user) | --uid, --gid |
Unraid default 99/100 (nobody:users); today 1000/1000 |
| Docker of the new host for agents and terminals | --docker-sock |
bind mount of /var/run/docker.sock plus its group (see below) |
| Port and address | --port, --bind |
8787; 0.0.0.0 if the reverse proxy runs on another machine or in another Docker network, 127.0.0.1 if it runs on the same host with host networking |
Moving
On the current host, in the repository folder (where .env is):
# 1. Look at the steps first (changes nothing)
scripts/move-server.sh root@unraid:/mnt/user/appdata/codecraft \
--workspace /mnt/user/projects --tools-dir /mnt/disks/ssd/codecraft \
--uid 99 --gid 100 --bind 0.0.0.0 --docker-sock --dry-run
# 2. Move (same command without --dry-run)
scripts/move-server.sh root@unraid:/mnt/user/appdata/codecraft \
--workspace /mnt/user/projects --tools-dir /mnt/disks/ssd/codecraft \
--uid 99 --gid 100 --bind 0.0.0.0 --docker-sock
What happens:
- Checks: docker/tar/rsync on the target; the target data folder (and
home/,users/in the tools folder) must be empty – the script never overwrites. - Workspace, first pass with rsync while CodeCraft keeps running (the long part).
- Stops CodeCraft here. Running agents and terminals end. The container is only stopped, not removed.
- Data volume is streamed with tar over SSH into
<dir>/data; with--tools-dirthe agent home and the users' homes are then moved to the tools folder. - Workspace, second pass: only what changed since step 2.
- Owner of data, tools and workspace set to
--uid:--gid(needs root on the target). - Writes
<dir>/docker-compose.yml,<dir>/.env(your.envwith the new paths, port and owner),<dir>/start.sh(the same asdocker run, for hosts without Compose) and<dir>/docker/seccomp-sandbox.json. - Starts the image
CODECRAFT_VERSIONfrom.env(Compose, elsestart.sh). - Smoke test on the target (
scripts/smoke-test.sh): health, version, web UI, terminal client download.
Afterwards:
- Reverse proxy: point the proxy host for
code.familie-zink.org(Nginx Proxy Manager) to the new host and port; keep WebSocket support on. - Check in the web UI: sign in, open a chat, check the status LEDs (providers, MCP servers),
let an agent run
git statusin a project (credentials, identity), open a terminal tab. Models or MCP servers on the old host's LAN address orlocalhostneed new addresses. - Clean up on the old host when everything works:
docker rm codecraft, laterdocker volume rm codecraft-data.
Docker socket (--docker-sock)
With --docker-sock the container gets the new host's Docker: /var/run/docker.sock is bind
mounted and the container joins the socket's group (the script reads its group id on the
target). This is root-equivalent access to the host: whoever can start containers can mount
any host folder.
- Admins' agents and terminals (they run without sandbox) can use it.
- Sandboxed users do not see the socket (the sandbox does not mount
/var/run). dockeranddocker-composecommands always need an approval, except in bypass mode.- The image has no Docker CLI; agents install the static CLI into their home when they need it
(on the tools disk with
--tools-dir).
The current host has the same setup in its local docker-compose.override.yml (group 997).
Rollback
Nothing is deleted on the old host. On Unraid stop the new container (docker stop codecraft),
on the old host start the old one (docker start codecraft) and point the reverse proxy back.
Changes made on the new host in the meantime (chats, settings) are not in the old installation.
Running it on the new host
In <dir> on Unraid:
| Task | With Compose | Without Compose |
|---|---|---|
| Update | set CODECRAFT_VERSION in .env, then docker compose pull && docker compose up -d |
set CODECRAFT_VERSION in .env, docker pull …:<version>, then ./start.sh |
| Restart | docker compose restart |
docker restart codecraft |
| Logs | docker compose logs -f |
docker logs -f codecraft |
| Check | bash smoke-test.sh http://127.0.0.1:8787 <version> |
same |
Releases are published from the development machine with scripts/release.sh; the new host
only pulls them.
Troubleshooting
data on the target is not empty: an earlier attempt left files. Move<dir>/data(andhome/,users/in the tools folder) away and run the script again.- Image pull refused:
docker login git.familie-zink.orgon the target, thencd <dir> && docker compose up -d(or./start.sh). - Smoke test fails:
docker logs codecrafton the target. The old installation is stopped but intact –docker start codecrafton the old host brings it back. could not chown: the SSH user is not root; set the owner by hand (chown -R 99:100 <dir>/data <tools-dir> <workspace>).- Permission denied inside the container: data, tools and workspace must belong to the
UID/GIDin<dir>/.env. - Port already in use: change
PORTin<dir>/.envand start again.