Domain and DNS Configuration
The essential playbook for implementing domain and dns configuration in your SaaS.
Configure your domain before pointing production traffic at your app. For a small SaaS, this usually means setting correct A/AAAA or CNAME records, deciding whether www or apex is canonical, avoiding DNS mistakes that break HTTPS, and verifying requests reach Nginx or your platform correctly.
Quick Fix / Quick Setup
Use this baseline setup for a single VPS behind Nginx:
# Example DNS plan
# Apex/root domain -> server public IP
A example.com 203.0.113.10
# Optional IPv6
AAAA example.com 2001:db8::10
# www -> apex
CNAME www example.com
# API subdomain -> same server or separate service
A api.example.com 203.0.113.10
# Mail provider examples (set at your DNS host)
MX example.com 10 mail.provider.com
TXT example.com "v=spf1 include:_spf.provider.com ~all"
TXT default._domainkey "k=rsa; p=PUBLIC_KEY"
TXT _dmarc "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"
# Verify DNS from terminal
dig example.com A +short
dig www.example.com CNAME +short
dig api.example.com A +short
# Verify traffic reaches server
curl -I http://example.com
curl -I http://www.example.com
# Nginx server_name should match
server {
listen 80;
server_name example.com www.example.com;
location / {
proxy_pass http://127.0.0.1:8000;
}
}Use A records for root/apex domains and CNAME for subdomains like www when possible. Do DNS first, confirm records resolve, then issue HTTPS certificates.
What’s happening
- DNS maps your domain name to the IP address or hostname that serves your app.
- Your registrar controls domain ownership, but DNS may be hosted at the registrar or at a separate provider such as Cloudflare, Route 53, or DigitalOcean.
- Apex/root domains usually use
AorAAAArecords. Subdomains often useCNAME. - If DNS points to the wrong target, your app may return
404, timeout, show SSL failures, or serve another app on the same server. - DNS changes are cached. Old values may persist until TTL expires.
- DNS only gets traffic to the right destination. Your web server still needs to match the requested hostname.
request flow diagram showing Browser -> DNS provider -> Server IP -> Nginx -> Gunicorn/Uvicorn/App.
Step-by-step implementation
1. Decide your canonical hostname
Pick one primary host:
example.comwww.example.com
For most small SaaS apps:
- use apex for branding simplicity
- redirect
wwwto apex - or choose
wwwif your CDN or DNS provider works better with it
Be consistent. One host should be canonical.
2. Confirm where DNS is actually hosted
Do not assume your registrar hosts DNS.
Check authoritative nameservers:
dig NS example.com +shortIf the nameservers point to Cloudflare, Route 53, or another provider, make changes there, not only at the registrar dashboard.
3. Collect your deployment target
You need one of these:
- VPS public IPv4
- VPS public IPv6
- load balancer hostname
- platform target hostname
- CDN/proxy origin setup
For a VPS:
curl ifconfig.me
ip -6 addrOnly publish an AAAA record if your server is reachable over IPv6.
4. Create DNS records
Typical small SaaS setup:
A example.com 203.0.113.10
CNAME www example.com
A api.example.com 203.0.113.10If IPv6 is correctly configured:
AAAA example.com 2001:db8::10Set low TTL during setup:
TTL = 300Do not create conflicting records for the same name and type.
Bad example:
A example.com 203.0.113.10
A example.com 203.0.113.20
CNAME example.com target.provider.comUnless you intentionally want multiple A records, remove stale values.
5. Verify propagation
Check records from your local resolver and public resolvers:
dig example.com A +short
dig example.com AAAA +short
dig www.example.com CNAME +short
dig api.example.com A +short
dig @1.1.1.1 example.com A +short
dig @8.8.8.8 example.com A +short
nslookup example.com
host example.comIf public resolvers return the expected values, DNS is usually correct even if your laptop still shows an older result.
6. Align Nginx with DNS hostnames
DNS alone is not enough. Nginx must match the hostnames you plan to serve.
Example Nginx server block:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}Test config:
sudo nginx -t
sudo systemctl reload nginxIf you run multiple apps on one VPS, make sure each app has a precise server_name. Avoid overly broad defaults.
Related deployment guides:
7. Verify host-based routing before HTTPS
Test via the public domain:
curl -I http://example.com
curl -I http://www.example.comTest directly against the server IP using the Host header:
curl -H 'Host: example.com' http://203.0.113.10
curl -H 'Host: www.example.com' http://203.0.113.10This isolates Nginx routing from DNS.
If direct IP + Host works but the domain does not, the problem is usually DNS, caching, or a proxy layer.
8. Update framework host validation
Some frameworks reject unknown hosts.
Examples:
Django
ALLOWED_HOSTS = ["example.com", "www.example.com", "api.example.com"]FastAPI / Starlette trusted hosts
from starlette.middleware.trustedhost import TrustedHostMiddleware
app.add_middleware(
TrustedHostMiddleware,
allowed_hosts=["example.com", "www.example.com", "api.example.com"]
)Flask behind proxy
Make sure host and proxy headers are handled correctly if you enforce host validation or URL generation.
9. Issue HTTPS only after DNS is correct
Once:
- DNS resolves to the right target
- Nginx routes the hostname correctly
- port
80is open
Issue certificates.
If you use Let’s Encrypt with Nginx:
sudo certbot --nginx -d example.com -d www.example.comThen verify:
curl -k -I https://example.com
curl -k -I https://www.example.comFor the full TLS setup, see:
10. Add canonical redirects
If apex is primary:
server {
listen 80;
server_name www.example.com;
return 301 http://example.com$request_uri;
}After HTTPS is active:
server {
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
return 301 https://example.com$request_uri;
}Also redirect HTTP to HTTPS for the canonical host.
11. Add email-related DNS separately
Do not mix app DNS and mail DNS without documenting both.
Typical mail records:
MX example.com 10 mail.provider.com
TXT example.com "v=spf1 include:_spf.provider.com ~all"
TXT default._domainkey "k=rsa; p=PUBLIC_KEY"
TXT _dmarc "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"If you send transactional email from your app, keep these records documented for future migrations.
12. Document the final DNS plan
Store:
- registrar
- nameservers
- DNS provider
- canonical host
- all records
- server IPs
- TLS issuance method
- redirect rules
This avoids breakage during server moves, DNS provider migrations, or team handoff.
Common causes
Arecord points to the wrong server IP- DNS changes were made at the registrar while authoritative DNS is hosted elsewhere
- Old conflicting records still exist for the same hostname
- Apex domain was configured with an unsupported
CNAMEat the DNS provider AAAArecord exists but the server is not reachable over IPv6- Nginx
server_namedoes not include the requested domain - Framework host validation blocks the domain
- Cloudflare or another proxy is enabled before origin routing works
- Firewall blocks port
80or443 - HTTPS certificate was requested before DNS resolved correctly
Debugging tips
Start from DNS authority, then resolver output, then network reachability, then web server routing, then TLS.
Check authoritative nameservers
dig NS example.com +shortIf these are not the provider you edited, you changed the wrong DNS zone.
Check record resolution
dig example.com A +short
dig example.com AAAA +short
dig www.example.com CNAME +short
dig api.example.com A +short
dig @1.1.1.1 example.com A +short
dig @8.8.8.8 example.com A +shortCheck reachability
ping example.com
traceroute example.com
sudo ss -tulpn | grep -E ':80|:443'If the server is not listening on 80 or 443, DNS is not the main issue.
Test HTTP routing
curl -I http://example.com
curl -I http://www.example.com
curl -H 'Host: example.com' http://203.0.113.10Test Nginx config
sudo nginx -t
sudo systemctl reload nginxTLS-specific checks
curl -k -I https://example.comIf HTTPS fails right after DNS setup:
- confirm records resolve publicly
- confirm the certificate covers the exact hostname
- confirm any proxy/CDN SSL mode matches your origin
- confirm
80is open if using HTTP challenge validation
Process Flow
Checklist
- ✓ Registrar access confirmed
- ✓ Authoritative nameservers identified
- ✓ DNS hosted in the expected provider
- ✓ Apex/root record created
- ✓
wwwrecord created - ✓ Required subdomains added
- ✓ TTL reduced during setup
- ✓ No conflicting duplicate records
- ✓ Server public IP verified
- ✓ Nginx
server_namematches all domains - ✓ Framework allowed-host settings updated
- ✓ Port
80and443open in firewall - ✓ HTTP routing verified
- ✓ HTTPS issued after DNS validation
- ✓ Canonical redirect configured
- ✓ Mail DNS records configured if needed
- ✓ DNS records documented for future migrations
For broader release validation, use:
- SaaS Production Checklist
- SaaS Architecture Overview (From MVP to Production)
- Choosing a Tech Stack for a Small SaaS
- Structuring a Flask/FastAPI SaaS Project
Related guides
- Environment Setup on VPS
- HTTPS Setup (Let’s Encrypt)
- Deploy SaaS with Nginx + Gunicorn
- Logging Setup (Application + Server)
- 502 Bad Gateway Fix Guide
FAQ
Should I use apex or www as the main domain?
Either works. For small SaaS apps, apex is simpler for branding, while www can be easier with some DNS and CDN setups. Pick one canonical host and redirect the other.
Why does my domain resolve on one machine but not another?
DNS is cached by browsers, operating systems, ISPs, and recursive resolvers. Wait for TTL expiry or test against public resolvers like 1.1.1.1 and 8.8.8.8.
Can I use a CNAME on the root domain?
Usually no, unless your DNS provider supports ALIAS, ANAME, or CNAME flattening behavior at the apex. Otherwise use A/AAAA records.
When should I enable HTTPS?
After DNS resolves to the correct origin and your web server responds for the intended hostnames. Then issue certificates and add redirects.
Do I need separate domains for app and API?
Not always. You can serve both from one domain with path routing, or split them into subdomains like app.example.com and api.example.com if that fits your deployment and CORS model better.
Final takeaway
Good domain setup is mostly about consistency:
- correct DNS records
- correct Nginx host routing
- correct TLS order
Do DNS first, verify resolution, confirm the app answers the right Host header, then enable HTTPS and redirects.
Most production domain issues come from:
- editing the wrong DNS zone
- conflicting records
- mismatched
server_namesettings - publishing
AAAAwhen IPv6 is not actually working - enabling a proxy before the origin is correct
If you validate each layer in order, domain setup is straightforward and repeatable.