> ## Documentation Index
> Fetch the complete documentation index at: https://warden.buildlab.in/llms.txt
> Use this file to discover all available pages before exploring further.

# Container image

> A distroless image of the gateway, and a compose stack that brings up Warden and PostgreSQL together.

## The image

```bash theme={null}
docker pull ghcr.io/abhishek-mallick/warden:latest
```

> [!NOTE]
>
> Images are published by the release workflow when a `vX.Y.Z` tag is pushed. Until the first tagged release, build it locally with `docker build -t warden:local .` — the compose stack does this for you.
>
> Built from a private repository, the package starts **private**, and GitHub has no API for changing that — it is a one-time click in the package's settings page. Until then, pulling needs a `ghcr.io` login.

Built in two stages:

* **Build stage** — `golang:1.25-bookworm`, because a C toolchain is needed: Warden compiles PostgreSQL's own parser, which is what lets it analyse SQL with the server's real grammar rather than a regular expression.
* **Runtime stage** — `gcr.io/distroless/cc-debian12:nonroot`. No shell, no package manager, running as UID 65532. The gateway holds database credentials, so the smallest image that can run it is the right one.

| | |
| - | - |
| Entrypoint | `/usr/local/bin/warden` |
| Default command | `serve --config /etc/warden/warden.yaml` |
| Exposed port | 9470 |
| State directory | `/var/lib/warden`, owned by the runtime user |
| Architectures | `linux/amd64`, `linux/arm64` (native builds, not emulated) |

Mount your configuration and policies read-only, and give the state directory a named volume so the audit chain, leases, and idempotency keys survive a restart:

```bash theme={null}
docker run --rm \
  -p 127.0.0.1:9470:9470 \
  -v "$PWD/warden.yaml:/etc/warden/warden.yaml:ro" \
  -v "$PWD/policies:/etc/warden/policies:ro" \
  -v warden-state:/var/lib/warden \
  ghcr.io/abhishek-mallick/warden:latest
```

> [!WARNING]
>
> There is no shell in the image, so `docker exec … sh` will not work. That is deliberate. Use `warden audit tail` and the control plane from outside the container, or run the binary locally against the same state directory.

## The compose stack

> [!NOTE]
>
> `compose.yaml` lives in the source repository, which is private, so this route needs access to it. Without access, [the quickstart](https://warden.buildlab.in/quickstart.md) puts the same gateway in front of your own database.

It brings up PostgreSQL 17 with a seeded commerce schema and Warden in front of it:

```bash theme={null}
docker compose up --build
```

Two properties worth noticing:

* **The database is not published to the host at all.** Agents reach it through Warden or not at all — the demo enforces its own premise.
* **Warden's port is published to `127.0.0.1` only**, which is the only reason plaintext is acceptable there. Warden refuses a non-loopback listener without TLS unless the configuration says so explicitly.

The demo credentials in `deploy/compose/warden.yaml` are in plain sight on purpose, and the gateway warns about them at startup.

```bash theme={null}
docker compose down -v    # clean slate, including the state volume
```

> [card] [Configuration reference](https://warden.buildlab.in/configure/warden-yaml.md)
>
> Every field of `warden.yaml`, including `data_dir`, TLS, and lease bounds.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.