better-openclaw supports automatic reverse proxy configuration with either Caddy or Traefik. Both proxies provide automatic HTTPS via Let’s Encrypt and route services to subdomains.
Choosing a reverse proxy
Select your reverse proxy when generating a stack:
Interactive
Non-interactive
npx create-better-openclaw
# Select proxy: caddy or traefik
Caddy configuration
Caddy provides zero-config HTTPS with automatic certificate management.
Generated files
When you select Caddy, the generator creates:
Caddyfile - Reverse proxy routes for all exposed services
docker-compose.yml - Caddy service with port mappings
Caddyfile structure
Each service with exposed ports gets a subdomain route:
# PostgreSQL
# Relational database with full SQL support
postgresql.example.com {
reverse_proxy postgresql:5432 {
header_up Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
}
# Root domain serves OpenClaw gateway
example.com {
reverse_proxy openclaw:18789 {
header_up Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
}
Global options
The Caddyfile includes automatic HTTPS configuration:
Custom ports
Override default HTTP (80) and HTTPS (443) ports:
npx create-better-openclaw \
--proxy caddy \
--proxy-http-port 8080 \
--proxy-https-port 8443 \
--domain example.com
This automatically updates the Caddy service port mappings in docker-compose.yml.
Environment variables
# Domain for service routing
OPENCLAW_DOMAIN = example.com
# Custom Caddy ports (optional)
CADDY_EXTERNAL_PORT = 80
CADDY_EXTERNAL_PORT_1 = 443
Traefik configuration
Traefik uses Docker labels for automatic service discovery and routing.
Generated files
traefik/traefik.yml - Static configuration
docker-compose.yml - Services with Traefik labels
Static configuration
api :
dashboard : true
insecure : true
entryPoints :
web :
address : ":80"
websecure :
address : ":443"
providers :
docker :
endpoint : "unix:///var/run/docker.sock"
exposedByDefault : false
network : openclaw-network
certificatesResolvers :
letsencrypt :
acme :
email : [email protected]
storage : /letsencrypt/acme.json
httpChallenge :
entryPoint : web
log :
level : INFO
Docker labels
Traefik discovers services via Docker labels. Each exposed service gets:
labels :
traefik.enable : "true"
# HTTPS router
traefik.http.routers.postgresql.rule : "Host(`postgresql.example.com`)"
traefik.http.routers.postgresql.entrypoints : "websecure"
traefik.http.routers.postgresql.tls.certresolver : "letsencrypt"
traefik.http.services.postgresql.loadbalancer.server.port : "5432"
# HTTP → HTTPS redirect
traefik.http.routers.postgresql-http.rule : "Host(`postgresql.example.com`)"
traefik.http.routers.postgresql-http.entrypoints : "web"
traefik.http.routers.postgresql-http.middlewares : "redirect-to-https"
Traefik dashboard
Access the Traefik dashboard at http://localhost:8080 (insecure mode for local development).
For production, secure the dashboard:
Set api.insecure: false in traefik.yml
Add HTTP basic auth middleware
Use a dedicated subdomain with TLS
Custom ports
npx create-better-openclaw \
--proxy traefik \
--proxy-http-port 8080 \
--proxy-https-port 8443 \
--domain example.com
No reverse proxy
Services are exposed directly on their host ports:
npx create-better-openclaw --proxy none
Access services at:
http://localhost:18789 - OpenClaw gateway
http://localhost:5432 - PostgreSQL
http://localhost:6379 - Redis
DNS configuration
Before deploying with a reverse proxy, configure DNS A records for your domain and all service subdomains.
Wildcard DNS (recommended)
Create a wildcard A record pointing to your server:
*.example.com A YOUR_SERVER_IP
example.com A YOUR_SERVER_IP
This routes all subdomains (postgresql.example.com, grafana.example.com, etc.) to your server.
Individual records
Alternatively, create an A record for each service:
example.com A YOUR_SERVER_IP
postgresql.example.com A YOUR_SERVER_IP
redis.example.com A YOUR_SERVER_IP
grafana.example.com A YOUR_SERVER_IP
Firewall configuration
Open required ports on your server:
# Allow HTTP and HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Or custom ports
sudo ufw allow 8080/tcp
sudo ufw allow 8443/tcp
Troubleshooting
Certificate errors
Caddy:
# Check Caddy logs
docker compose logs caddy
# Verify ACME challenge is reachable
curl http://example.com/.well-known/acme-challenge/test
Traefik:
# Check certificate resolver
docker compose logs traefik | grep letsencrypt
# Inspect acme.json
docker compose exec traefik cat /letsencrypt/acme.json
Service not accessible
Verify DNS resolution:
nslookup postgresql.example.com
Check service health:
Test proxy routing:
# Caddy
docker compose exec caddy caddy validate --config /etc/caddy/Caddyfile
# Traefik
curl http://localhost:8080/api/http/routers
Port conflicts
better-openclaw automatically detects port conflicts and suggests available ports during generation. If you encounter conflicts after deployment:
# Check port usage
sudo netstat -tulpn | grep :80
# Update ports in .env
CADDY_EXTERNAL_PORT = 8080
CADDY_EXTERNAL_PORT_1 = 8443
# Restart stack
docker compose up -d