caddy-tls-proxy
Skill4 starsChanged 5 months agoMITView on GitHub
Caddy as a zero-config TLS reverse proxy for single-service EC2 deployments. Auto-provisioned Let's Encrypt certs, 3-line Caddyfile, systemd integration. Use when terminating HTTPS on EC2 for a Dockerized service, avoiding ALB costs, or replacing nginx+certbot.
In this repository101 other files it gives its agents.
- ai-video-understandingSkill
- apple-foundation-modelsSkill
- arch-dddSkill
- arch-decision-recordsSkill
- arch-diagramsSkill
- arch-eventsSkill
- arch-mvp-roadmapSkill
- arch-python-modernSkill
- aws-app-runnerSkill
- aws-cicd-patternsSkill
- aws-security-hardeningSkill
- azure-functions-python-v2Skill
- azure-identity-m2m-authSkill
- azure-service-bus-messagingSkill
- azure-workflow-execution-modelsSkill
- compliance-frameworksSkill
- design-system-workflowSkill
- dev-debugging-strategiesSkill
- dev-standardsSkill
- docker-python-poetrySkill
- docker-pythonSkill
- fastapi-patternsSkill
- ffmpeg-laravel-videoSkill
- formik-yup-react-nativeSkill
- frontend-accessibilitySkill
- frontend-angular-aiSkill
- frontend-angularSkill
- frontend-angular-toolingSkill
- frontend-design-systemsSkill
- frontend-material-chatSkill
- frontend-material-design-3Skill
- frontend-svelteSkill
- gcp-cicd-patternsSkill
- gcp-cloud-runSkill
- gcp-cloudsql-infrastructureSkill
- gcp-finopsSkill
- gcp-observabilitySkill
- gcp-security-hardeningSkill
- github-actions-cicdSkill
- healthkit-biofeedbackSkill
- infra-terraformSkill
- ios-app-qualitySkill
- ios-audio-hapticsSkill
- jest-nestjs-testingSkill
- langchain-azure-openai-patternsSkill
- laravel-auth-hardeningSkill
- laravel-ci-mysqlSkill
- laravel-mix-webpackSkill
- laravel-modern-patternsSkill
- laravel-pint-patternsSkill
- laravel-s3-storageSkill
- laravel-sail-dockerSkill
- mobile-app-deploymentSkill
- mobile-e2e-testingSkill
- mobile-offline-syncSkill
- mobile-push-notificationsSkill
- mobile-video-uploadSkill
- mongodb-asyncmongoclient-patternsSkill
- mongodb-atlas-patternsSkill
- nestjs-patternsSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 45
Use this path on Amazon Linux 2023 where the COPR repo (copr.fedorainfracloud.org/coprs/@caddy/caddy/) is frequently unavailable.
- Very specific: line 81
Default -p 8000:8000 binds to 0.0.0.0 and becomes externally reachable if the security group allows port 8000 — a defense-in-depth gap.
- Distinctive: line 85
Only 80 and 443 need to be open to the internet.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Caddy TLS Reverse Proxy
Caddy is the simplest way to terminate TLS in front of a single service on an EC2 (or similar) box. One binary, a 3-line Caddyfile, automatic Let's Encrypt certs with renewal. No certbot cron, no nginx config, no ALB.
When to Use
| Scenario | Caddy fit |
| Single service on EC2, one domain | Excellent — zero config |
| Multiple services, path routing | Good — add more reverse_proxy blocks |
| Multi-AZ, load balancing across targets | Prefer ALB/ELB — Caddy is one box |
| Blue/green or canary routing | Prefer ALB — no traffic-split features |
| Amazon Linux 2023 (COPR repos fail) | Excellent — single binary sidesteps package manager |
Minimal Caddyfile
api.example.com {
reverse_proxy localhost:8000
}That's it. Caddy provisions a Let's Encrypt cert on first run and auto-renews. Port 80 is used for the HTTP-01 challenge; Caddy redirects 80 → 443 automatically.
Installation (pinned binary)
Pin the version via query param — the default download URL is a moving target and unpinned binaries are a supply-chain risk.
CADDY_VERSION=2.8.4
curl -fsSL "https://caddyserver.com/api/download?os=linux&arch=amd64&version=${CADDY_VERSION}" \
-o /usr/local/bin/caddy
chmod +x /usr/local/bin/caddy
caddy version # verifyUse this path on Amazon Linux 2023 where the COPR repo (copr.fedorainfracloud.org/coprs/@caddy/caddy/) is frequently unavailable.
systemd Unit
[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network-online.target docker.service
Wants=network-online.target
Requires=docker.service
[Service]
Type=notify
ExecStart=/usr/local/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/local/bin/caddy reload --config /etc/caddy/Caddyfile
TimeoutStopSec=5s
LimitNOFILE=1048576
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.targetAfter=docker.service + Requires=docker.service ensures the upstream container is up before Caddy starts forwarding.
Upstream binding
Bind the upstream (Docker, gunicorn, etc.) to 127.0.0.1 only so external traffic cannot bypass TLS:
docker run -d --restart=always -p 127.0.0.1:8000:8000 myapp:latestDefault -p 8000:8000 binds to 0.0.0.0 and becomes externally reachable if the security group allows port 8000 — a defense-in-depth gap. See docker-python for the full pattern.
Security Group rules
Only 80 and 443 need to be open to the internet. Lock down upstream ports (8000, 3000, etc.) to the VPC or block them entirely — Caddy reaches them via localhost.
| Port | Source | Purpose |
| 80 | 0.0.0.0/0 | HTTP-01 challenge + HTTPS redirect |
| 443 | 0.0.0.0/0 | TLS termination |
| 22 | admin CIDR or SSM-only | SSH (prefer SSM) |
| 8000+ | (none) | Localhost-only upstream |
SSM deployment pattern
Deploying Caddy via aws ssm send-command avoids SSH keys and works well for "fix live, then codify":
aws ssm send-command \
--instance-ids i-0abc \
--document-name AWS-RunShellScript \
--parameters 'commands=[
"curl -fsSL \"https://caddyserver.com/api/download?os=linux&arch=amd64&version=2.8.4\" -o /usr/local/bin/caddy",
"chmod +x /usr/local/bin/caddy",
"mkdir -p /etc/caddy",
"printf \"api.example.com {\\n reverse_proxy localhost:8000\\n}\\n\" > /etc/caddy/Caddyfile",
"systemctl daemon-reload",
"systemctl enable --now caddy"
]'Heredoc pitfall: \n inside a bash heredoc passed through SSM's JSON commands array gets mangled by the JSON parser (observed as cat: {n: No such file or directory). Use printf 'line1\nline2\n' > file instead of cat <<EOF.
Verification
curl -I https://api.example.com # HTTP/2 200
curl -I http://api.example.com | grep -i location # 308 → https://
echo | openssl s_client -connect api.example.com:443 2>/dev/null | openssl x509 -noout -issuer -dates # Let's Encrypt, ~90 daysCost comparison
| Option | Monthly cost | Setup effort |
| Caddy on EC2 (t3.small) | ~$15 (EC2 only) | ~5 min |
| nginx + certbot + cron | Same EC2 cost | ~30 min, more moving parts |
| ALB + ACM | +~$20 (ALB) + data | ~15 min, requires VPC/target group |
For single-service deployments, Caddy saves ~$20/month vs ALB and is simpler than nginx+certbot.
Anti-Patterns
| Anti-Pattern | Pattern |
| Unpinned Caddy binary download | Pin with ?version=X.Y.Z query param |
| Running Caddy + another process on port 80 | Stop nginx/httpd before systemctl start caddy |
Heredoc for Caddyfile inside SSM commands array | printf '...\n' > /etc/caddy/Caddyfile |
Docker -p 8000:8000 behind Caddy | -p 127.0.0.1:8000:8000 — block external bypass |
Manual certbot renew cron | Caddy auto-renews — no cron needed |
| Opening the upstream port (8000) in the SG | Only 80/443 open; upstream stays localhost |
| COPR/yum install on Amazon Linux 2023 | Single binary download — avoids repo flakiness |
When to Graduate to ALB
Move to ALB when any of these apply: (1) multiple EC2 targets need load balancing, (2) WAF integration required, (3) you need path- or header-based traffic splits, (4) blue/green or canary deploys, (5) >1 availability zone. For everything else, Caddy is lighter and cheaper.
Related
docker-python— localhost binding behind reverse proxyaws-security-hardening— Secrets Manager validation, SSM live-fix patternaws-cicd-patterns— CI/CD for EC2 deploys
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

