From f42c6214a0fd69836726b48efe0f23ef3b7d6b45 Mon Sep 17 00:00:00 2001 From: clawbot <35+clawbot@noreply.example.org> Date: Tue, 10 Nov 2026 22:42:02 +0100 Subject: [PATCH] Make the image prepare its own data directory (closes #262) A host directory mounted at /var/lib/neoirc kept the host's owner, so neoircd could not create state.db and stopped at startup. The image now starts deploy/docker-entrypoint.sh as root. It creates /var/lib/neoirc, gives it and its contents to neoirc with mode 0700, and execs neoircd as neoirc through su-exec. The runtime stage drops USER neoirc and no longer creates the directory at build time. Judgement call: the entrypoint assumes it starts as root; docker run --user fails at chown. Model: opus-5-5 --- Dockerfile | 13 +++++++------ README.md | 21 +++++++++++++++++++-- deploy/docker-entrypoint.sh | 14 ++++++++++++++ 3 files changed, 40 insertions(+), 8 deletions(-) create mode 100755 deploy/docker-entrypoint.sh diff --git a/Dockerfile b/Dockerfile index 0e22ff2..cb998b9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -83,14 +83,15 @@ RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /neoirc-cli ./cmd/neoir # stage's chain and nothing else. # alpine:3.21, 2026-02-26 FROM alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709 -RUN apk add --no-cache ca-certificates \ - && addgroup -S neoirc && adduser -S neoirc -G neoirc \ - && mkdir -p /var/lib/neoirc \ - && chown neoirc:neoirc /var/lib/neoirc +# su-exec 0.2-r3, 2026-11-10 +RUN apk add --no-cache ca-certificates su-exec=0.2-r3 \ + && addgroup -S neoirc && adduser -S neoirc -G neoirc COPY --from=builder /neoircd /usr/local/bin/neoircd +COPY deploy/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh -USER neoirc +# No USER: the entrypoint starts as root to give /var/lib/neoirc to neoirc, +# then runs neoircd as neoirc. EXPOSE 8080 6667 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD wget -qO- http://localhost:8080/.well-known/healthcheck.json || exit 1 -ENTRYPOINT ["neoircd"] +ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] diff --git a/README.md b/README.md index 136a2c3..85155a9 100644 --- a/README.md +++ b/README.md @@ -1790,13 +1790,17 @@ NEOIRC_HASHCASH_BITS=20 the linter first and stops when either fails. The image: - is Alpine with the `neoircd` binary and CA certificates; -- runs as the user `neoirc`; +- runs `neoircd` as the user `neoirc`; - exposes ports 8080 and 6667; - keeps its database in `/var/lib/neoirc`; - has a `HEALTHCHECK` that calls `/.well-known/healthcheck.json` every 30 seconds. -Run it with a volume for the database and the settings as environment variables: +The image prepares `/var/lib/neoirc` itself on every start. It creates the +directory, gives it to `neoirc` and then runs `neoircd` as `neoirc`. + +Run it with a named volume for the database and the settings as environment +variables: ```bash docker run -d --name neoirc \ @@ -1807,6 +1811,17 @@ docker run -d --name neoirc \ neoirc ``` +A host directory works the same way in place of the named volume: + +```bash +docker run -d --name neoirc \ + -p 8080:8080 -p 6667:6667 \ + -v /srv/neoirc:/var/lib/neoirc \ + -e SERVER_NAME="My Server" \ + -e MOTD="Welcome!" \ + neoirc +``` + ### Reverse proxy Run the server behind a reverse proxy that terminates TLS. The server itself @@ -2000,6 +2015,8 @@ and their sessions to end. Then it closes the database. - `schema/`: JSON Schema files for the message envelope, with their own `README.md`. - `script/`: the entrypoints below. +- `deploy/`: `docker-entrypoint.sh`, the image's entrypoint, which prepares + `/var/lib/neoirc` and starts `neoircd` as `neoirc`. - `CONVENTIONS.md`, `REPO_POLICIES.md` and `AGENTS.md`: the architecture conventions, the repository policies and the rules for coding agents. diff --git a/deploy/docker-entrypoint.sh b/deploy/docker-entrypoint.sh new file mode 100755 index 0000000..f26b6c8 --- /dev/null +++ b/deploy/docker-entrypoint.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# deploy/docker-entrypoint.sh: the image's ENTRYPOINT, run as root. A host +# directory mounted at /var/lib/neoirc keeps the host's owner, so this gives +# it to neoirc before running neoircd as neoirc. +set -eu + +main() { + mkdir -p /var/lib/neoirc + chown -R neoirc:neoirc /var/lib/neoirc + chmod 0700 /var/lib/neoirc + exec su-exec neoirc neoircd "$@" +} + +main "$@"