Overview
Dokploy can deploy pre-built Docker images directly from container registries, bypassing the build process. This is ideal for:
Pre-built Images - Deploy official images from Docker Hub
CI/CD Integration - Deploy images built in external pipelines
Multi-Architecture - Use registry-built multi-arch images
Private Images - Deploy proprietary images from private registries
Docker Source Type
Configure an application to use Docker images as the source:
{
"name" : "My Application" ,
"sourceType" : "docker" ,
"dockerImage" : "nginx:alpine" ,
"username" : null , // No auth for public images
"password" : null ,
"registryUrl" : null // Defaults to Docker Hub
}
Public Docker Images
Deploy publicly available images without authentication.
Docker Hub
Deploy images from Docker Hub:
{
"sourceType" : "docker" ,
"dockerImage" : "nginx:latest" , // Official image
"dockerImage" : "postgres:16-alpine" , // Official with tag
"dockerImage" : "mycompany/myapp:v1.0.0" // User/org image
}
Official Images
Community Images
// Deploy official nginx
{
"sourceType" : "docker" ,
"dockerImage" : "nginx:1.25-alpine"
}
// Deploy official PostgreSQL
{
"sourceType" : "docker" ,
"dockerImage" : "postgres:16-alpine"
}
// Deploy official Redis
{
"sourceType" : "docker" ,
"dockerImage" : "redis:7-alpine"
}
GitHub Container Registry
Deploy public images from GHCR:
{
"sourceType" : "docker" ,
"dockerImage" : "ghcr.io/organization/image:tag" ,
"registryUrl" : "ghcr.io"
}
Other Public Registries
{
"sourceType" : "docker" ,
"dockerImage" : "quay.io/organization/image:tag" ,
"registryUrl" : "quay.io"
}
{
"sourceType" : "docker" ,
"dockerImage" : "gcr.io/project-id/image:tag" ,
"registryUrl" : "gcr.io"
}
{
"sourceType" : "docker" ,
"dockerImage" : "public.ecr.aws/organization/image:tag" ,
"registryUrl" : "public.ecr.aws"
}
Private Docker Images
Deploy images from private registries with authentication.
Docker Hub Private
Authenticate with Docker Hub:
{
"sourceType" : "docker" ,
"dockerImage" : "mycompany/private-app:v1.0.0" ,
"username" : "dockerhub-username" ,
"password" : "dckr_pat_xxxxxxxxxxxxx" , // Access token
"registryUrl" : "https://index.docker.io/v1/"
}
Create Access Token
Log in to Docker Hub
Go to Account Settings > Security
Click New Access Token
Set description and permissions:
Read - Pull images only
Read, Write - Pull and push images
Copy the token (shown only once)
Configure Application
{
"username" : "your-dockerhub-username" ,
"password" : "dckr_pat_xxxxxxxxxxxxx"
}
GitHub Container Registry Private
Authenticate with GitHub:
{
"sourceType" : "docker" ,
"dockerImage" : "ghcr.io/myorg/private-app:latest" ,
"username" : "github-username" ,
"password" : "ghp_xxxxxxxxxxxxx" , // Personal access token
"registryUrl" : "ghcr.io"
}
Create GitHub Token
Go to GitHub Settings > Developer settings
Click Personal access tokens > Tokens (classic)
Generate new token with scopes:
read:packages - Download packages
write:packages - Upload packages
Copy the token
Configure Authentication
{
"username" : "your-github-username" ,
"password" : "ghp_xxxxxxxxxxxxx" ,
"registryUrl" : "ghcr.io"
}
AWS Elastic Container Registry
Authenticate with AWS ECR:
{
"sourceType" : "docker" ,
"dockerImage" : "123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:latest" ,
"username" : "AWS" ,
"password" : "<ecr-token>" , // Generated token
"registryUrl" : "123456789.dkr.ecr.us-east-1.amazonaws.com"
}
Generate ECR Token
aws ecr get-login-password --region us-east-1
This outputs a token valid for 12 hours.
Configure Application
{
"username" : "AWS" ,
"password" : "eyJwYXlsb2FkIjoiY..." , // Token from step 1
"registryUrl" : "123456789.dkr.ecr.us-east-1.amazonaws.com"
}
AWS ECR tokens expire after 12 hours. Consider using IAM roles or automated token refresh.
Azure Container Registry
Authenticate with Azure ACR:
{
"sourceType" : "docker" ,
"dockerImage" : "myregistry.azurecr.io/myapp:latest" ,
"username" : "myregistry" ,
"password" : "<acr-password>" ,
"registryUrl" : "myregistry.azurecr.io"
}
Enable Admin Access
az acr update --name myregistry --admin-enabled true
Get Credentials
az acr credential show --name myregistry
Use the username and password from the output.
Self-Hosted Registry
Authenticate with private registries:
{
"sourceType" : "docker" ,
"dockerImage" : "registry.example.com:5000/myapp:v1.0.0" ,
"username" : "registry-user" ,
"password" : "registry-password" ,
"registryUrl" : "registry.example.com:5000"
}
Registry Integration
Use configured registry credentials for better management.
Create Registry Configuration
First, add a registry in Dokploy:
curl -X POST https://your-domain.com/api/trpc/registry.create \
-H "x-api-key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"registryName": "Docker Hub Production",
"registryUrl": "https://index.docker.io/v1/",
"username": "dockerhub-user",
"password": "dckr_pat_xxxxx",
"registryType": "cloud"
}'
Deploy with Registry
Dokploy automatically uses configured registries for authentication:
{
"sourceType" : "docker" ,
"dockerImage" : "mycompany/private-app:v1.0.0" ,
// No need to specify username/password if registry is configured
}
Registry credentials are matched by URL and automatically applied during deployment.
Tag Strategies
{
"dockerImage" : "myapp:1.0.0" , // Specific version
"dockerImage" : "myapp:1.0" , // Minor version
"dockerImage" : "myapp:1" , // Major version
}
Best for: Production deployments with controlled updates
{
"dockerImage" : "myapp:latest" // Always pulls latest
}
Best for: Development environments, always get latest changesUsing latest in production can lead to unexpected updates. Pin specific versions.
{
"dockerImage" : "myapp:abc1234" // Specific commit
}
Best for: Reproducible deployments, exact version tracking
Updating Images
Redeploy to pull the latest image:
curl -X POST https://your-domain.com/api/trpc/application.redeploy \
-H "x-api-key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"applicationId": "app-123",
"title": "Update to latest image"
}'
Dokploy will:
Pull the latest version of the image
Stop the current container
Start a new container with the updated image
Multi-Architecture Images
Deploy images that support multiple CPU architectures:
{
"dockerImage" : "nginx:alpine" // Supports amd64, arm64, arm/v7, etc.
}
Docker automatically pulls the correct architecture for your server:
amd64 - x86_64 Intel/AMD processors
arm64 - ARM 64-bit (Apple Silicon, AWS Graviton)
arm/v7 - ARM 32-bit (Raspberry Pi)
arm/v6 - Older ARM devices
Multi-arch images use Docker manifests. The registry sends the correct image variant automatically.
CI/CD Integration
Integrate Dokploy with external CI/CD pipelines.
GitHub Actions
name : Build and Deploy
on :
push :
branches : [ main ]
jobs :
build-and-deploy :
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v4
- name : Build Docker image
run : |
docker build -t mycompany/myapp:${{ github.sha }} .
docker tag mycompany/myapp:${{ github.sha }} mycompany/myapp:latest
- name : Push to Docker Hub
run : |
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
docker push mycompany/myapp:${{ github.sha }}
docker push mycompany/myapp:latest
- name : Deploy to Dokploy
run : |
curl -X POST "https://dokploy.example.com/api/trpc/application.redeploy" \
-H "x-api-key: ${{ secrets.DOKPLOY_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{
"applicationId": "app-123",
"title": "Deploy commit ${{ github.sha }}",
"description": "Deployed from GitHub Actions"
}'
GitLab CI
stages :
- build
- deploy
variables :
IMAGE_TAG : $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
build :
stage : build
script :
- docker build -t $IMAGE_TAG .
- docker tag $IMAGE_TAG $CI_REGISTRY_IMAGE:latest
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker push $IMAGE_TAG
- docker push $CI_REGISTRY_IMAGE:latest
deploy :
stage : deploy
script :
- |
curl -X POST "https://dokploy.example.com/api/trpc/application.redeploy" \
-H "x-api-key: $DOKPLOY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"applicationId": "app-123",
"title": "Deploy '$CI_COMMIT_SHORT_SHA'",
"description": "Pipeline: '$CI_PIPELINE_ID'"
}'
only :
- main
Bitbucket Pipelines
image : docker:latest
pipelines :
default :
- step :
name : Build and Push
services :
- docker
script :
- docker build -t mycompany/myapp:$BITBUCKET_COMMIT .
- docker tag mycompany/myapp:$BITBUCKET_COMMIT mycompany/myapp:latest
- echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin
- docker push mycompany/myapp:$BITBUCKET_COMMIT
- docker push mycompany/myapp:latest
- step :
name : Deploy to Dokploy
script :
- |
curl -X POST "https://dokploy.example.com/api/trpc/application.redeploy" \
-H "x-api-key: $DOKPLOY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"applicationId": "app-123"}'
Image Verification
Verify images before deployment.
Image Scanning
Scan images for vulnerabilities:
# Using Trivy
trivy image mycompany/myapp:latest
# Using Docker Scout
docker scout cves mycompany/myapp:latest
Image Signing
Verify image authenticity:
# Sign with Docker Content Trust
export DOCKER_CONTENT_TRUST = 1
docker push mycompany/myapp:v1.0.0
# Verify signature
docker trust inspect mycompany/myapp:v1.0.0
Configuration Examples
Production Application
{
"name" : "Production API" ,
"sourceType" : "docker" ,
"dockerImage" : "mycompany/api:v2.1.0" ,
"username" : "mycompany" ,
"password" : "dckr_pat_xxxxx" ,
"registryUrl" : "https://index.docker.io/v1/" ,
"env" : "DATABASE_URL=postgresql://... \n REDIS_URL=redis://..." ,
"memoryLimit" : "2048MB" ,
"cpuLimit" : "2" ,
"replicas" : 3 ,
"ports" : [{ "targetPort" : 3000 , "publishedPort" : 3000 }]
}
Staging with Latest
{
"name" : "Staging API" ,
"sourceType" : "docker" ,
"dockerImage" : "mycompany/api:staging" ,
"username" : "mycompany" ,
"password" : "dckr_pat_xxxxx" ,
"env" : "NODE_ENV=staging \n DEBUG=true" ,
"memoryLimit" : "512MB" ,
"cpuLimit" : "0.5" ,
"replicas" : 1
}
Third-Party Service
{
"name" : "Redis Cache" ,
"sourceType" : "docker" ,
"dockerImage" : "redis:7.2-alpine" ,
"command" : "redis-server --appendonly yes" ,
"volumes" : [
{
"source" : "redis-data" ,
"target" : "/data" ,
"type" : "volume"
}
],
"memoryLimit" : "256MB"
}
Best Practices
Image Management
Pin Versions Always use specific tags in production: // Good
"dockerImage" : "nginx:1.25.3-alpine"
// Avoid
"dockerImage" : "nginx:latest"
Small Images Use minimal base images: // Alpine variants are smaller
"dockerImage" : "node:20-alpine"
"dockerImage" : "python:3.12-alpine"
Regular Updates Keep base images updated: # Update monthly
docker pull nginx:1.25-alpine
Clean Tags Remove unused image tags: # Prune old images
docker image prune -a --filter "until=720h"
Security
Scan Images - Use vulnerability scanning before deployment
Private Registries - Store proprietary images in private registries
Access Tokens - Use tokens instead of passwords
Rotate Credentials - Change registry passwords regularly
Least Privilege - Grant minimal registry permissions
Registry Location - Use registries geographically close to servers
Image Layers - Optimize Dockerfile layers for caching
Compress Images - Use tools like docker-slim to reduce size
Parallel Pulls - Enable parallel layer downloads
Troubleshooting
Image Pull Failed - Authentication Required
Symptoms: Error response from daemon: pull access denied for mycompany/private-app
Solutions:
Verify credentials are correct:
docker login -u username -p password
Check username and password in application config
Ensure registry URL matches:
// Docker Hub requires full URL
"registryUrl" : "https://index.docker.io/v1/"
Verify user has access to the repository
Symptoms: Error: manifest for myapp:v1.0.0 not found
Solutions:
Verify image name and tag are correct
Check image exists in registry:
docker manifest inspect mycompany/myapp:v1.0.0
Ensure tag was pushed:
docker push mycompany/myapp:v1.0.0
Try alternative tag (e.g., latest)
Wrong Architecture Pulled
Symptoms: Container fails with “exec format error”Solutions:
Verify server architecture:
uname -m # x86_64, aarch64, armv7l, etc.
Check image supports your architecture:
docker manifest inspect myapp:latest
Build for correct architecture:
docker buildx build --platform linux/amd64 -t myapp:latest .
Use multi-arch images when possible
Symptoms: You have reached your pull rate limit
Solutions:
Authenticate with Docker Hub (increases rate limit)
Upgrade to Docker Hub Pro plan
Use alternative registries (GHCR, Quay.io)
Cache images locally:
docker pull myapp:latest
docker tag myapp:latest localhost:5000/myapp:latest
docker push localhost:5000/myapp:latest
API Reference
Save Docker Provider
curl -X POST https://your-domain.com/api/trpc/application.saveDockerProvider \
-H "x-api-key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"applicationId": "app-123",
"dockerImage": "mycompany/myapp:v1.0.0",
"username": "dockerhub-user",
"password": "dckr_pat_xxxxx",
"registryUrl": "https://index.docker.io/v1/"
}'
Update Docker Image
curl -X POST https://your-domain.com/api/trpc/application.update \
-H "x-api-key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"applicationId": "app-123",
"dockerImage": "mycompany/myapp:v2.0.0"
}'
Next Steps
Registry Configuration Configure container registries
Environment Variables Configure application settings
Build Configuration Build custom images
Monitoring Monitor deployments