The recommended way to run a shared server. The official image is published on the GitHub Container Registry, so the host needs nothing but Docker. Use Compose for a real deployment behind HTTPS, or the Docker Desktop GUI to evaluate on a single machine.
The official image is ghcr.io/nightship-io/nightshipd.
It runs --data-dir /data --port 8080 on its own, so the only
thing you must provide is a persistent volume for /data. A
Docker Hub mirror is published as nightshipio/nightshipd for
Docker Desktop’s search bar.
nightshipd part — Drydock just wires it up automatically
(and adds bundled storage) for a one-click local demo. Here you set it up
yourself, for a real deployment.
This is the recommended setup for a server other people use. It runs
nightshipd behind Caddy,
which fetches and renews a Let’s Encrypt certificate automatically.
Caddy is just a sensible default — swap it for nginx, Traefik, or your
existing ingress; nightshipd only speaks plain HTTP and
doesn’t care what is in front of it. (More in
Terminate TLS with a reverse proxy (Caddy).)
Save this as docker-compose.yml:
services:
nightshipd:
image: ghcr.io/nightship-io/nightshipd:latest
restart: unless-stopped
volumes:
- nightship-data:/data # persistent: users, tokens, builds
caddy:
image: caddy:2
restart: unless-stopped
ports: ["80:80", "443:443"]
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-data:/data
- caddy-config:/config
depends_on: [nightshipd]
volumes:
nightship-data:
caddy-data:
caddy-config:
And a Caddyfile next to it — point the domain’s DNS record at this host first:
builds.example.com {
reverse_proxy nightshipd:8080
}
A fresh server has no accounts. Mint an admin token before starting the stack — these one-shot commands write into the same data volume the server uses:
docker compose run --rm nightshipd user create admin --role admin --data-dir /data
docker compose run --rm nightshipd token create my-laptop --user admin --data-dir /data
The second command prints a token once — copy it. Full detail, and the other ways to bootstrap, are in Bootstrap the first admin.
docker compose up -d
Then in the desktop app: Servers → Add server →
https://builds.example.com, and Set token with the
value from above. To update later:
docker compose pull && docker compose up -d
(see Upgrade nightshipd).
systemd setup
runs the same server straight from the binary.
Prefer not to touch a command line? You can run the same official image entirely through the Docker Desktop interface. This is ideal for evaluating on a single machine; for a shared, internet-facing server use the Compose setup above so you get HTTPS in front.
Nearly everything happens in Docker Desktop’s own windows. The one exception is minting the first admin token — that has no button anywhere (local access to the data directory is the root of trust, by design), but Docker Desktop’s built-in Exec tab runs it without you opening a separate terminal.
Use Docker Desktop’s search bar (it searches Docker Hub) for
nightshipio/nightshipd — the Docker Hub mirror of the
canonical ghcr.io/nightship-io/nightshipd — and pull the
latest tag.
On the image, click Run → Optional settings and set:
nightshipd8080); it maps to the container’s 8080.nightship-data, Container path /data. Typing a bare name rather than a folder path makes it a persistent named volume — this is where users, tokens, and builds live, and it survives container restarts and recreations.--data-dir /data --port 8080 on its own.Click Run. The container should report healthy within a few seconds and show its port as <your-port>:8080.
Open http://localhost:<your-port>/api/version in a browser — you should see a small JSON response with the version.
Click the running nightshipd container, open its Exec tab
(labelled Terminal in some versions), and run these two lines. Because
this shell is inside the running server, it writes straight into the
same /data the server reads — there is no separate volume
to get wrong:
nightshipd user create admin --role admin --data-dir /data
nightshipd token create my-laptop --user admin --data-dir /data
The second command prints a token once — copy it.
In the desktop app: Servers → Add server →
http://localhost:<your-port>, then Set token
with the value from step 4. The Admin page loads and you are running a
Docker-hosted server from the UI.
docker run one-shot, it must mount the exact
same named volume (nightship-data): a bare
docker run -v nightship-data:/data and a Compose-managed volume
(<project>_nightship-data) are different volumes,
and a token written to the wrong one produces 401 even though it
reported “created”. And inside the Exec tab the server is on
8080 — the container’s own port, not the host
port you published; use the host port only from your browser and the app.