fix(core): serve HTTP-01 ACME challenges via webroot provider - #347
Open
Splicho wants to merge 1 commit into
Open
fix(core): serve HTTP-01 ACME challenges via webroot provider#347Splicho wants to merge 1 commit into
Splicho wants to merge 1 commit into
Conversation
The panel's "Apply Free Cert" UI fails with 404 on every domain because two issues stack on top of each other: 1. The SafePath middleware in cmd.go returns 404 for any unauthenticated request without a session cookie. Let's Encrypt validation requests have no cookie, so they hit the gate before reaching the ACME handler. 2. GoFrame's static file handler (fileServerEnabled: true in manifest/config/config.yaml) runs ahead of bound handlers. Even if the SafePath gate is bypassed, the bound /.well-known/acme-challenge proxy is shadowed by the static handler returning 404 for the missing token file. The lego internal server on 127.0.0.1:60880 is never reached. Switch the HTTP-01 provider from lego's NewProviderServer to its webroot provider, pointing at server.serverRoot. lego writes the token directly to <serverRoot>/.well-known/acme-challenge/<token>, where the existing static handler serves it, and lego removes it after validation. The 60880 reverse proxy in cmd.go is now dead code and is removed. A small SafePath bypass for /.well-known/acme-challenge/ keeps the path open for unauthenticated LE validation requests. Verified end-to-end on billionmail/core:4.9.3: - /api/ssl/apply_cert returns success for fresh domains - letsencrypts row created with status=1 and correct not_after - Live TLS confirmed on 443/993/587 (issuer Let's Encrypt R12) - Challenge dir empty after issuance (cleanup works)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The panel's Apply Free Cert UI fails with
Invalid response from http://<host>/.well-known/acme-challenge/<token>: 404on every domain. This is reproducible on a clean install ofbillionmail/core:4.9.3with port 80 reachable and DNS pointed at the host:Root cause
Two issues compound:
SafePath middleware blocks unauthenticated ACME requests. The hook at
cmd.goreturns 404 for any non-/api/request without a session cookie. Let's Encrypt validation servers have no session, so they never reach the ACME handler.The static file handler shadows the ACME proxy.
manifest/config/config.yamlsetsfileServerEnabled: true, which makes GoFrame's static file handler run ahead of bound handlers. Even with the SafePath gate bypassed, requests for/.well-known/acme-challenge/<token>are intercepted by the static handler and 404 because the file doesn't exist on disk. The bound proxy ats.BindHandler(\"/.well-known/acme-challenge/*any\", …)and the lego internal server at127.0.0.1:60880are never reached.I confirmed (1) by adding a SafePath bypass and observing requests reach the bound handler. I confirmed (2) by adding a unique response body to the bound handler and seeing the static handler's stock
Not Foundreturned instead.Fix
http01.NewProviderServer(\"127.0.0.1\", \"60880\")to lego's webroot provider, pointing atserver.serverRoot. lego writes the challenge token to<serverRoot>/.well-known/acme-challenge/<token>directly. The existing static handler serves it. lego removes the file after validation completes.cmd.go./.well-known/acme-challenge/bypass to the SafePath middleware so LE can reach the webroot path.The webroot path is read from config (
server.serverRoot, defaulting topublic/dist) instead of being hardcoded.Diff stats
Verification
End-to-end test against
billionmail/core:4.9.3with the patched binary deployed:POST /api/ssl/apply_cert{\"success\":true,\"msg\":\"Certificate applied successfully\"}letsencryptsrow createdstatus=1, correctnot_after, validsubjectLet's Encrypt R12, CN matches host<serverRoot>/.well-known/acme-challenge/empty after issuanceTested with two domains (
mail.emudevs.gg,mail.synapse-themes.cc); both issued cleanly through the panel UI.Notes
github.com/go-acme/lego/v4/providers/http/webrootis part of the lego module already ingo.mod.g.Cfg().MustGet(ctx, \"server.serverRoot\", \"public/dist\")is used so admins who customizeserverRootaren't broken.