Your first host with HTTPS¶
Take one domain from nothing to a working, automatically renewed HTTPS host, over HTTP-01 or DNS-01.
Prerequisites¶
- A running gpm instance you can sign in to: see Quickstart, Install with Docker or Install the binary.
- A domain whose public
A/AAAArecord already points at this host. gpm does not create that record for you on a first run; DNS sync publishes records only once a host exists and opts in. - For HTTP-01, inbound
tcp/80forwarded to gpm through every router, firewall and load balancer in front of it. Port 80 is not optional for this challenge, even when the host itself only serves HTTPS. - For DNS-01, an API token for the zone instead (no inbound port at all).
- A backend that answers HTTP on an address gpm can reach.
Choosing a challenge¶
Pick the challenge that fits the deployment:
- HTTP-01 (default when no DNS provider is referenced): no credentials at
all, but
:80must be reachable from the internet and the name must already resolve here. Single names only. - DNS-01: works from behind a firewall with no inbound port, and is the only
way to get a wildcard. Needs a DNSProvider credential
(
cloudflare,digitalocean,hetzner,desec,rfc2136for any nameserver that accepts TSIG-signed dynamic updates, oracme-dnsfor anything else: see DNSProvider for theconfigkeys each one takes).
# config/certificates/app.yaml - HTTP-01, no provider needed
name: app
type: acme
domains: [app.example.com]
acme: {email: admin@example.com, challenge: http-01}
The HTTP-01 token is served by gpm's own :80 proxy listener ahead of host
routing and the force-SSL redirect, so no host or exception has to be configured
for /.well-known/acme-challenge/. Anything in front of gpm (a router port
forward, a cloud LB) must pass port 80 through unmodified. A CA that requires
External Account Binding (ZeroSSL, Google Public CA) takes acme.eab.kid +
acme.eab.hmacKey alongside its directoryURL.
Steps¶
- Create the proxy host with no
tlsblock, so it is reachable over plain HTTP while you confirm routing:
yaml
# config/proxy-hosts/app.yaml
name: app
domains: [app.example.com]
upstream: {scheme: http, host: 10.0.0.40, port: 8080}
- Confirm plain HTTP reaches the backend before involving a CA:
curl -sI http://app.example.com/
- Create the certificate using one of the two blocks below.
- Wait for issuance. The ACME manager issues on the next load and logs the
outcome; the Certificates page shows
stateanddaysRemaining. - Attach TLS to the host and force the redirect:
yaml
tls: {certificateRef: app, forceSSL: true}
- Add a second host by repeating steps 1-5, or by pointing it at a wildcard certificate you already issued: one wildcard covers every subdomain, and no per-host issuance is needed.
DNS-01 instead¶
DNS-01 needs a DNSProvider credential and no inbound port:
# config/dns-providers/cloudflare.yaml
name: cloudflare
provider: cloudflare
config: {apiToken: ${FILE:/run/secrets/cf_token}}
# config/certificates/wildcard.yaml
name: wildcard
type: acme
domains: ["*.example.com", example.com]
acme: {email: admin@example.com, dnsProvider: cloudflare}
Full walkthrough: Issue a wildcard certificate over DNS-01. For a nameserver with no native client, see rfc2136 and acme-dns.
Verify¶
| Check | Expected |
|---|---|
GET /api/certificates |
state: valid, issuer set, daysRemaining near 90 |
curl -sI https://app.example.com/ |
200/3xx and no TLS error |
curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' http://app.example.com/ |
308 https://app.example.com/ |
GET /api/health |
certificates.expired and certificates.error stay 0 |
Troubleshooting¶
| Symptom | Cause | Fix |
|---|---|---|
Certificate stuck at state: pending |
The first order has not completed, or keeps failing | Read lastError; for HTTP-01 confirm :80 is reachable from the internet, for DNS-01 confirm the token's zone scope |
curl reports an unknown-SNI TLS error |
No certificate object covers this domain | Add the domain to a certificate's domains, or issue one for it |
| The wrong certificate is served | Selection is by SNI, not by tls.certificateRef |
Check which certificate's domains cover the name; see Certificate |
| HTTP-01 fails behind another proxy | Something ahead of gpm answers or rewrites /.well-known/acme-challenge/ |
Pass port 80 through unmodified, or switch to DNS-01 |
| Wildcard issuance is refused at validation | A wildcard cannot be proven over HTTP-01 | Use DNS-01 for any *.example.com name |