Flask Domain and DNS Setup for Production
If you're trying to point a domain to a Flask app in production, this guide shows you how to set up DNS and connect the domain to your server step-by-step. The goal is to make the domain resolve correctly, reach Nginx, and be ready for HTTPS.
Quick Fix / Quick Setup
Use this when you have a single VPS with a public IPv4 address and Nginx in front of Gunicorn.
# 1) Get your server public IP
curl -4 ifconfig.me
# 2) At your DNS provider, create records
# Replace values with your real domain and IP
# A record
@ A YOUR_SERVER_IP
# Optional www record
www CNAME @
# 3) Verify DNS propagation
dig +short example.com A
dig +short www.example.com
# 4) Point Nginx server_name to the domain
sudo nano /etc/nginx/sites-available/flask_app
# server_name example.com www.example.com;
# 5) Test and reload Nginx
sudo nginx -t
sudo systemctl reload nginx
# 6) Confirm the domain reaches the server
curl -I http://example.com
After DNS resolves correctly over HTTP, continue with your HTTPS setup.
What’s Happening
A domain only reaches your Flask app after DNS points the hostname to the correct public server endpoint. Nginx must also recognize that hostname through server_name, or requests may hit the wrong virtual host. DNS changes are cached by resolvers, so updates may not appear immediately. This setup should be complete before issuing TLS certificates.
Step-by-Step Guide
- Identify the public endpoint
For a VPS, get the public IPv4 address:bashcurl -4 ifconfig.me
If you use a load balancer, use its static IP or provider hostname instead. - Decide which hostnames to serve
Typical production setup:example.comas apexwww.example.comas alias
Choose one canonical host. Common options:wwwredirects to apex- apex redirects to
www
- Create the apex DNS record
In your DNS provider dashboard, edit the zone for your domain and add:txt@ A YOUR_SERVER_IP
If using IPv6 and the server is actually reachable over IPv6, also add:txt@ AAAA YOUR_SERVER_IPV6
Do not addAAAAunless IPv6 is working end-to-end. - Create the
wwwrecord
For a standard VPS setup, add:txtwww CNAME @
If your provider requires the full hostname:txtwww CNAME example.com
If you are pointing the apex to a load balancer hostname, useALIASorANAMEat the root if your DNS provider supports it. - Use a practical TTL during rollout
Set a low TTL such as300seconds while changing records. Increase it later after validation. - Update your Nginx server block
Open your Nginx site config:bashsudo nano /etc/nginx/sites-available/flask_app
Make sure it includes the production hostnames:nginxserver { 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-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
If needed, enable the site:bashsudo ln -s /etc/nginx/sites-available/flask_app /etc/nginx/sites-enabled/ - Test and reload Nginxbash
sudo nginx -t && sudo systemctl reload nginx
Do not continue untilnginx -tpasses. - Verify DNS resolution
From your machine, check the apex record:bashdig +short example.com A
Check thewwwhost:bashdig +short www.example.com
The result must match your intended production endpoint. - Verify the domain reaches Nginxbash
curl -I http://example.com curl -I http://www.example.com
Expected results include:200 OK301 Moved Permanently404 Not Foundfrom your app or Nginx
Unexpected results include:- timeout
- connection refused
- unrelated website response
- Open port 80 if DNS resolves but requests fail
On Ubuntu with UFW:bashsudo ufw allow 80/tcp sudo ufw status
Also confirm your cloud firewall or security group allows inbound TCP80. - Check for conflicting Nginx virtual hosts
If multiple sites run on the same server, verify the intended site is enabled:bashls -l /etc/nginx/sites-enabled/ sudo nginx -T | less
Remove or disable conflicting default hosts if necessary. - Proceed to HTTPS after HTTP works
Once DNS resolution and HTTP reachability are confirmed, move to TLS setup.
Common Causes
- Wrong A record → The domain points to an old or incorrect IP → Update the record to the current server IP and verify with
dig +short. - Missing
wwwrecord →example.comworks butwww.example.comfails → Add aCNAMEforwwwand include it in Nginxserver_name. - Nginx
server_namemismatch → DNS resolves correctly but the wrong site responds → Updateserver_nameand reload Nginx. - DNS propagation delay → Some networks still resolve the previous record → Check multiple resolvers and wait for cache expiry.
- Cloud firewall closed → DNS resolves but the browser times out → Open inbound TCP
80and later443in both OS and provider firewall. - AAAA record misconfigured → IPv6 clients fail while IPv4 works → Remove the
AAAArecord or configure IPv6 correctly. - Registrar nameserver mismatch → Changes in one DNS panel have no effect → Confirm the domain uses the nameservers for the DNS zone you edited.
- Proxy/CDN interference → Proxy mode changes origin behavior during setup → Use DNS-only mode while validating origin connectivity.
Debugging Section
Check DNS, Nginx, and network path in this order.
DNS checks
dig example.com
dig @1.1.1.1 example.com
dig @8.8.8.8 example.com
dig NS example.com +short
dig +short example.com A
dig +short www.example.com
What to look for:
- active nameservers match the provider you edited
- apex resolves to the correct IP or alias target
wwwresolves to the expected canonical host- public resolvers return the same result after propagation
HTTP reachability checks
curl -I http://example.com
curl -I http://www.example.com
What to look for:
- response from your server, not timeout
- status like
200,301, or app-generated404 - expected redirect behavior for canonical host
Nginx validation
sudo nginx -t
sudo nginx -T | less
sudo systemctl reload nginx
What to look for:
- syntax test passes
- correct
server_nameentries are loaded - expected site is enabled
- no conflicting default server block captures traffic
Port and listener checks
sudo ss -tulpn | grep ':80\|:443'
What to look for:
- Nginx is listening on port
80 - later, Nginx should also listen on
443after TLS setup
Live Nginx logs
sudo tail -f /var/log/nginx/access.log /var/log/nginx/error.log
What to look for:
- incoming requests for your domain
- host header used by clients
- upstream or vhost errors
Checklist
- Domain uses the expected authoritative nameservers.
- Apex domain has a correct
Arecord to the production IP or anALIAS/ANAMEto the load balancer. -
wwwhostname has a correctCNAMEor equivalent record. - No invalid
AAAArecord exists unless IPv6 is configured and reachable. - Nginx
server_nameincludes the exact production hostnames. - Nginx config passes
nginx -tand has been reloaded. - Port
80is open in OS firewall and cloud firewall/security group. -
dig +shortreturns the expected IP or hostname. -
curl -I http://domainreaches Nginx successfully. - The site is ready for HTTPS setup after HTTP validation.
Related Guides
- Deploy Flask with Nginx + Gunicorn (Step-by-Step Guide)
- Deploy Flask on Ubuntu VPS (Step-by-Step)
- Flask Production Checklist (Everything You Must Do)
FAQ
Q: Should I point my domain directly to Gunicorn?
A: No. Point the domain to Nginx or your load balancer. Nginx should proxy requests to Gunicorn.
Q: Should I use A or CNAME for the root domain?
A: Use an A record for a VPS IP. If pointing apex to a provider hostname, use ALIAS/ANAME if your DNS provider supports it.
Q: How long does DNS propagation take?
A: Often a few minutes, but cached resolvers may take longer depending on TTL and previous records.
Q: Why does the domain resolve but the wrong website loads?
A: Nginx is likely matching a different server block. Check server_name, enabled sites, and the default host.
Q: Do I need DNS working before HTTPS?
A: Yes. Certificate issuance and validation depend on the domain resolving to the correct server or validation endpoint.
Q: Should I create an AAAA record?
A: Only if your server is configured for IPv6 and reachable over IPv6. Otherwise omit it.
Q: Why does DNS look correct on my machine but not for other users?
A: Resolver caching and TTL differences can cause temporary mismatches. Check multiple public resolvers.
Q: Do I need both apex and www records?
A: Only if you want both hostnames to work. If so, configure DNS and an Nginx redirect strategy for one canonical host.
Final Takeaway
Production domain setup is a two-part match: DNS must point to the correct public endpoint, and Nginx must recognize the same hostnames. Validate DNS first, then validate HTTP reachability, and only then move to HTTPS.