Skip to content

editor-code-assistant/eca-tls

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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:

    • ZoneDNSEdit
    • ZoneZoneRead
    • Zone Resources → IncludeSpecific zoneeca.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 CNAMEeditor-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).

About

web app to host ECA certificates for remote features

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors