Replace Cloudflare DNS challenge with standard Let's Encrypt HTTP-01
Caddy's built-in ACME support handles TLS automatically — no CF_API_TOKEN, no Cloudflare account, no DNS plugin needed. Requires ports 80+443 forwarded to the Pi and ACME_EMAIL set in infra/.env.
This commit is contained in:
parent
3794f4cf36
commit
dc59293c5e
4 changed files with 46 additions and 83 deletions
|
|
@ -140,29 +140,24 @@ docker run --rm hello-world # verify
|
|||
|
||||
---
|
||||
|
||||
## 6. Domain and DNS (Cloudflare)
|
||||
## 6. Domain and DNS
|
||||
|
||||
You need a domain whose DNS is managed by Cloudflare (the free plan is fine).
|
||||
You need a domain pointing to your Pi's public IP. Any DNS provider works.
|
||||
|
||||
1. In Cloudflare, add two DNS records pointing to your **public home IP**:
|
||||
1. Add DNS A records pointing to your **public home IP**:
|
||||
|
||||
| Type | Name | Content | Proxy |
|
||||
|---|---|---|---|
|
||||
| A | `hiy` | `<your-public-IP>` | Proxied (orange cloud) |
|
||||
| A | `*` | `<your-public-IP>` | Proxied (orange cloud) |
|
||||
| Type | Name | Content |
|
||||
|---|---|---|
|
||||
| A | `hiy` | `<your-public-IP>` |
|
||||
| A | `*` | `<your-public-IP>` |
|
||||
|
||||
The wildcard `*` record routes `<appname>.yourdomain.com` to the Pi.
|
||||
|
||||
2. In **Cloudflare → SSL/TLS → Overview**, set mode to **Full (strict)**.
|
||||
|
||||
3. Create a **Cloudflare API token** for Caddy's ACME DNS challenge:
|
||||
- Go to My Profile → API Tokens → Create Token
|
||||
- Use the **Edit zone DNS** template, scope it to your zone
|
||||
- Copy the token — you will need it in step 8
|
||||
|
||||
### Port forwarding
|
||||
|
||||
Forward the following ports on your router to the Pi's static IP:
|
||||
Forward the following ports on your router to the Pi's static IP.
|
||||
**Both ports are required** — Caddy uses port 80 to prove domain ownership
|
||||
to Let's Encrypt before issuing the HTTPS certificate.
|
||||
|
||||
| External | Internal |
|
||||
|---|---|
|
||||
|
|
@ -195,63 +190,20 @@ Minimum required variables:
|
|||
# Your domain (apps will be at <name>.yourdomain.com)
|
||||
DOMAIN_SUFFIX=yourdomain.com
|
||||
|
||||
# Cloudflare API token for ACME DNS-01 challenge
|
||||
CF_API_TOKEN=your_cloudflare_api_token
|
||||
# Email for Let's Encrypt expiry notices
|
||||
ACME_EMAIL=you@example.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Caddy — automatic HTTPS
|
||||
|
||||
Caddy handles TLS via Cloudflare's DNS challenge (no port-80 HTTP challenge
|
||||
needed, works even behind CGNAT).
|
||||
Caddy obtains a Let's Encrypt certificate automatically via the HTTP-01
|
||||
challenge. No DNS API token or Cloudflare account required.
|
||||
|
||||
Edit `proxy/caddy.json` and replace the top-level config with:
|
||||
|
||||
```json
|
||||
{
|
||||
"admin": { "listen": "0.0.0.0:2019" },
|
||||
"apps": {
|
||||
"tls": {
|
||||
"automation": {
|
||||
"policies": [{
|
||||
"subjects": ["*.yourdomain.com", "yourdomain.com"],
|
||||
"issuers": [{
|
||||
"module": "acme",
|
||||
"challenges": {
|
||||
"dns": {
|
||||
"provider": {
|
||||
"name": "cloudflare",
|
||||
"api_token": "{env.CF_API_TOKEN}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}]
|
||||
}
|
||||
},
|
||||
"http": {
|
||||
"servers": {
|
||||
"hiy": {
|
||||
"listen": [":80", ":443"],
|
||||
"routes": [
|
||||
{
|
||||
"handle": [{
|
||||
"handler": "reverse_proxy",
|
||||
"upstreams": [{"dial": "server:3000"}]
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> **Note:** The Caddy image in `docker-compose.yml` needs the Cloudflare DNS
|
||||
> plugin. Use `caddy:2-alpine` with `xcaddy` or replace the image with
|
||||
> `ghcr.io/caddybuilds/caddy-cloudflare:latest`.
|
||||
The `proxy/Caddyfile` is already configured — nothing to edit here.
|
||||
Just make sure `DOMAIN_SUFFIX` and `ACME_EMAIL` are set in `infra/.env`
|
||||
and that ports 80 and 443 are forwarded to the Pi (see step 6).
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -427,7 +379,7 @@ Caddy never restarts.
|
|||
| Symptom | Likely cause | Fix |
|
||||
|---|---|---|
|
||||
| Dashboard not reachable | Compose not started / port 443 not forwarded | `docker compose logs server` |
|
||||
| TLS certificate error | CF_API_TOKEN wrong or DNS not propagated | Check Caddy logs: `docker compose logs caddy` |
|
||||
| TLS certificate error | Port 80/443 not forwarded or DNS not propagated yet | Check Caddy logs: `docker compose logs caddy` |
|
||||
| Build fails — "docker not found" | Docker socket not mounted | Verify `docker-proxy` service is up |
|
||||
| Build fails — "pack not found" | `pack` not installed | See step 11 |
|
||||
| Webhook returns 401 | Secret mismatch | Regenerate app, re-copy secret to GitHub |
|
||||
|
|
|
|||
5
infra/.env.example
Normal file
5
infra/.env.example
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Your domain — apps will be served at <name>.yourdomain.com
|
||||
DOMAIN_SUFFIX=yourdomain.com
|
||||
|
||||
# Email address for Let's Encrypt expiry notices (required for HTTPS)
|
||||
ACME_EMAIL=you@example.com
|
||||
|
|
@ -53,11 +53,14 @@ services:
|
|||
- "80:80"
|
||||
- "443:443"
|
||||
- "2019:2019" # admin API
|
||||
environment:
|
||||
DOMAIN_SUFFIX: ${DOMAIN_SUFFIX:-localhost}
|
||||
ACME_EMAIL: ${ACME_EMAIL:-}
|
||||
volumes:
|
||||
- ../proxy/caddy.json:/etc/caddy/caddy.json:ro
|
||||
- ../proxy/Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
- caddy-data:/data
|
||||
- caddy-config:/config
|
||||
command: caddy run --config /etc/caddy/caddy.json
|
||||
command: caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
|
||||
networks:
|
||||
- hiy-net
|
||||
- default
|
||||
|
|
|
|||
|
|
@ -1,29 +1,32 @@
|
|||
# HIY — Caddyfile
|
||||
#
|
||||
# Local development: auto-HTTPS is disabled; everything runs on :80.
|
||||
# Production (Pi): remove the `auto_https off` line, set your real email,
|
||||
# and Caddy will obtain Let's Encrypt certificates automatically.
|
||||
# Caddy automatically obtains a Let's Encrypt certificate for every domain it
|
||||
# serves (HTTP-01 challenge). No Cloudflare or DNS API token required.
|
||||
#
|
||||
# Wildcard TLS on the Pi (recommended):
|
||||
# tls your@email.com {
|
||||
# dns cloudflare {env.CLOUDFLARE_API_TOKEN}
|
||||
# }
|
||||
# Requirements:
|
||||
# - Ports 80 and 443 must be publicly reachable (router port-forward to Pi)
|
||||
# - DNS A record for {$DOMAIN_SUFFIX} must point to your public IP
|
||||
# - Set ACME_EMAIL in infra/.env (Let's Encrypt needs a contact address)
|
||||
#
|
||||
# Local dev: set DOMAIN_SUFFIX=localhost in infra/.env — Caddy will use a
|
||||
# self-signed cert automatically for localhost.
|
||||
|
||||
{
|
||||
# Admin API — used by build.sh to update routes dynamically.
|
||||
# Admin API — used by hiy-server to add/remove app routes dynamically.
|
||||
admin 0.0.0.0:2019
|
||||
|
||||
# Comment this out on the Pi with a real domain.
|
||||
auto_https off
|
||||
# Contact email for Let's Encrypt expiry notices.
|
||||
email {$ACME_EMAIL}
|
||||
}
|
||||
|
||||
# Fallback: serves the HIY dashboard itself.
|
||||
:80 {
|
||||
# HIY dashboard — served at your root domain.
|
||||
{$DOMAIN_SUFFIX} {
|
||||
reverse_proxy server:3000
|
||||
}
|
||||
|
||||
# Example of what the build script adds via the Caddy API:
|
||||
# Deployed apps are added here dynamically by hiy-server via the Caddy API.
|
||||
# Each entry looks like:
|
||||
#
|
||||
# myapp.yourdomain.com {
|
||||
# reverse_proxy <container-ip>:3000
|
||||
# myapp.{$DOMAIN_SUFFIX} {
|
||||
# reverse_proxy <container-ip>:<port>
|
||||
# }
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue