Skip to content

Reverse Proxy

How traffic reaches Sartiq services — routing, SSL, and how to add new proxy entries.


Overview

All external traffic to Sartiq backend services goes through a Caddy reverse proxy running as a Docker container on the backend VM. Caddy handles:

  • SSL termination — automatic HTTPS via Let's Encrypt, zero configuration
  • Domain routing — maps subdomains to internal services
  • WebSocket proxying — automatic, no extra config needed
Internet → Caddy (:80/:443) → Backend API (:8000)
                             → Compute API (:9000)
                             → Admin Panel (:8000)

Configuration

The proxy is configured via a Caddyfile in the deployment repo:

shootify-deployment/
├── GCP-Backend-staging/
│   ├── Caddyfile              ← proxy routes
│   └── docker-compose.yml     ← includes caddy service
├── GCP-Backend-production/
│   ├── Caddyfile
│   └── docker-compose.yml

Current Staging Routes

staging-api.sartiq.com {
    reverse_proxy localhost:8000
}

staging-app-admin.sartiq.com {
    reverse_proxy localhost:8000
}

compute-api-staging.sartiq.com {
    reverse_proxy localhost:9000
}

Adding a New Proxy Entry

Step 1: Edit the Caddyfile

Open the Caddyfile for the target environment and add a new block:

# Add this to the Caddyfile
my-new-service.sartiq.com {
    reverse_proxy localhost:3000
}

If the service runs on a different machine, use its internal IP:

my-new-service.sartiq.com {
    reverse_proxy 10.0.1.5:3000
}

Step 2: Add DNS record in Cloudflare

In the Cloudflare dashboard for sartiq.com:

  • Type: A
  • Name: my-new-service (or staging-my-new-service for staging)
  • Content: the backend VM's static IP (from terragrunt output backend_external_ip)
  • Proxy status: DNS only (grey cloud) — Caddy handles SSL, not Cloudflare

Step 3: Deploy

Push the Caddyfile change to main. CI/CD will SCP it to the VM and restart Caddy. SSL certificates are obtained automatically on first request.

Alternatively, deploy manually:

ssh ubuntu@<backend-ip>
cd /home/ubuntu/services/shootify-deploy
docker compose up -d caddy

Caddy detects the Caddyfile change and reloads without downtime.


Common Patterns

Path-based routing

Route different paths to different backends:

api.sartiq.com {
    reverse_proxy /compute/* compute-server:9000
    reverse_proxy * localhost:8000
}

Strip a path prefix

Forward /api/v2/* to a backend that expects requests at /:

api.sartiq.com {
    handle_path /api/v2/* {
        reverse_proxy localhost:8001
    }
}

Add response headers

api.sartiq.com {
    header Cache-Control "no-store"
    reverse_proxy localhost:8000
}

Redirect old domain

old-api.sartiq.com {
    redir https://api.sartiq.com{uri} permanent
}

Basic auth for internal tools

internal-tool.sartiq.com {
    basic_auth {
        admin $2a$14$... # bcrypt hash
    }
    reverse_proxy localhost:8080
}

Generate a bcrypt hash with: caddy hash-password


Docker Compose Service

The Caddy service in docker-compose.yml:

services:
  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy-data:/data        # SSL certificates
      - caddy-config:/config

The caddy-data volume stores SSL certificates. Do not delete this volume — it contains your Let's Encrypt account and certificates.


Troubleshooting

Check Caddy logs

docker compose logs caddy

Verify Caddyfile syntax

docker compose exec caddy caddy validate --config /etc/caddy/Caddyfile

Force certificate renewal

docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile

SSL certificate not working

  • Ensure the DNS record exists and points to the correct IP
  • Ensure ports 80 and 443 are open in the GCP firewall
  • Check Caddy logs for ACME errors