configuration for self hosting a spindle in docker
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

CLAUDE.md#

This file provides guidance to Claude Code when working with code in this repository.

What this repo is#

A Docker Compose deployment stack for Spindle (a CI/CD pipeline tool) backed by OpenBao (an open-source HashiCorp Vault fork) for secrets management. Spindle is not developed here — it is cloned from tangled.org/tangled.org/core at tag v1.13.0-alpha and built inside Dockerfile.

Current state#

This stack is actively being tested for first-time deployment on Ubuntu Linux. The init script and Docker config have had several fixes applied and may need further iteration.

Known working:

  • OpenBao starts and reads config correctly
  • init-openbao.sh fixes data volume permissions, restarts OpenBao, and runs the full vault bootstrap

Known issues / things being tested:

  • Full end-to-end stack (openbao → openbao-proxy → spindle) not yet verified
  • Spindle healthcheck is intentionally omitted pending manual testing of its HTTP endpoints

Architecture#

┌──────────┐    AppRole     ┌───────────────┐    KV v2      ┌─────────┐
│  spindle │ ─────────────► │ openbao-proxy │ ─────────────► │ openbao │
│  :6555   │                │   :8201       │                │  :8200  │
└──────────┘                └───────────────┘                └─────────┘
     │
     │ /var/run/docker.sock
     ▼
  Host Docker daemon  (pipeline containers run here)
  • openbao — vault backend, file storage, sealed on every start
  • openbao-proxy — AppRole sidecar, auto-authenticates, token cached at /tmp/openbao-token
  • spindle — CI runner, starts only after proxy is healthy, mounts Docker socket

Key config files#

File Purpose
docker-compose.yml Service definitions, volumes, port bindings, dependency order
Dockerfile Clones tangled.org/core at v1.13.0-alpha, builds with Go, produces Alpine image
config/openbao/server/server.hcl OpenBao server (file storage, TCP listener on 8200, TLS off)
config/openbao/proxy/proxy.hcl Proxy AppRole auto-auth, token sink at /tmp/openbao-token, listener on 8201
config/openbao/spindle-policy.hcl Grants Spindle KV v2 CRUD on spindle/data/* and spindle/metadata/*
init-openbao.sh One-time bootstrap: fixes volume perms, inits vault, enables KV v2, creates AppRole
.env.sample All configurable env vars with defaults — copy to .env before starting

Important implementation details#

  • Config directories are split: config/openbao/server/ and config/openbao/proxy/ are mounted separately so each service only sees its own HCL files. Mixing them caused OpenBao server to fail parsing proxy-specific stanzas.
  • The openbao-data Docker volume is created root-owned by default. init-openbao.sh fixes this with docker compose exec --user root openbao chown -R openbao:openbao /openbao/data before running init.
  • All docker compose exec calls in the init script use -T with </dev/null to prevent stdin hanging.
  • OpenBao port 8200 is bound to 127.0.0.1 only (not exposed to the network).
  • Both OpenBao and its proxy have IPC_LOCK capability to prevent secrets swapping to disk.
  • All images are pinned to SHA256 digests. Spindle source is pinned to commit 3572988b89fa093269ae78e02d7283ee206b6888.

First-time setup#

cp .env.sample .env
# Set SPINDLE_SERVER_HOSTNAME and SPINDLE_SERVER_OWNER in .env

docker compose up -d openbao
# Wait for "seal configuration missing, not initialized" in logs, then:

./init-openbao.sh   # ONE-TIME ONLY — save the unseal key and root token it prints

docker compose up -d

After every restart#

OpenBao seals itself on restart. Unseal before the proxy or Spindle can start:

docker compose exec openbao bao operator unseal -address=http://localhost:8200 <unseal_key>

Verify the stack#

curl http://localhost:8200/v1/sys/health   # OpenBao server (127.0.0.1 only)
curl http://localhost:6555/               # Spindle