A Caddy module that automatically synchronizes your reverse proxy configurations with Twingate, enabling secure Zero Trust access to your services.
This module scans your Caddy reverse proxy routes and automatically creates corresponding Twingate resources. When you add or update reverse proxy configurations in your Caddyfile, the module syncs them to Twingate so they're accessible through your Zero Trust network.
Download the latest release for your platform from the Releases page.
Supported Platforms:
- Linux: amd64, arm64, armv6, armv7
- FreeBSD: amd64
# Make it executable (Linux/macOS/FreeBSD)
chmod +x caddy
# Run it
./caddy run --config CaddyfileRequires Go 1.25+ and xcaddy.
# Install xcaddy
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
# Build Caddy with this module
xcaddy build --with github.com/EngineeredDev/twingate-caddy
# Run
./caddy run --config CaddyfileDocker images are available from GitHub Container Registry.
Supported Platforms:
- linux/amd64: x86_64 64-bit
- linux/arm64: ARM 64-bit (including Apple Silicon via Docker Desktop)
# Pull the latest image
docker pull ghcr.io/engineereddev/twingate-caddy:latest
# Or pull a specific version
docker pull ghcr.io/engineereddev/twingate-caddy:v0.0.1
# Run with a Caddyfile from your host
docker run -d \
--name twingate-caddy \
-p 80:80 \
-p 443:443 \
-e TWINGATE_API_KEY=your_api_key_here \
-v $(pwd)/Caddyfile:/etc/caddy/Caddyfile \
-v caddy_data:/data \
-v caddy_config:/config \
ghcr.io/engineereddev/twingate-caddy:latestDocker Compose Example:
version: '3.8'
services:
twingate-caddy:
image: ghcr.io/engineereddev/twingate-caddy:latest
container_name: twingate-caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "2019:2019" # Admin API (optional)
environment:
- TWINGATE_API_KEY=${TWINGATE_API_KEY}
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
volumes:
caddy_data:
caddy_config:- Log in to your Twingate Admin Console
- Navigate to Settings → API
- Generate a new API token
- Set the API token as the
TWINGATE_API_KEYenvironment variable - Note your tenant name (subdomain in your Twingate URL)
Add the Twingate configuration block to your Caddyfile:
{
twingate {
tenant "your-company" # Required: Your Twingate tenant name
remote_network "Caddy-Resources" # Optional: Remote network (defaults to "Caddy-Managed")
caddy_address "192.168.1.100" # Optional: Caddy server address for Twingate
resource_cleanup {
enabled true # Optional: Auto-delete resources not in Caddyfile
}
}
}
# Your reverse proxy configurations
api.example.com {
reverse_proxy localhost:8080
}
app.example.com {
reverse_proxy /api/* localhost:3000
reverse_proxy /admin/* localhost:3001
}- Scans your Caddy configuration for
reverse_proxydirectives - Extracts route patterns (hosts, paths) and upstream destinations
- Creates or updates Twingate resources in your specified remote network
- Resources are named after the route pattern and point to the upstream address
- Re-syncs automatically when Caddy configuration is reloaded
For each reverse proxy route, a Twingate resource is created:
- Name: The source route (e.g.,
api.example.com,app.example.com/api/) - Address: The Caddy server's outbound address (auto-detected or manually set via
caddy_address)
Example:
{
twingate {
tenant "your-company"
caddy_address "192.168.1.100" # Optional: Set manually, otherwise auto-detected
}
}
api.example.com {
reverse_proxy http://localhost:3000
}Creates a Twingate resource:
- Name:
api.example.com - Address:
192.168.1.100(the Caddy server's address, not the upstream)
If resource_cleanup.enabled is true, the module will delete any resources in the remote network that aren't defined in your Caddyfile. Use a dedicated remote network for Caddy-managed resources to avoid accidentally deleting manually created resources.
- Host-based:
api.example.com { reverse_proxy localhost:8080 } - Path-based:
reverse_proxy /api/* localhost:3000 - Wildcards:
*.dev.example.com { reverse_proxy localhost:9000 } - Load balancing:
reverse_proxy localhost:8001 localhost:8002 - Handle blocks:
handle /v1/* { reverse_proxy localhost:8100 }
See examples/Caddyfile for more patterns.
caddy run --config Caddyfile --log-level debugAPI Connection Failed
- Verify the
TWINGATE_API_KEYenvironment variable is set - Verify tenant name is correct
- Check network access to
https://{tenant}.twingate.com/api/graphql/
No Resources Created
- Ensure
reverse_proxydirectives exist in your Caddyfile - Verify the
TWINGATE_API_KEYenvironment variable is set and has permissions to create resources and networks
Resources Not Updating
- Reload Caddy config:
caddy reload --config Caddyfile - Check logs for sync errors
- The API key is read from the
TWINGATE_API_KEYenvironment variable for security - Never commit API keys to version control
- Use dedicated remote networks to isolate Caddy-managed resources
- Review and apply appropriate Twingate access policies to created resources
- The
resource_cleanupfeature will delete resources - use with caution
MIT License - see LICENSE for details.