Deploy TokenPak with Docker¶
This guide is for developers who want to build the TokenPak v1.30.1 image and
run its proxy from Docker on the host's loopback interface. The image's default
tokenpak serve command binds to loopback inside the container, so publishing
port 8766 alone does not make that listener reachable from the host.
Prerequisites¶
- A checkout of the public TokenPak v1.30.1 tag.
- The
git,docker,curl, andopensslcommands. - Docker Compose v2 if you want to use the optional Compose procedure.
- An unused host port 8766 and permission to run local containers.
1. Check out v1.30.1¶
Check out the released source:
git checkout v1.30.1
2. Build the image¶
Build the source checkout as tokenpak:v1.30.1:
docker build -t tokenpak:v1.30.1 .
The shipped Dockerfile uses Python 3.11. It does not declare a configurable base-image build argument.
3. Create the proxy credential¶
Generate the Bearer credential that every non-localhost client must present:
export TOKENPAK_PROXY_AUTH_TOKEN="$(openssl rand -hex 32)"
Keep this shell open for the remaining steps.
4. Run a proxy reachable from the host¶
Bind the proxy to all interfaces inside the container, publish it only on the host's loopback interface, and require a proxy credential:
docker run --rm -d --name tokenpak-proxy \
-p 127.0.0.1:8766:8766 \
-e TOKENPAK_BIND_ADDRESS=0.0.0.0 \
-e TOKENPAK_PROXY_AUTH_TOKEN="$TOKENPAK_PROXY_AUTH_TOKEN" \
tokenpak:v1.30.1 python -m tokenpak.proxy.server
The host-side loopback publish keeps the service off the LAN. Docker bridge traffic is non-localhost traffic from the proxy's perspective, so the Bearer credential is still required.
5. Verify the deployment¶
Call the host-published health endpoint with the credential from step 3:
curl -H "Authorization: Bearer $TOKENPAK_PROXY_AUTH_TOKEN" \
http://127.0.0.1:8766/health
The deployment is ready when the response includes "status": "ok" and
"version": "1.30.1".
Optional custom configuration¶
Built-in defaults are used when TOKENPAK_CONFIG is omitted. To replace the
running container with one that mounts a specific configuration, first create
the host file, then stop the current container and pass the file's container
path explicitly:
test -f "$PWD/config/config.yaml"
docker stop tokenpak-proxy
docker run --rm -d --name tokenpak-proxy \
-p 127.0.0.1:8766:8766 \
-e TOKENPAK_BIND_ADDRESS=0.0.0.0 \
-e TOKENPAK_PROXY_AUTH_TOKEN="$TOKENPAK_PROXY_AUTH_TOKEN" \
-e TOKENPAK_CONFIG=/app/config/config.yaml \
-v "$PWD/config/config.yaml:/app/config/config.yaml:ro" \
tokenpak:v1.30.1 python -m tokenpak.proxy.server
Proxy authentication and provider authentication are separate. The
Authorization: Bearer value above authenticates a non-localhost client to
TokenPak and is stripped before forwarding. Configure provider credentials
separately through the client or the proxy's provider credential settings.
Optional Docker Compose deployment¶
The repository's v1.30.1 docker-compose.yml is not an out-of-the-box
host-facing deployment recipe: it retains the container-loopback entrypoint
and requires ./config/config.yaml. Do not use that file unchanged for host
access.
For a minimal host-loopback deployment, save this as compose.host.yml:
services:
tokenpak:
image: tokenpak:v1.30.1
container_name: tokenpak-proxy
command: ["python", "-m", "tokenpak.proxy.server"]
ports:
- "127.0.0.1:8766:8766"
environment:
TOKENPAK_BIND_ADDRESS: "0.0.0.0"
TOKENPAK_PROXY_AUTH_TOKEN: "${TOKENPAK_PROXY_AUTH_TOKEN:?set TOKENPAK_PROXY_AUTH_TOKEN}"
restart: unless-stopped
Then stop any single-container deployment and start Compose with the credential created in step 3:
docker stop tokenpak-proxy 2>/dev/null || true
docker compose -f compose.host.yml up -d
docker compose -f compose.host.yml ps
Add a read-only config mount and TOKENPAK_CONFIG only when the host file
actually exists, as shown in the single-container recipe.
Health and diagnostics¶
Inspect the Dockerfile health check:
docker inspect --format '{{json .State.Health}}' tokenpak-proxy
Run a container-local check with Python. The slim image does not include
curl, and a request from container loopback does not require proxy auth:
docker exec tokenpak-proxy python -c \
"import urllib.request; print(urllib.request.urlopen('http://127.0.0.1:8766/health', timeout=5).read().decode())"
View process output through Docker rather than assuming an application log path inside the image:
docker logs --tail 100 tokenpak-proxy
docker logs -f tokenpak-proxy
Resource limits¶
Docker can apply CPU and memory limits without changing TokenPak. Replace the running single-container deployment with the limited alternative:
docker stop tokenpak-proxy
docker run --rm -d --name tokenpak-proxy \
--cpus 1 --memory 512m \
-p 127.0.0.1:8766:8766 \
-e TOKENPAK_BIND_ADDRESS=0.0.0.0 \
-e TOKENPAK_PROXY_AUTH_TOKEN="$TOKENPAK_PROXY_AUTH_TOKEN" \
tokenpak:v1.30.1 python -m tokenpak.proxy.server
Stop or remove the container¶
The --rm single-container recipe removes the stopped container while keeping
the locally built image:
docker stop tokenpak-proxy
For the Compose recipe:
docker compose -f compose.host.yml down
Deployment boundary¶
Kubernetes, public reverse proxies, and cloud container services require the
same two controls: a non-loopback bind inside the container and a configured
TOKENPAK_PROXY_AUTH_TOKEN presented by every non-localhost client. TokenPak
v1.30.1 does not ship a separately verified Kubernetes or cloud-service
manifest, so this guide does not present those platform-specific snippets as
copy-paste deployment recipes.
Never expose port 8766 publicly without proxy authentication and an external TLS boundary.