Domains, DNS & SSL
Fix domain verification, DNS propagation, missing routes, certificate issuance and renewal, external ingress, uploads and custom proxy config.
A working custom domain needs DNS that reaches the server (or your own proxy), a route to the right app, and a certificate on the server or at your proxy. This page explains the failure messages and which part to check.
If you haven't added a domain yet, start with the custom domains guide; this page is for when something is already stuck. The Domains page is the quickest overview: it shows each domain's live DNS answer, certificate state and the reason for the last failure.
How verification works on Synq
Verifying a domain obtains (or reuses) a valid certificate through ACME (Let's Encrypt). Synq doesn't compare
the public IP with the server's and doesn't check an ownership TXT record. With External ingress & TLS,
Synq accepts the domain as it is and leaves TLS to your proxy.
Verification keeps failing
Symptom / what you see
You press Verify and the live log ends in a failure, or the domain shows a red "Last attempt ..." line on
the Domains page. From the API, POST /api/domains/:id/verify returns the failure message; the cnameVerified
and txtVerified flags belong to hosted-cloud DNS checks and don't mean anything on your own server.
What it means. Let's Encrypt couldn't confirm the name through this server. Synq reads certbot's output and puts the real cause first. The common ones:
| The message says | Cause | Fix |
|---|---|---|
| Port 80 for the domain isn't reachable from the internet | A firewall or cloud security group blocks port 80, the name points elsewhere, or another proxy holds port 80. | Open port 80 to the internet, check the A record, and make sure the Synq edge owns port 80 (see The edge). |
| The domain doesn't resolve to this server yet | The A record is missing or hasn't propagated. | Add the record, wait, then retry. |
| Cloudflare's proxy is answering the certificate challenge | Cloudflare redirected the challenge to HTTPS and then refused the server's certificate (errors 525/526). | Set the record to DNS only until the first certificate is issued, or set Cloudflare's SSL/TLS mode to Full until then, or upload a Cloudflare Origin CA certificate. See Cloudflare's proxy. |
| The challenge was redirected from HTTP to HTTPS and then answered with a 404 | Usually Cloudflare's "Always Use HTTPS" redirecting the challenge. | Same as above. Nothing is occupying port 80, so taking over another proxy won't help. |
| Port 80 answered but not with our ACME challenge | Another web server still serves port 80. | Take over or migrate the existing proxy. |
| Let's Encrypt rate limit reached | Too many attempts or certificates for this name. | Wait before retrying. Test with the staging directory next time (see Certificate authority settings). |
| Couldn't start the certificate challenge listener | A certificate run from an earlier attempt hasn't exited yet. Nothing was requested from Let's Encrypt. | Retry. If it persists, find the process holding the port named in the message with ss -ltnp and stop it. |
| Can't reach the server over SSH | The project's server is offline or unreachable. | Bring the server back, then verify again. |
How to fix, step by step
- Check the hostname points at your server:
dig A app.example.comshould return the server's public IP. A free subdomain (<slug>.<domain>) relies on the wildcard record*.<domain>instead. - Check for an
AAAArecord:dig AAAA app.example.com. Let's Encrypt tries IPv6 first, so anAAAApointing elsewhere breaks issuance. Point it at this server or delete it. - Make sure port 80 reaches the server from the internet (firewall, security group, NAT).
- Delete any old, conflicting record for the same name.
- Press Verify again. The Domain DNS verification job also retries on its own, less often after each failure (see Automatic retries).
After a failed check, Synq also looks up the hostname's DNS. If it has no record, or answers with an address that isn't the server serving the project, an Issue titled "app.example.com is not pointing at this server" opens on the Monitoring page with the addresses found, the expected server IP and the record to add. It updates on each automatic re-check and resolves itself once DNS points here and the certificate is issued. The lookup only explains a failure; it never blocks verification, so a CDN in front of a working domain is unaffected.
Wildcards and DNS-01
A wildcard (*.example.com) or a domain with Use DNS-01 challenge is verified through your DNS provider, not
port 80. "DNS-01 challenge for ... requires a connected DNS provider (e.g. Cloudflare) in Settings → DNS." means
no provider manages that zone: connect Cloudflare under Settings → Credentials. "DNS provider credential
rejected" means Cloudflare refused the stored token: replace it there. See
Wildcard certificates.
Already verified?
Verifying a domain that already has a valid certificate with more than 14 days left reuses it and requests nothing new. That's expected, not an error.
DNS hasn't propagated yet
Symptom / what you see
The records look correct at your registrar, but the Domains page shows No record yet or Points elsewhere, and Verify still fails, sometimes minutes after you saved them.
What it means. DNS isn't instant. After you save a record it has to spread across the internet's caches. Usually that takes minutes; occasionally hours (the panel warns it can take up to 48 hours).
How to fix
- Double-check the Host field for typos and remove leftover records for the same name.
- Use Check DNS on the Domains page to see what public DNS answers now (it asks Google's public resolver).
If your own
digdoesn't show the new value yet either, it's a propagation delay. - Wait. The Domain DNS verification job (on by default) first retries a pending domain once it is 10 minutes old, then backs off (15 minutes up to every 6 hours), and issues the certificate once DNS is right. It only retries domains of projects with a live deployment. Pressing Verify is only the faster retry.
What the first deployment does
A new custom domain starts Pending. The project's first deployment creates the HTTP route and prepares the server's certificate tools, but doesn't request a certificate yet. Issuance starts once the domain verifies, from the scheduled job or from Verify.
Verified, but no certificate yet
Symptom / what you see
The domain is Verified, but its SSL state stays on Awaiting certificate (Issuing on the Domains
page) instead of Active, so https:// doesn't work yet.
What it means. Issuance is still running, its result hasn't been read yet, or the first attempt failed.
How to fix
- Give it a moment, then open the domain's ⋯ menu and click Recheck SSL (Recheck certificate on the Domains page). It only reads the certificate on the server, so it spends no Let's Encrypt quota, and flips the state to Active once the certificate is there.
- If it says no valid certificate was found yet, wait a little longer and recheck.
- The scheduled domain job retries incomplete issuance. For an immediate retry, click Renew SSL; the real failure reason (DNS, blocked ports, rate limit, CA outage) appears there.
“Domain must be verified before SSL can be managed”
Renew, recheck and upload need a verified domain. Finish verification first, then manage the certificate.
Verify shouldn't need a redeploy
After a successful Verify, the existing route is re-registered with TLS, so no redeploy is needed. If HTTPS only starts working after a redeploy, keep both the deployment log and the Verify log: it points to a separate route problem, which Retry routing on the project's Domains & Routes tab repairs.
A certificate didn't renew
Symptom / what you see
An SSL cert expiring notification arrived, or a certificate on the Domains page shows Failed, a red countdown, or Expired.
What it means. The daily SSL certificate renewal job (ssl:renew) renews certificates with fewer than 14
days left. It failed for this one, for the same reasons issuance fails (DNS moved, port 80 closed, a CDN
redirecting the challenge), or the job is turned off.
How to fix
- Open the Certificates tab of the Domains page. The row shows the last error, and the Automatic renewal card shows whether the job is on and how its last run went.
- Fix the cause, then press Renew certificate on the row, or Renew {n} due to renew every due certificate at once.
- If the card says the renewal job is turned off, open it with Open renewal job and enable it.
Uploaded certificates (Auto-renew: Manual) are never renewed by Synq and send no reminder: upload a new one before the old one expires.
Uploading a certificate fails
"Invalid certificate: ..." means the certificate didn't pass the checks Synq runs before touching the edge: it must parse as PEM, the private key must match it, it must cover the hostname, and it must not be expired. Paste the full chain (your certificate first, then the intermediates) and the key that belongs to it. Nothing changes on the server when an upload is refused.
DNS and SSL are fine, but the app returns 404 or 502
A certificate proves the name reaches the server; it doesn't prove the route in front of your app is right.
- A 502 page titled "Application unavailable" means the edge couldn't reach the app: it's restarting, it
crashed, or it doesn't listen on the mapped port. Check the internal target on the Domains page (for example
https://app.example.com -> http://web:3000) against the port your app listens on, and read the app's logs. - A 404 page titled "Service not found" means no route exists for that hostname on this server. Use Retry routing on the project's Domains & Routes tab.
- A 503 page "... is not deployed yet" or "... is not live" means the domain is ready but the project has no live deployment. Deploy it (or read the failed deploy's log).
- For a Compose project, map the domain to the intended service's container port on Domains & Routes. A project-level domain without a port is skipped with a warning naming the available ports.
- A static route serves the release directory of the active deployment. A warning that no static root exists means the deployment's files need a new successful deployment.
If setup recorded SYNQ_PUBLIC_URL as external ingress, Synq assumes an existing proxy terminates TLS for
the panel and doesn't set up its own edge for it. Use the setup flow to hand ingress to Synq's edge if that
changes.
External ingress: your proxy terminates TLS
Symptom / what you see
Your app sits behind a Cloudflare Tunnel, a load balancer or another reverse proxy that handles HTTPS, but Synq
asks for an A record and tries to issue its own certificate, which you don't want.
How to fix
- Add the domain with External ingress & TLS turned on. From the API, pass
"externalIngress": trueonPOST /api/domains. - No DNS record is requested or checked. Point DNS at your proxy.
- Press Verify. The domain is verified straight away with the SSL state External TLS. Your proxy must forward requests to the Synq server on port 80 and serve HTTPS itself.
See Cloudflare Tunnel and external proxies.
Turn it on only if you mean it
If nothing in front of the server handles HTTPS, leave External ingress off; otherwise the domain verifies but is served over plain HTTP only, with no certificate from anyone.
Custom config was rolled back
"The edge rejected this config, so the previous config was restored." means your directives passed Synq's checks
but openresty -t or the reload failed. The error underneath is nginx's own, for example a duplicate directive
(often one that is also set in the project's Routing card) or an unknown directive. Nothing changed on the
server. Fix the snippet and save again; see Custom proxy config.
The hostname is refused
If Add domain is rejected before verification, the hostname failed a basic check:
Domain "app.example.com" is already in use (it's attached elsewhere) or "..." is not a valid public hostname.
(a bare IP, localhost, a single-label name, or a label longer than 63 characters). A free subdomain
(<slug>.<domain>) is saved as an ordinary custom domain, so it goes through the same checks.
Deployment & build failures
The build went red — here's how to read the failure and fix the usual causes, from a wrong build command to a compose deploy that needs a decision.
GitHub connection & repos
Fix an expired or unauthorized GitHub connection, a private repo that won't import, a public repo that should just work, and auto-deploy webhooks that never fire.