An open API service indexing awesome lists of open source software.

https://github.com/editor-code-assistant/eca-tls

web app to host ECA certificates for remote features
https://github.com/editor-code-assistant/eca-tls

Last synced: about 1 month ago
JSON representation

web app to host ECA certificates for remote features

Awesome Lists containing this project

README

          

# eca-tls

Issues, renews, and publishes the `*.local.eca.dev` wildcard TLS certificate
that ECA's remote web-control server uses for HTTPS. The certificate is served
at **https://tls.eca.dev/** via GitHub Pages; ECA fetches and caches it at
runtime (it is no longer bundled in the ECA binary).

## Why this exists (the tricky bit)

`local.eca.dev` is delegated in Cloudflare to **sslip.io**'s nameservers so that
`192-168-1-42.local.eca.dev` resolves to the LAN IP `192.168.1.42`. The wildcard
cert covers those hostnames, giving browsers a valid HTTPS connection to a
private IP (no mixed-content blocking).

That delegation also means Cloudflare can't serve the ACME `_acme-challenge`
TXT record (sslip.io is authoritative for everything under `local.eca.dev`, and
it can't serve the bare `_acme-challenge.local.eca.dev`). So issuance:

1. **Backs up + removes** the `local` NS delegation in Cloudflare.
2. Runs **lego** (DNS-01 via the Cloudflare API) to publish the TXT and issue
the cert — now servable because Cloudflare is authoritative again.
3. **Always restores** the NS delegation (even on failure).
4. Publishes the new PEMs to `tls.eca.dev` (gh-pages) and commits them to `main`.

While the delegation is removed (~6 min, scheduled off-peak) new
`*.local.eca.dev` lookups fail; existing TLS sessions and the Tailscale/localhost
paths are unaffected.

> The private key is intentionally public. `*.local.eca.dev` only resolves to
> private LAN IPs, so publishing the key just enables valid HTTPS to a private
> address for everyone without per-user setup.

## One-time setup

1. **Create the repo** `editor-code-assistant/eca-tls` and push this directory.
`public/` is pre-seeded with the current valid cert.

2. **Cloudflare API token** (My Profile → API Tokens → Create) scoped to:
- `Zone` → `DNS` → `Edit`
- `Zone` → `Zone` → `Read`
- Zone Resources → `Include` → `Specific zone` → `eca.dev`

3. **Repo secrets** (Settings → Secrets and variables → Actions):
- `CF_API_TOKEN` — the token above
- `CF_ZONE_ID` — the `eca.dev` zone id (Cloudflare dashboard → eca.dev → Overview)
- `ACME_EMAIL` — email for Let's Encrypt expiry notices (set a monitored one!)
- `ALERT_WEBHOOK` — *(optional)* Slack/Discord webhook for failure alerts

4. **GitHub Pages** (Settings → Pages): set source to the **`gh-pages`** branch,
root. (It's created by the first workflow run.)

5. **Cloudflare DNS**: add `tls` `CNAME` → `editor-code-assistant.github.io`.
- DNS-only (grey cloud) lets GitHub issue the `tls.eca.dev` cert.
- Proxied (orange) also works (Cloudflare serves an edge cert for `*.eca.dev`).

6. **First run**: trigger the workflow manually (Actions → *Renew \*.local.eca.dev
cert* → Run workflow). With a cert >30 days from expiry it just publishes the
seeded cert, bringing `tls.eca.dev` live. Verify:
```
curl -sS https://tls.eca.dev/local-eca-dev-fullchain.pem | openssl x509 -noout -subject -enddate
```

Only after `tls.eca.dev` serves a valid cert should the ECA change that drops the
bundled cert be released.

## Renewals

The workflow runs weekly and renews only when the published cert is within 30
days of expiry; otherwise it republishes the current one. `workflow_dispatch`
with `force: true` renews immediately.

## If a run fails

The NS-restore step runs `always()`, so the delegation should self-heal. Verify:

```
dig +short A 192-168-1-42.local.eca.dev # should return 192.168.1.42
```

If it doesn't resolve, restore the delegation manually in Cloudflare — add three
`NS` records on `local`: `ns-do-sg.sslip.io`, `ns-hetzner.sslip.io`,
`ns-ovh.sslip.io`. Or re-run the workflow (it backs up/restores idempotently).