Tutorials
Run the agent with Docker
Run the Kepeink agent as a Docker container in the same compose project as your app — no host install, no port forwarding, with exact env and networking.
Run the agent with Docker
Run the agent as a container registry.kepeink.hu/agent:2 in the same compose project as the service you want to expose. One service block, one env var, no host install.
Image
registry.kepeink.hu/agent:2
Anonymous pull (no docker login), multi-arch (amd64/arm64/arm), major-pinned (:2 always points to the latest release — docker compose pull is how you update). Exact immutable tags like 2.5.41 exist too.
Exact required runtime env:
| Variable | Value | Notes |
|---|---|---|
KEPEINK_AGENT_TOKEN | kpt_… from the tunnel you created | The only required input |
Baked defaults you do not need to set: KEPEINK_AGENT_NO_SUPERVISOR=1, KEPEINK_AGENT_AUTO_UPDATE=0 (image immutability is the update model — pull a new image, don't self-update inside the container), KEPEINK_AGENT_DIR=/tmp (stateless; certs/caches are ephemeral — see end-to-end TLS note).
Minimal compose snippet
Same compose file (or docker-compose.override.yml) as your app — being in the same file puts the agent on the same network automatically:
services:
kepeink-agent:
image: registry.kepeink.hu/agent:2
restart: unless-stopped
environment:
KEPEINK_AGENT_TOKEN: ${KEPEINK_AGENT_TOKEN}
# .env next to compose file
KEPEINK_AGENT_TOKEN=kpt_xxxxxxxx
docker compose up -d kepeink-agent
docker compose logs -f kepeink-agent
One-liner without compose (uses host network's egress only — no --network host needed):
docker run -d --name kepeink-agent --restart unless-stopped \
-e KEPEINK_AGENT_TOKEN=kpt_… registry.kepeink.hu/agent:2
Networking: pick the target that the agent container can actually resolve
The container needs only egress to the internet. The tunnel target is how the agent reaches your app — choose the one the agent container can resolve:
| App location | Tunnel target (set in dashboard or POST /api/v1/tunnels) | Why |
|---|---|---|
| Service in same compose project | http://<service-name>:<port>, e.g. http://web:3000 or http://immich-server:2283 | Same Docker network → DNS name resolves inside the agent container |
| Service on the host (not in Docker) | http://host.docker.internal:<port> + add extra_hosts: ["host.docker.internal:host-gateway"] to the agent service | Bridge-to-host gateway |
| Service in a different compose project | Attach the agent to that project's network: networks: [other_default] with other_default: { external: true } | Otherwise the DNS name is not visible |
http://localhost:<port> inside the agent container means the agent container itself — it will 502. Join the right network and use the service name instead.
Verify
curl -fsS https://<your-sni>/ # the hostname the tunnel creation returned
docker compose logs kepeink-agent | grep -i session
Toggle the tunnel without redeploying the agent: POST /api/v1/tunnels/{id}/enabled {"enabled": false|true}.
Notes
docker compose pull && docker compose up -d kepeink-agentis the update path. Do not enable in-container self-update.- For end-to-end TLS,
KEPEINK_AGENT_DIR=/tmpis ephemeral — the Let's Encrypt cert is cached under that dir, so a container recreate re-issues it (first request ≈ 15 s). Mount a volume at/tmp(or setKEPEINK_AGENT_DIRto a mounted path) if you want it to survivedocker compose down. - More: Expose a local web app, Expose Immich with Docker, Turn on end-to-end TLS, API quickstart at
https://manage.kepeink.hu/llms.txt.