SSL
Pinner provisions and renews SSL certificates for your custom domains automatically, using Caddy's On-Demand TLS with Let's Encrypt. You don't need to buy certificates, configure web servers, or set up renewal cron jobs.
How it works
- You add a CNAME or A record pointing your domain at Pinner's infrastructure
- When the first HTTPS request arrives, Caddy checks if the domain is authorized by querying the gateway's
/allowedendpoint - The gateway validates the domain: it checks the DNSLink record and confirms the website is active in the portal
- If the domain passes validation, Caddy requests a certificate from Let's Encrypt via the HTTP-01 ACME challenge
- Caddy completes the ACME challenge (served on port 80) and obtains the certificate
- Caddy calls back to the portal's internal webhook to update the SSL status to
ready - Your site is served over HTTPS
You don't touch any of this. The entire process runs in the background.
Prerequisites
For SSL provisioning to work:
- Port 80 must be accessible from the internet (required for the HTTP-01 ACME challenge)
- Port 443 must be accessible for HTTPS traffic
- Your domain's DNSLink record (
_dnslink.yourdomain.com) must be properly configured - Your website must be in
activestatus in the portal
SSL states
SSL moves through these states:
pending → issuing → ready
↘ failed
| State | What's happening |
|---|---|
pending | Waiting to start: the domain hasn't been validated or no HTTPS request has triggered certificate issuance yet |
issuing | Caddy is obtaining the certificate from Let's Encrypt via the ACME protocol |
ready | Certificate issued and serving HTTPS traffic |
failed | Provisioning failed; the error field on the SSL status has details |
There is no separate valid or error state. A failed state includes an error message explaining what went wrong.
Checking status
You can check SSL status through the SDK. The GetSSLStatus method returns the current state, and the WaitForSSLStatusReady method polls until the certificate reaches ready or failed.
// Check current status
resp, err := client.Websites().GetSSLStatus(ctx, "example.com")
fmt.Println("SSL status:", resp.Ssl.Status)
// Wait until settled (ready or failed)
status, err := client.Websites().WaitForSSLStatusReady(ctx, "example.com")The response also includes issued_at and last_updated_at timestamps when available.
Renewal
Caddy automatically renews certificates before they expire (typically 30 days before). You don't need to do anything; renewal happens automatically in the background. The portal tracks the renewal via the same Caddy webhook callback, updating last_updated_at.
If a previously valid certificate for a soft-deleted website is still within its validity period, recreating the website for the same domain will inherit the ready SSL status automatically.
DNS validation token
Before SSL can be provisioned, your website must be validated. When you create a website, Pinner generates a validation token and tells you to add a TXT record like:
pinner-verify.<yourdomain.com> TXT "pinner-verify=<token>"
The token has an expiry time. If it expires, Pinner generates a new one automatically when you re-validate.
Troubleshooting
SSL stays in pending
No HTTPS request has triggered certificate issuance yet, or the domain hasn't been validated. Ensure:
- Your website is in
activestatus (run DNS validation first) - Your DNS is pointing at Pinner's infrastructure (CNAME or A record)
- The DNSLink record exists:
dig TXT _dnslink.yourdomain.com
SSL stays in issuing
The ACME challenge is in progress. Common causes for getting stuck:
- Port 80 is not accessible: The HTTP-01 challenge requires port 80 to be reachable from the internet
- DNS hasn't propagated: Let's Encrypt needs to resolve your domain to the correct IP
- The gateway's
/allowedendpoint rejected the domain: Check that the DNSLink record and website status are valid
You can test the /allowed endpoint directly:
curl "http://localhost:8080/allowed?domain=yourdomain.com"A 200 response means the domain is approved for certificate issuance.
SSL fails with failed
Check the error field on the SSL status response. Common causes:
- Port 80 not accessible from the internet: Required for the HTTP-01 ACME challenge; check firewall rules
- DNS not pointing at Pinner: The CNAME or A record is missing or incorrect
- Website is not active: The gateway's
/allowedcheck returns 400 when the website status isn'tactive - DNSLink record missing or incorrect: The gateway validates the
_dnslinkTXT record before allowing certificate issuance - Let's Encrypt rate limits: Too many failed issuance attempts; wait and retry (see Let's Encrypt rate limits)
SSL works but the site isn't loading
SSL is only one piece. Check that:
- Your website's target hash points at a valid, pinned CID
- The content is actually accessible on IPFS
- DNS is correctly pointing at Pinner's infrastructure