Skip to main content

Deploy Docker Apps on Digital Ocean with Caddy for Automatic HTTPS

This guide shows you how to set up a production-ready Docker server on Digital Ocean with automatic HTTPS using Caddy. Unlike traditional setups with Nginx and Certbot, Caddy handles SSL certificates automatically with zero configuration.

Why Caddy Instead of Nginx?

  • Automatic HTTPS - Obtains and renews Let's Encrypt certificates automatically
  • Zero SSL configuration - No certbot, no cron jobs, no manual renewal
  • Simple syntax - Caddyfile is human-readable vs nginx.conf complexity
  • Built-in reverse proxy - Perfect for Docker containers
  • HTTP/3 support - Modern protocol support out of the box

Architecture Overview

graph TB
    subgraph "Internet"
        Users[Users/Browsers]
        DNS[DNS Provider]
    end
    
    subgraph "Digital Ocean Droplet"
        subgraph "Docker Network"
            Caddy[Caddy Container<br/>Ports 80/443]
            App[Your App Container<br/>Port 3000]
        end
        
        subgraph "Volumes"
            CaddyData[(caddy_data<br/>Certificates)]
            AppData[(app_data<br/>Persistent Storage)]
        end
    end
    
    Users -->|HTTPS| DNS
    DNS -->|A Record| Caddy
    Caddy -->|Proxy| App
    Caddy <-->|Store Certs| CaddyData
    App <-->|Persist Data| AppData
    
    style Caddy fill:#22C55E
    style App fill:#3B82F6

Step 1: Create a Digital Ocean Droplet

Create the Droplet

  1. Log into Digital Ocean and click Create > Droplets
  2. Choose your region (closest to your users)
  3. Select Ubuntu 24.04 LTS
  4. Choose a plan:
    • Basic $6/mo - Good for small apps
    • Basic $12/mo - Recommended for production
  5. Choose SSH keys for authentication (more secure than password)
  6. Click Create Droplet

Connect to Your Droplet

ssh root@YOUR_DROPLET_IP

Step 2: Install Docker

Run these commands to install Docker and Docker Compose:

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Verify installation
docker --version
docker compose version

Step 3: Configure Your DNS

Before Caddy can obtain SSL certificates, your domain must point to your Droplet.

  1. Go to your DNS provider (Cloudflare, Namecheap, etc.)
  2. Add an A Record:
    • Name: @ (or your subdomain like app)
    • Value: Your Droplet's IP address
    • TTL: Auto or 300

Wait a few minutes for DNS propagation.

Step 4: Set Up Your Project

Create Project Directory

mkdir -p /opt/myapp
cd /opt/myapp

Create the Caddyfile

nano Caddyfile

Add the following (replace yourdomain.com with your actual domain):

yourdomain.com {
    reverse_proxy app:3000
    encode gzip zstd
}

That's it! Caddy will automatically obtain SSL certificates from Let's Encrypt, redirect HTTP to HTTPS, proxy requests to your app container, and enable compression.

Create docker-compose.yml

nano docker-compose.yml
services:
  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - web

  app:
    image: your-app-image:latest
    restart: unless-stopped
    environment:
      - NODE_ENV=production
      - PORT=3000
    volumes:
      - app_data:/data
    networks:
      - web

networks:
  web:
    driver: bridge

volumes:
  caddy_data:
  caddy_config:
  app_data:

Step 5: Deploy

docker compose up -d
docker compose logs -f

Within seconds, Caddy will obtain your SSL certificate. Visit https://yourdomain.com and you'll see your app running with HTTPS!

Example: Deploying Flowise AI

Here's a complete example deploying Flowise:

Caddyfile

flowise.yourdomain.com {
    reverse_proxy flowise:3000
    encode gzip zstd
}

docker-compose.yml

services:
  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - web

  flowise:
    image: flowiseai/flowise:latest
    restart: unless-stopped
    environment:
      - PORT=3000
      - FLOWISE_USERNAME=admin
      - FLOWISE_PASSWORD=your-secure-password
      - DATABASE_PATH=/root/.flowise
      - SECRETKEY_PATH=/root/.flowise
      - LOG_PATH=/root/.flowise/logs
      - BLOB_STORAGE_PATH=/root/.flowise/storage
    volumes:
      - flowise_data:/root/.flowise
    networks:
      - web

networks:
  web:

volumes:
  caddy_data:
  caddy_config:
  flowise_data:

Multiple Apps on One Server

Caddy can proxy multiple apps on different subdomains:

Caddyfile

flowise.yourdomain.com {
    reverse_proxy flowise:3000
    encode gzip zstd
}

n8n.yourdomain.com {
    reverse_proxy n8n:5678
    encode gzip zstd
}

api.yourdomain.com {
    reverse_proxy api:8080
    encode gzip zstd
}

docker-compose.yml

services:
  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - web

  flowise:
    image: flowiseai/flowise:latest
    restart: unless-stopped
    volumes:
      - flowise_data:/root/.flowise
    networks:
      - web

  n8n:
    image: n8nio/n8n:latest
    restart: unless-stopped
    environment:
      - N8N_HOST=n8n.yourdomain.com
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://n8n.yourdomain.com
    volumes:
      - n8n_data:/home/node/.n8n
    networks:
      - web

  api:
    image: your-api-image:latest
    restart: unless-stopped
    volumes:
      - api_data:/data
    networks:
      - web

networks:
  web:

volumes:
  caddy_data:
  caddy_config:
  flowise_data:
  n8n_data:
  api_data:

Advanced Caddyfile Options

Basic Authentication

admin.yourdomain.com {
    basicauth * {
        admin $2a$14$hashedpassword
    }
    reverse_proxy admin:3000
}

Generate password hash:

docker run --rm caddy:2-alpine caddy hash-password --plaintext 'your-password'

Custom Headers

yourdomain.com {
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
    }
    reverse_proxy app:3000
}

WebSocket Support

Caddy handles WebSockets automatically, but you can add explicit headers:

yourdomain.com {
    reverse_proxy app:3000 {
        header_up Host {host}
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }
}

Useful Commands

# Start containers
docker compose up -d

# Stop containers
docker compose down

# View logs
docker compose logs -f
docker compose logs caddy

# Reload Caddy without restart
docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile

# Update images
docker compose pull
docker compose up -d

# SSH into container
docker compose exec app sh

Firewall Setup (Recommended)

ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
ufw status

Troubleshooting

Certificate Issues

docker compose logs caddy

# Common issues:
# - DNS not propagated yet (wait a few minutes)
# - Port 80 blocked by firewall
# - Rate limited by Let's Encrypt (wait 1 hour)

App Not Accessible

docker compose ps
docker compose logs app
docker compose exec caddy ping app

Summary

With Caddy + Docker Compose on Digital Ocean, you get:

  • Automatic HTTPS - Zero SSL configuration
  • Simple reverse proxy - One line in Caddyfile
  • Multiple apps - Easy subdomain routing
  • Persistent storage - Docker volumes for data
  • Easy updates - docker compose pull && docker compose up -d
  • Full control - SSH access to your server

The total setup takes about 10 minutes, and you never have to think about SSL certificates again.

Resources

Need help with your project or have questions?

We specialize in AI automation, custom integrations, and intelligent workflows tailored to your business needs.

Whether you need help deploying, building, implementing, or creating a solution - or just want expert guidance on your project - we're here to help.

Contact us today to discuss your project.