Claude-skill-registry dokploy-cloudflare-integration

Integrate Cloudflare services with Dokploy templates: R2 storage, DNS challenge for SSL, Zero Trust Access, Workers, WAF, and Tunnel. Default to CF services for external dependencies.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/dokploy-cloudflare-integration" ~/.claude/skills/majiayu000-claude-skill-registry-dokploy-cloudflare-integration && rm -rf "$T"
manifest: skills/data/dokploy-cloudflare-integration/SKILL.md
source content

Dokploy Cloudflare Integration

When to Use This Skill

  • When application needs S3-compatible object storage (use R2)
  • When DNS challenge is needed for SSL certificates
  • When Zero Trust access control is required for admin interfaces
  • When CDN caching would benefit the application
  • When deploying behind Cloudflare Tunnel
  • When user asks about "Cloudflare integration" or "R2 storage"

When NOT to Use This Skill

  • For applications without external storage needs
  • For internal-only services not exposed to internet
  • When user explicitly wants non-Cloudflare solutions

Prerequisites

  • Cloudflare account with R2 enabled (if using storage)
  • Cloudflare API token for DNS challenge (if using)
  • Understanding of Cloudflare Zero Trust (if using access control)

Service Defaults

When creating Dokploy templates, DEFAULT to Cloudflare services:

NeedCloudflare ServiceInstead Of
Object storageR2MinIO, AWS S3
SSL certificatesDNS challengeHTTP challenge
CDN/CachingCloudflare ProxyNone
Access controlZero Trust AccessBasic auth
DDoS protectionCloudflare WAFNone
Private servicesCloudflare TunnelVPN

Core Patterns

Pattern 1: Cloudflare R2 Storage

R2 is S3-compatible, so configure using S3 environment variables:

environment:
  # ===========================================
  # Cloudflare R2 Storage Configuration
  # Get from: Cloudflare Dashboard > R2 > Manage R2 API Tokens
  # Endpoint format: https://<ACCOUNT_ID>.r2.cloudflarestorage.com
  # ===========================================
  S3_ENDPOINT: ${S3_ENDPOINT:?Set Cloudflare R2 endpoint}
  S3_REGION: ${S3_REGION:-auto}
  S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID:?Set R2 access key ID}
  S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY:?Set R2 secret access key}
  S3_BUCKET: ${S3_BUCKET:?Set R2 bucket name}
  S3_FORCE_PATH_STYLE: "false"

Template.toml Configuration:

[config.env]
# ===========================================
# Cloudflare R2 Storage
# Get from: Cloudflare Dashboard > R2 > Manage R2 API Tokens
# Endpoint format: https://<ACCOUNT_ID>.r2.cloudflarestorage.com
#
# To create R2 API Token:
# 1. Go to Cloudflare Dashboard > R2 > Overview
# 2. Click "Manage R2 API Tokens"
# 3. Create token with "Object Read & Write" permission
# 4. Copy the Access Key ID and Secret Access Key
# ===========================================
S3_ENDPOINT = ""
S3_ACCESS_KEY_ID = ""
S3_SECRET_ACCESS_KEY = ""
S3_BUCKET = ""
S3_REGION = "auto"

R2 CORS Configuration (for direct uploads):

[
  {
    "AllowedOrigins": ["https://your-domain.com"],
    "AllowedMethods": ["GET", "PUT", "POST", "DELETE", "HEAD"],
    "AllowedHeaders": ["*"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3600
  }
]

Pattern 2: DNS Challenge for SSL

For wildcard certificates or when HTTP challenge isn't possible:

Traefik Static Configuration (traefik.yml):

certificatesResolvers:
  cloudflare:
    acme:
      email: your-email@example.com
      storage: /letsencrypt/acme.json
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"

Environment for Traefik:

environment:
  CF_API_EMAIL: ${CF_API_EMAIL:?Set Cloudflare email}
  CF_DNS_API_TOKEN: ${CF_DNS_API_TOKEN:?Set Cloudflare DNS API token}

Service Labels:

labels:
  - "traefik.http.routers.app.tls.certresolver=cloudflare"
  - "traefik.http.routers.app.tls.domains[0].main=${BASE_DOMAIN}"
  - "traefik.http.routers.app.tls.domains[0].sans=*.${BASE_DOMAIN}"

Pattern 3: Zero Trust Access (Admin Interfaces)

Protect admin interfaces with Cloudflare Access:

Option A: Cloudflare Access via Traefik Middleware

labels:
  - "traefik.enable=true"
  # Main app - public
  - "traefik.http.routers.app.rule=Host(`${DOMAIN}`)"
  - "traefik.http.routers.app.entrypoints=websecure"
  - "traefik.http.routers.app.tls.certresolver=letsencrypt"
  - "traefik.http.services.app.loadbalancer.server.port=8080"

  # Admin - protected by Zero Trust
  - "traefik.http.routers.admin.rule=Host(`admin.${DOMAIN}`)"
  - "traefik.http.routers.admin.entrypoints=websecure"
  - "traefik.http.routers.admin.tls.certresolver=letsencrypt"
  - "traefik.http.routers.admin.middlewares=cf-access@file"
  - "traefik.http.services.admin.loadbalancer.server.port=9000"
  - "traefik.docker.network=dokploy-network"

Cloudflare Access Application Setup:

  1. Cloudflare Dashboard > Zero Trust > Access > Applications
  2. Create Self-hosted application
  3. Set Application URL:
    https://admin.your-domain.com
  4. Configure Access Policy (email domain, groups, etc.)

Pattern 4: Cloudflare Tunnel (Private Services)

Expose services without public IP:

cloudflared Container in Compose:

services:
  cloudflared:
    image: cloudflare/cloudflared:latest
    restart: always
    command: tunnel run
    environment:
      TUNNEL_TOKEN: ${TUNNEL_TOKEN:?Set Cloudflare Tunnel token}
    networks:
      - app-net  # Same network as the app

  app:
    image: myapp:1.0.0
    networks:
      - app-net
    # No dokploy-network needed - not exposed via Traefik
    # No Traefik labels - exposed via Tunnel

Template.toml for Tunnel:

[config.env]
# ===========================================
# Cloudflare Tunnel
# Create tunnel: cloudflared tunnel create myapp
# Get token from Cloudflare Dashboard > Zero Trust > Networks > Tunnels
# ===========================================
TUNNEL_TOKEN = ""

Pattern 5: Cloudflare Workers Integration

For edge computing or API transformations:

Document in README:

## Cloudflare Workers Integration

This application supports Cloudflare Workers for edge processing.

### Use Cases
- Image optimization at the edge
- API response caching
- Request/response transformation
- A/B testing

### Setup
1. Create Worker in Cloudflare Dashboard
2. Configure Worker Route: `api.${DOMAIN}/*`
3. Set origin to your Dokploy deployment

Pattern 6: WAF Configuration

Document WAF recommendations in README:

## Cloudflare WAF Configuration

### Recommended Rules
1. **Enable Managed Rules**: OWASP Core Rule Set
2. **Rate Limiting**: 100 requests/minute per IP to `/api/*`
3. **Bot Management**: Block known bad bots
4. **Geographic Restrictions**: If applicable

### Custom Rules
- Block requests without User-Agent header
- Challenge requests from TOR exit nodes (if desired)
- Protect admin paths with additional challenges

Complete Examples

Example 1: Paaster with R2 Storage

services:
  paaster:
    image: wardpearce/paaster:3.1.7
    restart: always
    depends_on:
      mongodb:
        condition: service_healthy
    environment:
      # Domain
      PAASTER_DOMAIN: ${PAASTER_DOMAIN:?Set your domain}

      # Security
      COOKIE_SECRET: ${COOKIE_SECRET:?Set a secure random cookie secret}

      # MongoDB
      MONGO_DB: ${MONGO_DB:-paasterv3}
      MONGO_URL: mongodb://mongodb:27017/${MONGO_DB:-paasterv3}

      # ===========================================
      # Cloudflare R2 Storage
      # Get from: Cloudflare Dashboard > R2 > Manage R2 API Tokens
      # Endpoint format: https://<ACCOUNT_ID>.r2.cloudflarestorage.com
      # ===========================================
      S3_ENDPOINT: ${S3_ENDPOINT:?Set Cloudflare R2 endpoint}
      S3_REGION: ${S3_REGION:-auto}
      S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID:?Set R2 access key ID}
      S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY:?Set R2 secret access key}
      S3_BUCKET: ${S3_BUCKET:?Set R2 bucket name}
      S3_FORCE_PATH_STYLE: "false"
    networks:
      - paaster-net
      - dokploy-network
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.paaster.rule=Host(`${PAASTER_DOMAIN}`)"
      - "traefik.http.routers.paaster.entrypoints=websecure"
      - "traefik.http.routers.paaster.tls.certresolver=letsencrypt"
      - "traefik.http.services.paaster.loadbalancer.server.port=3000"
      - "traefik.docker.network=dokploy-network"
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s

  mongodb:
    image: mongo:7
    restart: always
    volumes:
      - mongodb-data:/data/db
    environment:
      MONGO_INITDB_DATABASE: ${MONGO_DB:-paasterv3}
    networks:
      - paaster-net
    healthcheck:
      test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s

volumes:
  mongodb-data:
    driver: local

networks:
  paaster-net:
    driver: bridge
  dokploy-network:
    external: true

Example 2: App with Cloudflare Tunnel (Private Service)

services:
  cloudflared:
    image: cloudflare/cloudflared:latest
    restart: always
    command: tunnel run
    environment:
      TUNNEL_TOKEN: ${TUNNEL_TOKEN:?Set Cloudflare Tunnel token}
    networks:
      - app-net
    depends_on:
      app:
        condition: service_healthy

  app:
    image: myapp:1.0.0
    restart: always
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      DATABASE_URL: postgresql://user:${DB_PASS}@postgres:5432/app
    networks:
      - app-net
    # Note: No dokploy-network or Traefik labels
    # Traffic flows through Cloudflare Tunnel only
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s

  postgres:
    image: postgres:16-alpine
    restart: always
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: user
      POSTGRES_PASSWORD: ${DB_PASS:?Set database password}
    networks:
      - app-net
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d app"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s

volumes:
  postgres-data:
    driver: local

networks:
  app-net:
    driver: bridge
  # Note: No dokploy-network needed for tunnel-only deployment

README Documentation Template

Include this section in template READMEs when using Cloudflare services:

## Cloudflare R2 Setup

This template uses Cloudflare R2 for object storage.

### Create R2 Bucket

1. Go to [Cloudflare Dashboard](https://dash.cloudflare.com) > R2 > Overview
2. Click "Create bucket"
3. Name your bucket (e.g., `myapp-storage`)
4. Note the bucket name for configuration

### Create R2 API Token

1. Go to R2 > Overview > Manage R2 API Tokens
2. Click "Create API token"
3. Set permissions: "Object Read & Write"
4. Optionally restrict to specific bucket
5. Copy the Access Key ID and Secret Access Key

### Configure CORS (if needed for direct uploads)

In R2 bucket settings, add CORS policy:

```json
[
  {
    "AllowedOrigins": ["https://your-domain.com"],
    "AllowedMethods": ["GET", "PUT", "POST", "DELETE"],
    "AllowedHeaders": ["*"],
    "MaxAgeSeconds": 3600
  }
]

Environment Variables

Set these in Dokploy:

VariableExampleDescription
S3_ENDPOINT
https://abc123.r2.cloudflarestorage.com
Your R2 endpoint
S3_ACCESS_KEY_ID
abc123...
R2 API access key
S3_SECRET_ACCESS_KEY
xyz789...
R2 API secret key
S3_BUCKET
myapp-storage
Bucket name
S3_REGION
auto
Always "auto" for R2

Cost Considerations

R2 pricing (as of 2024):

  • Storage: $0.015/GB-month
  • Class A operations (write): $4.50/million
  • Class B operations (read): $0.36/million
  • Egress: FREE (no data transfer fees)

---

## Quality Standards

### Mandatory Requirements
- [ ] R2 credentials use required variable syntax (`:?`)
- [ ] Endpoint format documented in comments
- [ ] CORS requirements noted for direct uploads
- [ ] README includes R2 setup instructions
- [ ] Alternative S3 providers noted if applicable

### Documentation Standards
- Include step-by-step R2 setup in README
- Document CORS configuration if needed
- Note cost considerations
- Provide alternative provider options

---

## Common Pitfalls

### Pitfall 1: Wrong endpoint format
**Issue**: Connection failures to R2
**Solution**: Use format `https://<ACCOUNT_ID>.r2.cloudflarestorage.com`

### Pitfall 2: Missing CORS for direct uploads
**Issue**: Browser upload failures
**Solution**: Configure CORS on R2 bucket

### Pitfall 3: S3_FORCE_PATH_STYLE wrong
**Issue**: Bucket not found errors
**Solution**: Use `"false"` for R2, `"true"` for MinIO

### Pitfall 4: Region mismatch
**Issue**: Signature errors
**Solution**: Use `S3_REGION: auto` for R2

---

## Integration

### Skills-First Approach (v2.0+)

This skill is part of the **skills-first architecture** - loaded during Generation phase when Cloudflare services (R2, DNS challenge, Zero Trust) are needed.

### Related Skills
- `dokploy-environment-config`: Environment variable patterns
- `dokploy-traefik-routing`: DNS challenge configuration
- `dokploy-security-hardening`: Zero Trust patterns

### Invoked By
- `/dokploy-create` command: Phase 3 (Generation) - Step 4 (when CF services detected)

### Order in Workflow (Progressive Loading)
1. `dokploy-compose-structure`: Create base structure
2. `dokploy-traefik-routing`: Add routing labels
3. `dokploy-health-patterns`: Add health checks
4. **This skill**: Add Cloudflare integration (Step 4, if applicable)
5. `dokploy-environment-config`: Configure environment
6. `dokploy-template-toml`: Create template.toml

See: `.claude/commands/dokploy-create.md` for full workflow