Every App answers on https://<name>.jetdeploy.app from its first deploy. Serving it on your own domain adds three things to get right: the DNS records, the order of the steps, and what your application does with the new host name. This guide goes through them for example.com and www.example.com.
Direct or proxy
Pick the routing mode first, because the DNS records depend on it.
| Direct | Proxy | |
|---|---|---|
| DNS points to | JetDeploy's IP addresses | your CDN or WAF (Cloudflare, CloudFront…) |
| HTTPS certificate | issued and renewed by JetDeploy | your CDN's towards visitors, JetDeploy's towards the origin |
| Records to create | one A record per JetDeploy address |
the proxy setup, plus a TXT record |
| Visitor's IP in the App | X-Real-Ip, X-Forwarded-For |
the header your CDN adds, such as CF-Connecting-IP |
Without a CDN already in place, choose direct.
1. Add the domains
In the Console, add example.com and www.example.com as two domains. Each domain page lists the records it needs. Through the API:
curl -sS -X POST -H "Authorization: Bearer $JD_TOKEN" -H 'Content-Type: application/json' \
-d '{"name": "www.example.com"}' https://jetdeploy.com/api/v1/domains
The answer carries dns_target, the IP addresses to use, and verification_record, which is null unless a TXT record is needed.
2. Create the DNS records
In direct mode, create one A record for each address, on the apex and on www alike:
example.com. 300 IN A <address 1 shown on the domain page>
example.com. 300 IN A <address 2 shown on the domain page>
example.com. 300 IN A <address 3 shown on the domain page>
www.example.com. 300 IN A <address 1 shown on the domain page>
www.example.com. 300 IN A <address 2 shown on the domain page>
www.example.com. 300 IN A <address 3 shown on the domain page>
Create one record per address listed, not just one. The same addresses are the organization's inbound_ips in the API.
A CNAME works too, between your own names. www.example.com CNAME example.com validates, as long as the chain ends on the A records above. A CNAME to my-app.jetdeploy.app does not: no name in the chain may be under jetdeploy.app.
A TXT record is also required in proxy mode, and in direct mode when another organization holds the name or held it recently. The domain page shows it when it applies:
_jetdeploy.www.example.com. 300 IN TXT "<token shown on the domain page>"
3. Validate
Click Validate on each domain. JetDeploy asks your authoritative nameservers directly, so there is no propagation delay to wait out. When something is missing, the API answers 409 with code domain_unvalidated, and the hint lists the exact records still to create.
Keep the records afterwards. They are checked again every day, and a domain that is never validated is removed after 7 days.
4. Attach and apply
Attach both domains to the App, then click Apply. A domain is routed only when it is both validated and applied. From that moment JetDeploy requests the certificate in the background, usually within a couple of minutes.
Follow it on the domain page, or through the API:
curl -sS -H "Authorization: Bearer $JD_TOKEN" \
https://jetdeploy.com/api/v1/domains/9 | jq .certificate
certificate.status |
Meaning |
|---|---|
pending |
being requested, message says what it waits for |
issued |
HTTPS is live on the domain |
failed |
message says why; after a rate limit, retry_at says when a new attempt is accepted |
none |
no certificate yet, message says what is needed |
unknown |
the status could not be read right now; check again shortly |
5. Redirect one name to the other
Serve the site on one name and redirect the other, so search engines and cookies see a single host. With both domains attached to the App, add a redirect rule from example.com to www.example.com on the App page. It is a permanent redirect and keeps the path, so example.com/pricing goes to www.example.com/pricing.
Plain http:// needs no rule: the edge already redirects it to https://, with a 301 for GET and a 308 for other methods.
6. Tell the application
The App now receives a new Host header. Frameworks that check it refuse the request until you add the domain:
# Django
ALLOWED_HOSTS=www.example.com,example.com,my-app.jetdeploy.app
Rails checks the host in production only when config.hosts is set. If yours sets it, list every name the App answers on, the default host included, or requests to the missing ones are blocked:
# Rails, config/environments/production.rb
config.hosts += ["www.example.com", "example.com", "my-app.jetdeploy.app"]
Update the base URL your application uses in emails, OAuth callbacks and webhooks too. An environment variable change goes live with the next Apply.
Moving a live site
When example.com already serves traffic from another host, the switch happens when you change the A records. To keep it short:
- Lower the TTL of the existing records to 300 seconds a day in advance.
- Add and attach the domains in JetDeploy, update
ALLOWED_HOSTS, and apply. - Change the records, then validate and apply right away.
- Check
certificate.statusuntil it readsissued.
Between the record change and the issued certificate, visitors reaching JetDeploy over HTTPS on the new name get a certificate error, so choose a quiet moment for the switch.
Proxy mode with a CDN
- Set the domain to proxy mode and create the
TXTrecord. - In the CDN, set the origin to the JetDeploy addresses, or to a name of yours with
Arecords to them, over HTTPS. - Point the domain at the CDN as the CDN instructs.
The connecting address is now the CDN's. The visitor's address arrives in the CDN's own header, such as CF-Connecting-IP. Trust that header only when X-Real-Ip is one of the CDN's published addresses, since anyone can reach the origin directly and set it.
Next step
The Domains section of the docs has the full rules, including switching a validated domain between direct and proxy mode. To keep automated traffic away from the new domain, see AI Crawler & Bot protection.