Part 4 of 6

    CI/CD & Git Workflows

    Connect Dokploy to your Git provider, enable automatic deployments, set up branch-based environments, and master rollbacks.

    25 min read
    GitHub, GitLab, Bitbucket

    Manual deployments work for side projects. Production needs automation. This guide covers connecting Dokploy to your Git provider, automatic deployments on push, branch-based environments, and rollbacks when things go wrong.

    Git Provider Integration

    Dokploy supports GitHub, GitLab, and Bitbucket. The setup flow is similar for each.

    Connecting GitHub

    Two methods available: GitHub App (recommended) or Personal Access Token

    GitHub App Method (Recommended)

    1. Go to Dokploy SettingsGit Providers
    2. Click Install GitHub App
    3. Authorize Dokploy to access your repositories
    4. Select which repos to grant access (all or specific ones)
    5. Complete installation

    Personal Access Token Method

    1. Go to GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)
    2. Generate new token with scopes: repo and admin:repo_hook
    3. Paste token in Dokploy

    Automatic Deployments

    Once your Git provider is connected, enable auto-deploy for your applications.

    1

    Setting Up Auto-Deploy

    1. Go to your application in Dokploy
    2. Open the Git tab
    3. Configure:
      • Repository: Select from your connected repos
      • Branch: main (or your production branch)
      • Auto Deploy: Toggle ON
    4. Save

    Now every push to that branch triggers a deployment.

    How It Works

    1. You push code to GitHub/GitLab/Bitbucket
    2. Git provider sends a webhook to Dokploy
    3. Dokploy pulls the latest code
    4. Docker builds your image
    5. New container replaces the old one
    6. Traffic routes to the new container

    The whole process typically takes 1-5 minutes depending on your build.

    Manual Webhook Setup

    For self-hosted GitLab instances that require manual configuration

    1. Go to your application → Git tab
    2. Copy the Webhook URL
    3. In your Git provider, add a webhook:
      • URL: The copied webhook URL
      • Content type: application/json
      • Events: Push events (and optionally Pull Request events)
      • Secret: Copy from Dokploy if shown

    Branch-Based Deployments

    Production and staging should be separate environments with different configurations.

    Strategy 1: Separate Applications (Recommended)

    Full isolation between environments

    Production App

    • Branch: main
    • Domain: app.yourdomain.com
    • Environment: Production database credentials, NODE_ENV=production

    Staging App

    • Branch: develop or staging
    • Domain: staging.yourdomain.com
    • Environment: Staging database credentials, NODE_ENV=staging

    Staging Database

    Don't share databases between staging and production. Create a separate database service for staging:

    1. Create ServiceDatabasePostgreSQL
    2. Name it staging-db
    3. Use different credentials
    4. Point your staging app at this database

    Preview Deployments for Pull Requests

    Deploy every PR to a temporary environment for review. This requires a bit more setup but is invaluable for teams.

    Manual PR Previews

    1. Create a new application in Dokploy
    2. Set the branch to your PR branch (e.g., feature/new-login)
    3. Set a preview domain: pr-123.preview.yourdomain.com
    4. Deploy

    When the PR merges, delete the preview app.

    Automated PR Previews with GitHub Actions

    .github/workflows/preview.yml
    name: Deploy PR Preview
    
    on:
      pull_request:
        types: [opened, synchronize, reopened]
    
    jobs:
      deploy-preview:
        runs-on: ubuntu-latest
        steps:
          - name: Deploy to Dokploy
            run: |
              curl -X POST \
                -H "Authorization: Bearer ${{ secrets.DOKPLOY_API_TOKEN }}" \
                -H "Content-Type: application/json" \
                -d '{
                  "projectId": "${{ secrets.DOKPLOY_PROJECT_ID }}",
                  "branch": "${{ github.head_ref }}",
                  "domain": "pr-${{ github.event.number }}.preview.yourdomain.com"
                }' \
                https://your-dokploy-server:3000/api/applications/deploy
              
          - name: Comment PR with preview URL
            uses: actions/github-script@v7
            with:
              script: |
                github.rest.issues.createComment({
                  issue_number: context.issue.number,
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  body: '🚀 Preview deployed to https://pr-${{ github.event.number }}.preview.yourdomain.com'
                })

    Note: You'll need to create a Dokploy API token and set up the API endpoint. Check Dokploy's documentation for current API details.

    Wildcard DNS for Previews

    To support dynamic preview subdomains:

    Add wildcard DNS record
    *.preview.yourdomain.com → your-server-ip

    In Dokploy/Traefik, configure wildcard certificate handling (Let's Encrypt supports this via DNS challenge).

    Build Caching

    Slow builds kill productivity. Optimize your Docker builds.

    Layer Caching Basics

    Docker caches each layer. Order your Dockerfile to maximize cache hits.

    Dockerfile ordering
    # Dependencies change less often — cache these
    COPY package.json package-lock.json ./
    RUN npm ci
    
    # Source changes frequently — put last
    COPY . .
    RUN npm run build

    BuildKit Cache Mounts

    Persist downloaded packages across builds

    Cache mounts for package managers
    # npm
    RUN --mount=type=cache,target=/root/.npm npm ci
    
    # pip
    RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt
    
    # composer
    RUN --mount=type=cache,target=/root/.composer/cache composer install

    Enable BuildKit in Dokploy (usually enabled by default):

    export DOCKER_BUILDKIT=1

    Multi-Stage Builds

    Don't ship build tools to production

    Multi-stage Dockerfile
    # Build stage — has all the tools
    FROM node:20 AS builder
    WORKDIR /app
    COPY package*.json ./
    RUN npm ci
    COPY . .
    RUN npm run build
    
    # Production stage — minimal
    FROM node:20-alpine
    WORKDIR /app
    COPY --from=builder /app/dist ./dist
    COPY --from=builder /app/node_modules ./node_modules
    CMD ["node", "dist/index.js"]

    .dockerignore

    Exclude unnecessary files from the build context

    .dockerignore
    .git
    node_modules
    *.md
    .env*
    .DS_Store
    coverage
    .next
    dist

    A smaller build context means faster uploads and builds.

    Deployment Strategies

    Rolling Deployments (Default)

    Dokploy's default behavior:

    1. Build new container
    2. Start new container
    3. Health check passes
    4. Route traffic to new container
    5. Stop old container

    Zero downtime if your health checks work correctly.

    Blue-Green Deployments

    For critical applications, keep the old version running until you're confident:

    1. Deploy to a "green" environment (separate app in Dokploy)
    2. Test the green environment
    3. Switch DNS/load balancer to green
    4. Keep blue running as instant rollback
    5. After confidence period, tear down blue

    Canary Deployments

    Route a percentage of traffic to the new version. This requires a load balancer in front of Dokploy. Use Traefik's weighted routing or an external load balancer like HAProxy.

    Rollbacks

    Deployments fail. Be ready.

    Quick Rollback via Dokploy

    1. Go to your application → Deployments tab
    2. Find the last working deployment
    3. Click Redeploy on that version

    Dokploy rebuilds from that commit and deploys it.

    Preventing Bad Deployments

    • Health checks — Dokploy won't route traffic to unhealthy containers
    • Smoke tests — Run basic tests post-deployment
    • Gradual rollout — Deploy to staging first, always

    Deployment Hooks

    Run commands at specific points in the deployment lifecycle.

    Pre-Build Hook

    Runs before Docker build starts

    Use for: Fetching secrets, generating files, validating configuration

    In Dokploy → Application → Advanced
    echo "Starting build at $(date)"

    Post-Build Hook

    Runs after successful build, before container starts

    Use for: Database migrations, cache warming, Slack notifications

    Notify Slack
    curl -X POST -H 'Content-type: application/json' \
      --data '{"text":"Deployment starting for myapp"}' \
      $SLACK_WEBHOOK_URL

    Post-Deploy Hook

    Runs after container is live and healthy

    Use for: Smoke tests, cache invalidation, success notifications

    Run smoke test and notify
    # Run smoke test
    curl -f https://app.yourdomain.com/health || exit 1
    
    # Notify success
    curl -X POST -H 'Content-type: application/json' \
      --data '{"text":"✅ myapp deployed successfully"}' \
      $SLACK_WEBHOOK_URL

    Monorepo Deployments

    Deploying multiple apps from one repository.

    Subdirectory Builds

    Repository structure
    /
    ├── apps/
    │   ├── frontend/
    │   │   └── Dockerfile
    │   └── backend/
    │       └── Dockerfile
    └── packages/

    In Dokploy, set:

    • Build Context: apps/frontend
    • Dockerfile Path: apps/frontend/Dockerfile

    Create separate Dokploy applications for frontend and backend, each pointing to their subdirectory.

    Triggering Specific Apps

    By default, any push triggers all apps watching the repo. To be selective, use path filters in your CI:

    GitHub Actions path filter
    on:
      push:
        paths:
          - 'apps/frontend/**'
    jobs:
      deploy-frontend:
        # ... deploy frontend only

    Secrets in CI/CD

    Never commit secrets. Here's how to handle them.

    Environment Variables in Dokploy

    Store secrets in Dokploy's environment variables (they're encrypted at rest):

    1. Application → Environment tab
    2. Add sensitive values
    3. They're injected at runtime

    External Secrets

    For more control, use a secrets manager:

    • Infisical — See our guide
    • Vault — HashiCorp's solution
    • AWS Secrets Manager / Parameter Store
    Fetch secrets in post-build hook
    export DATABASE_URL=$(infisical secrets get DATABASE_URL --plain)

    Git-Ignored .env Files

    For local development, use .env files but never commit them:

    .gitignore
    .env
    .env.local
    .env.production

    Use .env.example to document required variables:

    .env.example
    DATABASE_URL=postgresql://user:pass@localhost:5432/myapp
    REDIS_URL=redis://localhost:6379/0
    SECRET_KEY=generate-a-random-string

    Troubleshooting CI/CD

    Webhook not triggering?

    • Check webhook URL is correct in Git provider
    • Verify webhook secret matches
    • Look at webhook delivery logs in GitHub/GitLab
    • Check Dokploy logs: docker logs dokploy

    Build succeeds but deploy fails?

    • Check health check endpoint exists and returns 200
    • Verify container starts correctly: docker logs <container-id>
    • Check port configuration matches

    Slow builds?

    • Review Dockerfile layer ordering
    • Add .dockerignore
    • Use multi-stage builds
    • Enable BuildKit cache mounts

    Wrong branch deploying?

    • Verify branch setting in Dokploy application
    • Check webhook is configured for correct events
    • Look for branch filters in CI config

    What's Next

    Your deployments are automated and recoverable. Part 5 adds visibility:

    Part 5

    Monitoring & Observability

    Integrate Prometheus and Grafana for metrics, Loki for logs, set up health checks and alerting so you know when things break before your users do.

    Related Guides