Docker Compose Deployment
Compose Deploy gives you full control by letting you paste a raw Docker Compose YAML file. The panel injects Traefik routing, manages DNS, and monitors health — you define everything else.
How It Works
Step 1: Prepare Your Compose File
Navigate to Deploy > Compose Deploy and enter:
| Field | Description |
|---|---|
| Service Name | Name for the service (becomes the subdomain) |
| Customer | Which customer owns this service |
| Docker Compose YAML | Your complete compose configuration |
Step 2: Write or Paste Compose YAML
Enter your Docker Compose file in the editor. You can use magic variables for dynamic values:
version: "3.8"
services:
app:
image: myapp:latest
environment:
- DATABASE_URL=postgresql://{{DB_USER}}:{{DB_PASSWORD}}@db:5432/{{DB_NAME}}
- APP_URL=https://{{DOMAIN}}
volumes:
- app-data:/data
db:
image: postgres:16
environment:
- POSTGRES_USER={{DB_USER}}
- POSTGRES_PASSWORD={{DB_PASSWORD}}
- POSTGRES_DB={{DB_NAME}}
volumes:
- db-data:/var/lib/postgresql/data
volumes:
app-data:
db-data:
Step 3: Deploy
Click Deploy. The panel processes your compose file:
- Substitutes magic variables with generated or configured values
- Injects Traefik labels on the first service (or the service marked with
expose):labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(`myapp.panel.example.com`)"
- "traefik.http.routers.myapp.tls.certresolver=letsencrypt" - Connects to the
aiadminpanelDocker network - Removes any
ports:directives (traffic routes through Traefik) - Pulls images and starts containers
- Monitors health and reports status
Magic Variables
Magic variables are placeholders in your compose file that the panel substitutes at deploy time:
| Variable | Description | Example Value |
|---|---|---|
{{SERVICE_NAME}} | The service name you provided | my-app |
{{DOMAIN}} | Full domain for the service | my-app.panel.example.com |
{{PASSWORD}} | Auto-generated secure password (32 chars) | aB3x... |
{{DB_USER}} | Auto-generated database username | user_a1b2c3 |
{{DB_PASSWORD}} | Auto-generated database password | kL9m... |
{{DB_NAME}} | Database name (derived from service name) | my_app |
{{SECRET_KEY}} | Auto-generated secret key (64 chars) | xY7z... |
{{PORT}} | The exposed port for Traefik routing | 8080 |
You can use the same magic variable multiple times — each occurrence gets the same generated value.
Routing Configuration
By default, Traefik routes to the first service in your compose file on port 80. To customize:
Specify the expose port
Add a label to the service that should receive traffic:
services:
app:
image: myapp:latest
labels:
- "aiadminpanel.expose.port=3000"
Multiple exposed services
If you need to expose multiple services on different subdomains:
services:
frontend:
image: myapp-frontend:latest
labels:
- "aiadminpanel.expose.port=3000"
- "aiadminpanel.expose.subdomain={{SERVICE_NAME}}"
api:
image: myapp-api:latest
labels:
- "aiadminpanel.expose.port=8080"
- "aiadminpanel.expose.subdomain={{SERVICE_NAME}}-api"
This creates two routes:
https://my-app.panel.example.compointing to the frontendhttps://my-app-api.panel.example.compointing to the API
Best Practices
- Always use named volumes for persistent data — anonymous volumes are lost on redeployment
- Never use
ports:— Traefik handles all external routing - Use magic variables for secrets — do not hardcode passwords in compose files
- Set restart policies — use
restart: unless-stoppedfor production services - Include health checks — either in the compose file or via labels for panel monitoring:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
Limitations
- Compose files using
build:contexts are not supported — use pre-built images - Host networking (
network_mode: host) is not supported — use Traefik routing - Privileged containers require the
rawsecurity profile approval - Compose file must be valid YAML — the editor validates syntax before deploy