-
Notifications
You must be signed in to change notification settings - Fork 3
Domain and SSL
Configure custom domains and SSL/TLS certificates for strut stacks using Let's Encrypt.
strut supports two reverse-proxy backends, selected by the REVERSE_PROXY
setting in strut.conf (default nginx):
-
nginx (default) — runs
configure-domain.sh+ certbot on the VPS. -
caddy — updates the stack's
Caddyfile; Caddy obtains and renews certificates automatically. See Caddy Backend below.
strut my-stack domain api.example.com admin@example.com --env prodWith the default nginx backend, this single command:
- Validates DNS resolves to the correct VPS IP
- Generates production-ready nginx reverse proxy config
- Obtains a Let's Encrypt certificate via certbot (webroot validation)
- Configures HTTPS with HTTP→HTTPS redirect
- Adds security headers (HSTS, X-Frame-Options, etc.)
- Sets up auto-renewal cron (daily at 3 AM)
(With the caddy backend the flow is simpler — see Caddy Backend.)
strut my-stack domain api.example.com admin@example.com --skip-ssl --env prodstrut <stack> domain above is the manual, one-time setup command. Separately, strut can auto-provision certs as part of every deploy, without you running domain at all — useful when domains are declared alongside the stack itself rather than configured out-of-band.
After a successful deploy and health check, strut looks for a domain in this order:
- Compose label
strut.domainon any service -
DOMAINenv var (single domain) -
DOMAINSenv var (comma-separated list) -
VIRTUAL_HOSTenv var (nginx-proxy convention, comma-separated)
If found, and AUTO_SSL isn't explicitly disabled, strut checks whether a valid cert already exists (skips if it has more than 30 days left), verifies the domain actually resolves to the VPS IP (skips with a warning on mismatch — never fights your DNS), then runs certbot certonly --webroot (falling back to --standalone if the webroot isn't writable).
# .env or strut.conf
AUTO_SSL=true # default
SSL_EMAIL=admin@example.com # required — no email means auto-SSL silently skips
DOMAIN=api.example.com# Opt out for a stack that manages its own certs
AUTO_SSL=falseThis complements, but doesn't replace, the manual domain command — use whichever fits how you already declare domains for a given stack. Both end up in the same place (a certbot-issued cert renewed on the usual cadence).
api.example.com A <VPS_IP> TTL=300
Verify: dig +short api.example.com
Your cloud provider's firewall must allow inbound TCP on ports 80 and 443.
strut my-stack deploy --env prod
strut my-stack status --env prod # Verify nginx is running| Property | Value |
|---|---|
| Provider | Let's Encrypt (free, trusted) |
| Validity | 90 days |
| Auto-renewal | Daily cron, renews when <30 days remain |
| Validation | Webroot (no downtime) |
| TLS versions | 1.2 and 1.3 only |
sudo certbot renew --dry-runstrut my-stack exec \
"docker compose --project-name prod exec nginx openssl s_client \
-connect localhost:443 -servername api.example.com < /dev/null 2>/dev/null \
| openssl x509 -noout -dates" --env prodstrut my-stack domain api.example.com admin@example.com --env prod
strut my-stack domain api2.example.com admin@example.com --env prodThe automated script uses webroot validation (no wildcard support). For wildcards:
sudo certbot certonly --manual --preferred-challenges dns -d "*.example.com"After running the domain command, customize:
nano stacks/<stack>/nginx/conf.d/<stack>.conf
strut my-stack exec "docker compose --project-name prod restart nginx" --env prodIf your stack uses Caddy as its reverse proxy, set
REVERSE_PROXY=caddy in strut.conf. Caddy provisions and renews Let's Encrypt
certificates automatically — there is no certbot, no webroot validation, and
no renewal cron to manage.
The same command drives the Caddy flow:
strut my-stack domain api.example.com admin@example.com --env prodWith the caddy backend, the command:
- Updates the stack's
Caddyfileon the VPS with a site block for the domain (replacing the# :80 {placeholder withapi.example.com {) - Reloads Caddy in place (
caddy reload) — no downtime - Pulls the updated
Caddyfileback tostacks/<stack>/caddy/Caddyfile - Commits and pushes the change (unless
--skip-sslis passed)
Caddy then obtains the certificate on first request and renews it on its own.
The stack's Caddyfile lives at stacks/<stack>/caddy/Caddyfile locally (synced
to the VPS). Customize site blocks there, then re-run the domain command or
reload Caddy:
nano stacks/<stack>/caddy/Caddyfile
strut my-stack exec \
"docker compose --project-name prod exec -T caddy caddy reload --config /etc/caddy/Caddyfile" --env prodBecause Caddy handles ACME natively, --skip-ssl does not disable TLS for
the caddy backend — it only skips the automatic git commit/push of the updated
Caddyfile. To serve plain HTTP with Caddy, configure an http:// site block
in the Caddyfile directly.
System-wide Caddy (a shared gateway proxying multiple stacks) is managed separately — see Gateway Management and Certificate Management.
- HSTS (1 year, includeSubDomains)
- TLS 1.2+ only, no weak ciphers
- X-Frame-Options, X-Content-Type-Options headers
- HTTP→HTTPS redirect for all traffic
- Optimized timeouts
Test your configuration: https://www.ssllabs.com/ssltest/
dig +short your-domain.com
# Wait for DNS propagation (5-60 minutes)curl -I http://your-domain.com # Test externally
sudo ufw status # Check VPS firewall
docker ps | grep nginx # Check nginx runningsudo journalctl -u certbot
# Common: port 80 blocked by cloud firewall, DNS wrong, rate limitstrut my-stack logs nginx --follow --env prod
sudo ls -la /etc/letsencrypt/live/your-domain.com/
docker exec <nginx-container> nginx -tstrut · v0.28.0 · Report an Issue
Getting Started
Core Concepts
Operations
- Deployment
- Ship and Rebuild
- GitHub Action
- Webhook Automation
- Remote Host Setup
- Provisioning
- Blue-Green Deploy
- Deploy Rollback
- Database Backups
- Secrets Management
- Stack Groups
- Lifecycle Hooks
- Notifications
- Key Rotation
- Drift Detection
- Domain and SSL
- Certificate Management
- Gateway Management
- Monitoring
- Volume Management
Advanced
- Security Posture
- VPS Audit and Migration
- Stack Validation
- Data Anonymization
- Debugging
- Local Development
Extending
Contributing