From 7c35608e092e646187b6d5322091ba76efe21e68 Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Wed, 22 Jul 2026 01:13:53 +0000 Subject: [PATCH 1/2] fix(docker): make quick-start compose run as non-root against a writable /data The documented `docker compose -f docker/docker-compose.yml up -d` quick-start crash-looped on first start. The image runs as non-root uid 1654 (app), but Docker creates the named volume's `/data` mount point as root:root 0755 (there is no `/data` in the image to inherit ownership from). The app cannot create the SQLite database there, so DatabaseInitializer/SchemaMigrator fails with `SQLite Error 14: 'unable to open database file'` and the container exits. Fix, compose-only (no image rebuild required): - Add a one-shot `init-data` service that runs as root (`user: "0:0"`) and chowns `/data` to 1654:1654 before the server starts. The server now gates on it via `depends_on: condition: service_completed_successfully`. The app itself still runs as non-root uid 1654, and data persists in the named volume. - Point the image at `ghcr.io/netclaw-dev/skillserver:0.4.0` instead of the local-only `skillserver:latest` tag, so a fresh clone can actually pull and `docker compose up` out of the box. - Set an explicit project `name: skillserver` so the stack no longer inherits the ambiguous `docker` project name from its parent directory. Verified from a clean state: reaches healthy, runs as uid 1654 (non-root), and the SQLite DB survives a `down` (without -v) + `up` restart. --- docker/docker-compose.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 80f03e9..c8e6d83 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,6 +1,22 @@ +name: skillserver + services: + # The image runs as non-root uid 1654 (app), but Docker creates the named + # volume's mount point as root:root, so the app can't create the SQLite DB. + # This one-shot init container fixes ownership before the server starts. + init-data: + image: ghcr.io/netclaw-dev/skillserver:0.4.0 + user: "0:0" + volumes: + - skill-data:/data + entrypoint: ["sh", "-c", "chown -R 1654:1654 /data"] + restart: "no" + skill-server: - image: skillserver:latest + image: ghcr.io/netclaw-dev/skillserver:0.4.0 + depends_on: + init-data: + condition: service_completed_successfully ports: - "8080:8080" volumes: From 10e002b0458fcfea6f6ba29e1d7887b4f59a3693 Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Tue, 21 Jul 2026 21:13:45 -0500 Subject: [PATCH 2/2] Update Docker images to use 'latest' tag Signed-off-by: Aaron Stannard --- docker/docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index c8e6d83..6bff9d3 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -5,7 +5,7 @@ services: # volume's mount point as root:root, so the app can't create the SQLite DB. # This one-shot init container fixes ownership before the server starts. init-data: - image: ghcr.io/netclaw-dev/skillserver:0.4.0 + image: ghcr.io/netclaw-dev/skillserver:latest user: "0:0" volumes: - skill-data:/data @@ -13,7 +13,7 @@ services: restart: "no" skill-server: - image: ghcr.io/netclaw-dev/skillserver:0.4.0 + image: ghcr.io/netclaw-dev/skillserver:latest depends_on: init-data: condition: service_completed_successfully