vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Run the server as one container with one volume
b86148d17f5c1b62ca437684b221a56369dd6493 · Keenan Nemetz · 3d ago · parent 04e063ca
Run the server as one container with one volume Vole is one process with its own SSH listener, so it needs no sshd in the image: a published 2222 for Git, a published 8080 for the web, and a volume holding the whole instance. An image cannot install at run time, so the entrypoint runs `vole admin init` first. That command is idempotent, and the same VOLE_CONFIG that serves also makes `docker run <image> admin account list` work. The compose file publishes 8080 on loopback, for the TLS proxy most container hosts already run, and health checks /healthz, which answers 200 there and does not under ACME. CI runners stay outside: they execute repository code and need a real OCI runtime on the host.
deploy/docker/Dockerfile +67
| @@ -0,0 +1,67 @@ | |||
| 1 | # A Vole instance in one container: the server, its own SSH listener, and the | ||
| 2 | # Git it shells out to. Build it from the repository root, because the compiler | ||
| 3 | # needs the source: | ||
| 4 | # | ||
| 5 | # docker build -f deploy/docker/Dockerfile -t vole . | ||
| 6 | # | ||
| 7 | # The base images are pinned the same way .vole/images pins them, so a rebuild | ||
| 8 | # compiles with the toolchain the release uses. The builder is the exact image | ||
| 9 | # the release workflow builds in; the runtime is the distribution the .deb and | ||
| 10 | # .rpm are made for. | ||
| 11 | # | ||
| 12 | # This image is the server only. A CI runner executes repository code in | ||
| 13 | # containers and needs a real OCI runtime on the host, so it belongs on the | ||
| 14 | # machine, not in here. See docs/runner.md. | ||
| 15 | |||
| 16 | FROM golang:1.27.3-bookworm@sha256:972b4110ba0f47539a975c31e52c64765e1ff19f2d74469ae4a595c6676e80a5 AS build | ||
| 17 | |||
| 18 | # The package links SQLite dynamically, so the binary is built against the | ||
| 19 | # system library rather than the driver's bundled copy; the runtime image | ||
| 20 | # installs the matching library below. | ||
| 21 | RUN apt-get update && apt-get install -y --no-install-recommends gcc libsqlite3-dev && rm -rf /var/lib/apt/lists/* | ||
| 22 | |||
| 23 | WORKDIR /src | ||
| 24 | COPY go.mod go.sum ./ | ||
| 25 | RUN go mod download | ||
| 26 | COPY . . | ||
| 27 | |||
| 28 | ARG VERSION=dev | ||
| 29 | RUN CGO_ENABLED=1 go build -tags libsqlite3,sqlite_fts5 -trimpath \ | ||
| 30 | -ldflags "-s -w -X main.version=${VERSION}" -o /out/vole ./cmd/vole | ||
| 31 | |||
| 32 | FROM debian:13-slim@sha256:a72b4433de1cf7d6bae0c4cee74d0547f58601a643b3375f070c51600d63b6b2 | ||
| 33 | |||
| 34 | # git is what the server runs for every push and clone; curl is the health | ||
| 35 | # check. Nothing else is needed: Vole is one process with no database server | ||
| 36 | # beside it. | ||
| 37 | RUN apt-get update && apt-get install -y --no-install-recommends \ | ||
| 38 | ca-certificates curl git libsqlite3-0 \ | ||
| 39 | && rm -rf /var/lib/apt/lists/* | ||
| 40 | |||
| 41 | # The same layout the packages install: a service account that owns the instance | ||
| 42 | # and nothing else, and a state directory under it. Creating the data directory | ||
| 43 | # in the image is what lets a fresh named volume start out owned by that account. | ||
| 44 | RUN groupadd --system vole \ | ||
| 45 | && useradd --system --gid vole --home-dir /var/lib/vole --no-create-home \ | ||
| 46 | --shell /usr/sbin/nologin --comment "Vole software forge" vole \ | ||
| 47 | && install -d -o vole -g vole -m 0750 /var/lib/vole /var/lib/vole/data /etc/vole | ||
| 48 | |||
| 49 | COPY --from=build /out/vole /usr/bin/vole | ||
| 50 | COPY deploy/docker/vole.toml /etc/vole/vole.toml | ||
| 51 | COPY deploy/docker/entrypoint.sh /usr/local/bin/vole-entrypoint | ||
| 52 | |||
| 53 | # Every command in the container finds the instance without being told where it | ||
| 54 | # is: `docker run --rm <image> admin account list` works. | ||
| 55 | ENV VOLE_CONFIG=/etc/vole/vole.toml | ||
| 56 | |||
| 57 | USER vole | ||
| 58 | |||
| 59 | # 2222 is Git over SSH, the only write transport. 8080 is the web interface and | ||
| 60 | # anonymous clone; put a TLS proxy in front of it, or switch the configuration to | ||
| 61 | # https_addr and publish 80 and 443 instead. | ||
| 62 | EXPOSE 2222 8080 | ||
| 63 | |||
| 64 | VOLUME ["/var/lib/vole"] | ||
| 65 | |||
| 66 | ENTRYPOINT ["/usr/local/bin/vole-entrypoint"] | ||
| 67 | CMD ["serve"] | ||