[GH-ISSUE #3243] Support using external certificates (file provider / BYOC, no ACME) with the cert scraper #30173

Open
opened 2026-06-13 10:42:27 -05:00 by GiteaMirror · 7 comments
Owner

Originally created by @L0sWach0s on GitHub (Jun 11, 2026).
Original GitHub issue: https://github.com/fosrl/pangolin/issues/3243

Originally assigned to: @oschwartz10612 on GitHub.

Describe the Bug

When Pangolin runs with externally managed certificates — Traefik serves certificates
from a file provider (e.g. wildcard certs issued by acme.sh) and no Traefik ACME
certResolver is configured — the dashboard shows the certificate status for
resources/domains as pending permanently.

HTTPS works correctly the whole time (Traefik picks the matching certificate from the
file-provider store via SNI), so this is purely a status/UI issue: Pangolin never learns
that a valid certificate already exists for the domain, because the only code path that
marks a certificate valid is the ACME cert sync, which doesn't apply to a
file-provider / BYOC deployment.

Environment

  • OS Type & Version: Debian 13 (Trixie)
  • Pangolin Version: 1.18.4
  • Edition (Community or Enterprise): Enterprise (fosrl/pangolin:ee-1.18.4)
  • Gerbil Version: 1.4.1
  • Traefik Version: v3.7.5
  • Newt Version: not used (local site + Traefik file provider, no tunneled sites)
  • Client Version: not used

To Reproduce

  1. Configure Traefik with a file provider that loads external certificates and no ACME
    certResolver.
  2. In config.yml set traefik.cert_resolver: "".
  3. (Optionally) disable ACME cert sync: privateConfig.ymlflags.enable_acme_cert_sync: false.
  4. Create an HTTP resource under a configured base domain.
  5. Open the dashboard and look at the certificate status of the resource/domain.

Actual result: the certificate status stays Pending indefinitely, even though the
resource is reachable over HTTPS with a valid certificate the whole time (Traefik selects
the matching cert from the file-provider store via SNI).

Image

Expected Behavior

The dashboard should reflect that a valid certificate is being served — or expose a
"bring your own certificate" / "externally managed" state — instead of showing pending
forever.

Why it stays pending (from reading the source):

  • The certificates table defaults status to pending
    (server/setup/scriptsSqlite/1.11.0.ts; status enum in
    server/routers/certificates/types.ts: pending, requested, valid, expired, failed).
  • The only code that sets status: "valid" is the ACME cert-sync logic
    (server/private/lib/acmeCertSync.ts), which reads Traefik's acme.json or an HTTP
    endpoint exposing issued certs.
  • In a file-provider / BYOC setup there is no acme.json and no ACME flow, so nothing ever
    transitions the record from pending to valid.

Possible fixes (any one):

  1. Allow a domain/resource to be flagged "externally managed", suppressing the pending
    status and ACME logic for it.
  2. Optionally verify the certificate actually served (or read the file-provider store) and
    mark it valid independent of ACME.
  3. Let acmeCertSync ingest PEM certs from a directory, not only Traefik acme.json.

Note: this is not a functional bug — routing and TLS work correctly. It's confusing
because the UI permanently implies the certificate is incomplete.

Originally created by @L0sWach0s on GitHub (Jun 11, 2026). Original GitHub issue: https://github.com/fosrl/pangolin/issues/3243 Originally assigned to: @oschwartz10612 on GitHub. ### Describe the Bug When Pangolin runs with **externally managed certificates** — Traefik serves certificates from a file provider (e.g. wildcard certs issued by `acme.sh`) and no Traefik ACME `certResolver` is configured — the dashboard shows the certificate status for resources/domains as **`pending` permanently**. HTTPS works correctly the whole time (Traefik picks the matching certificate from the file-provider store via SNI), so this is purely a status/UI issue: Pangolin never learns that a valid certificate already exists for the domain, because the only code path that marks a certificate `valid` is the ACME cert sync, which doesn't apply to a file-provider / BYOC deployment. ### Environment - OS Type & Version: Debian 13 (Trixie) - Pangolin Version: 1.18.4 - Edition (Community or Enterprise): Enterprise (`fosrl/pangolin:ee-1.18.4`) - Gerbil Version: 1.4.1 - Traefik Version: v3.7.5 - Newt Version: not used (local site + Traefik file provider, no tunneled sites) - Client Version: not used ### To Reproduce 1. Configure Traefik with a file provider that loads external certificates and **no** ACME `certResolver`. 2. In `config.yml` set `traefik.cert_resolver: ""`. 3. (Optionally) disable ACME cert sync: `privateConfig.yml` → `flags.enable_acme_cert_sync: false`. 4. Create an HTTP resource under a configured base domain. 5. Open the dashboard and look at the certificate status of the resource/domain. **Actual result:** the certificate status stays `Pending` indefinitely, even though the resource is reachable over HTTPS with a valid certificate the whole time (Traefik selects the matching cert from the file-provider store via SNI). <img width="605" height="63" alt="Image" src="https://github.com/user-attachments/assets/ce133c7e-f3d2-40db-953a-fd743594a786" /> ### Expected Behavior The dashboard should reflect that a valid certificate is being served — or expose a "bring your own certificate" / "externally managed" state — instead of showing `pending` forever. Why it stays `pending` (from reading the source): - The `certificates` table defaults `status` to `pending` (`server/setup/scriptsSqlite/1.11.0.ts`; status enum in `server/routers/certificates/types.ts`: `pending, requested, valid, expired, failed`). - The **only** code that sets `status: "valid"` is the ACME cert-sync logic (`server/private/lib/acmeCertSync.ts`), which reads Traefik's `acme.json` or an HTTP endpoint exposing issued certs. - In a file-provider / BYOC setup there is no `acme.json` and no ACME flow, so nothing ever transitions the record from `pending` to `valid`. Possible fixes (any one): 1. Allow a domain/resource to be flagged "externally managed", suppressing the `pending` status and ACME logic for it. 2. Optionally verify the certificate actually served (or read the file-provider store) and mark it `valid` independent of ACME. 3. Let `acmeCertSync` ingest PEM certs from a directory, not only Traefik `acme.json`. Note: this is not a functional bug — routing and TLS work correctly. It's confusing because the UI permanently implies the certificate is incomplete.
GiteaMirror added the enhancement label 2026-06-13 10:42:27 -05:00
Author
Owner

@AstralDestiny commented on GitHub (Jun 11, 2026):

Cert is what self signed elsewhere or in the acme.json?

<!-- gh-comment-id:4684014812 --> @AstralDestiny commented on GitHub (Jun 11, 2026): Cert is what self signed elsewhere or in the acme.json?
Author
Owner

@AstralDestiny commented on GitHub (Jun 11, 2026):

Will answer better detail after shower

<!-- gh-comment-id:4684019178 --> @AstralDestiny commented on GitHub (Jun 11, 2026): Will answer better detail after shower
Author
Owner

@L0sWach0s commented on GitHub (Jun 11, 2026):

For clarity, here's how the cert is wired in — Traefik's file provider loads the
PEM files that acme.sh produced; there is no certificatesResolvers block:

# traefik_config.yml (static) — note: NO certificatesResolvers / no ACME
providers:
  http:
    endpoint: "http://pangolin:3001/api/v1/traefik-config"
  file:
    filename: "/etc/traefik/dynamic_config.yml"
    watch: true
# dynamic_config.yml (file provider) — external acme.sh certs, served as-is
tls:
  certificates:
    - certFile: /opt/certs/example.com/fullchain.cer
      keyFile:  /opt/certs/example.com/example.com.key

acme.sh (running in its own container) obtains/renews the cert from a public CA via
DNS-01 and writes fullchain.cer + the private key to /opt/certs/.... Traefik just
serves it via SNI (watch: true picks up renewals automatically). No acme.json, no
self-signed cert — a fully browser-trusted certificate that Traefik did not issue.

<!-- gh-comment-id:4684105595 --> @L0sWach0s commented on GitHub (Jun 11, 2026): For clarity, here's how the cert is wired in — Traefik's **file provider** loads the PEM files that `acme.sh` produced; there is **no** `certificatesResolvers` block: ```yaml # traefik_config.yml (static) — note: NO certificatesResolvers / no ACME providers: http: endpoint: "http://pangolin:3001/api/v1/traefik-config" file: filename: "/etc/traefik/dynamic_config.yml" watch: true ``` ```yaml # dynamic_config.yml (file provider) — external acme.sh certs, served as-is tls: certificates: - certFile: /opt/certs/example.com/fullchain.cer keyFile: /opt/certs/example.com/example.com.key ``` `acme.sh` (running in its own container) obtains/renews the cert from a public CA via DNS-01 and writes `fullchain.cer` + the private key to `/opt/certs/...`. Traefik just serves it via SNI (`watch: true` picks up renewals automatically). No `acme.json`, no self-signed cert — a fully browser-trusted certificate that Traefik did not issue.
Author
Owner

@AstralDestiny commented on GitHub (Jun 11, 2026):

Well sni and snistrict are vastly different things but can ask the certificate status does check only against the acme.json populated data and doesn't look for stuff provided elsewhere outside of that.

<!-- gh-comment-id:4684170349 --> @AstralDestiny commented on GitHub (Jun 11, 2026): Well sni and snistrict are vastly different things but can ask the certificate status does check only against the acme.json populated data and doesn't look for stuff provided elsewhere outside of that.
Author
Owner

@AstralDestiny commented on GitHub (Jun 11, 2026):

I assume you have multiple RP's for this and you ust only want the cert that is generated off site or elsewhere to distribute it to the other hosts?

<!-- gh-comment-id:4684186802 --> @AstralDestiny commented on GitHub (Jun 11, 2026): I assume you have multiple RP's for this and you ust only want the cert that is generated off site or elsewhere to distribute it to the other hosts?
Author
Owner

@AstralDestiny commented on GitHub (Jun 11, 2026):

Sorry for additional messages or whatnot I'm responding from within discord even though I know I can update my edits to messages though that hits github's rate limits faster annoyingly.

<!-- gh-comment-id:4684195096 --> @AstralDestiny commented on GitHub (Jun 11, 2026): Sorry for additional messages or whatnot I'm responding from within discord even though I know I can update my edits to messages though that hits github's rate limits faster annoyingly.
Author
Owner

@oschwartz10612 commented on GitHub (Jun 11, 2026):

Right now as I think you figured we only support the acme.json file but I agree that we should support pulling certs from the file provider as this would be a common use case. I will mark this as such and we can see if we can fit it in.

<!-- gh-comment-id:4685201054 --> @oschwartz10612 commented on GitHub (Jun 11, 2026): Right now as I think you figured we only support the acme.json file but I agree that we should support pulling certs from the file provider as this would be a common use case. I will mark this as such and we can see if we can fit it in.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/pangolin#30173