Skip to content

Deploy to Dokploy

Dokploy is a self-hosted PaaS that uses Traefik as its built-in reverse proxy. Since Traefik is already running, trupu only needs Docker labels — no extra Traefik config files required.

  • A running Dokploy instance
  • A domain for the registry (e.g. registry.example.com) with a DNS A record pointing to your Dokploy server’s IP address
  • A GitHub repository with Actions enabled

In the Dokploy dashboard:

  1. Go to ProjectsCreate Project
  2. Give it a name (e.g. trupu)
  3. Inside the project, click Create ServiceCompose
  4. Set the source to Raw
  5. Copy the contents of docker-compose.dokploy.yml into the editor

Replace registry.example.com with your actual domain and set your trusted publishers directly in the compose:

services:
trupu:
image: ghcr.io/nmerget/trupu:latest
environment:
PORT: '3000'
# TODO: Change to your owner/repo:workflow.yml
ALLOWED_PUBLISHERS: 'your-org/your-repo:publish.yml'
# TODO: Change to https://your-registry-domain.com
OIDC_AUDIENCE: 'https://registry.example.com'
networks:
- dokploy-network
labels:
- traefik.enable=true
- traefik.http.services.trupu-server.loadbalancer.server.port=3000
registry:
image: registry:2
ports:
- '127.0.0.1:6000:5000'
environment:
REGISTRY_STORAGE_DELETE_ENABLED: 'true'
volumes:
- registry-data:/var/lib/registry
networks:
- dokploy-network
labels:
- traefik.enable=true
# TODO: Change registry.example.com to your registry domain
- traefik.http.routers.trupu-registry.rule=Host(`registry.example.com`)
- traefik.http.routers.trupu-registry.entrypoints=websecure
- traefik.http.routers.trupu-registry.tls=true
- traefik.http.routers.trupu-registry.tls.certresolver=letsencrypt
- traefik.http.routers.trupu-registry.middlewares=trupu-auth
- traefik.http.routers.trupu-registry.service=trupu-registry-svc
- traefik.http.services.trupu-registry-svc.loadbalancer.server.port=5000
# ForwardAuth middleware
- traefik.http.middlewares.trupu-auth.forwardauth.address=http://trupu:3000/auth
- traefik.http.middlewares.trupu-auth.forwardauth.authResponseHeaders=X-Trupu-Repository,X-Trupu-Workflow,X-Trupu-Ref,Www-Authenticate
volumes:
registry-data:
networks:
dokploy-network:
external: true

The key values to change:

  • Host(\registry.example.com`)` — the domain you configured in DNS for the registry
  • OIDC_AUDIENCE — use https:// + your registry domain (e.g. https://registry.example.com)
  • ALLOWED_PUBLISHERS — your owner/repo:workflow.yml

Click Deploy in Dokploy. This will:

  1. Pull the ghcr.io/nmerget/trupu image from GitHub Packages
  2. Pull the registry:2 image
  3. Connect both services to the dokploy-network
  4. Register the Traefik labels for routing and ForwardAuth

Dokploy’s Traefik will automatically:

  • Route registry.example.com to the Docker registry
  • Apply the trupu-auth ForwardAuth middleware on every request
  • Provision a Let’s Encrypt TLS certificate for your domain

See the GitHub Actions Workflow reference for a complete example workflow. Set the REGISTRY env variable to your registry domain from Step 2.

GitHub Actions ──► Traefik (Dokploy) ──► trupu (/auth) ──► Docker Registry
TLS + ForwardAuth OIDC verify stores images
  • Dokploy’s Traefik handles TLS termination and certificate management
  • The trupu-auth ForwardAuth middleware intercepts every request to the registry
  • trupu verifies the GitHub OIDC token and checks the publisher allow-list
  • On success, Traefik proxies the request to the registry

The docker-compose.dokploy.yml differs from the local development setup:

FeatureLocal (docker-compose.yml)Dokploy (docker-compose.dokploy.yml)
trupuBuilt from DockerfilePre-built image from ghcr.io
TraefikIncluded as a serviceUses Dokploy’s built-in Traefik
RoutingFile provider (traefik/)Docker labels
TLSSelf-signed (Traefik default)Let’s Encrypt via Dokploy
NetworkDefault compose networkdokploy-network (external)
Domainlocalhost:5000Your custom domain

The registry’s port 5000 is bound to 127.0.0.1:6000 on the host — accessible from the server itself but not from the internet. External traffic goes through Traefik with OIDC auth, while internal services pull directly via localhost without authentication.

Other Dokploy compose services can pull images using localhost:6000:

services:
app:
image: localhost:6000/my-image:latest
networks:
- dokploy-network
networks:
dokploy-network:
external: true

Add localhost:6000 to the Docker daemon’s insecure registries on your Dokploy server (the registry runs plain HTTP internally).

Edit /etc/docker/daemon.json:

{
"insecure-registries": ["localhost:6000"]
}

Then restart Docker:

Terminal window
sudo systemctl restart docker

The Docker registry does not automatically clean up deleted image layers. Over time, unreferenced blobs accumulate and waste disk space. Use Dokploy’s built-in Schedule Jobs to run garbage collection on a schedule.

  1. In the Dokploy dashboard, open your trupu Compose service
  2. Go to the Schedule Jobs tab
  3. Create a new Compose Job targeting the registry service
  4. Set Shell Type to Sh
  5. Set the command to:
Terminal window
registry garbage-collect /etc/docker/registry/config.yml --delete-untagged
  1. Set the cron schedule — for example 0 3 * * * to run daily at 3 AM
  2. Save the job

The --delete-untagged flag also removes manifests that are no longer referenced by any tag.

To preview what would be deleted without removing anything, create a separate job or run it once with:

Terminal window
registry garbage-collect /etc/docker/registry/config.yml --delete-untagged --dry-run

Check the job’s execution logs in Dokploy to see which blobs are eligible for deletion.