Reference Guide Detailed deployment notes with production context and concrete examples.

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.

bash
# 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

  1. Identify the public endpoint
    For a VPS, get the public IPv4 address:
    bash
    curl -4 ifconfig.me
    

    If you use a load balancer, use its static IP or provider hostname instead.
  2. Decide which hostnames to serve
    Typical production setup:
    • example.com as apex
    • www.example.com as alias

    Choose one canonical host. Common options:
    • www redirects to apex
    • apex redirects to www
  3. 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 add AAAA unless IPv6 is working end-to-end.
  4. Create the www record
    For a standard VPS setup, add:
    txt
    www   CNAME   @
    

    If your provider requires the full hostname:
    txt
    www   CNAME   example.com
    

    If you are pointing the apex to a load balancer hostname, use ALIAS or ANAME at the root if your DNS provider supports it.
  5. Use a practical TTL during rollout
    Set a low TTL such as 300 seconds while changing records. Increase it later after validation.
  6. Update your Nginx server block
    Open your Nginx site config:
    bash
    sudo nano /etc/nginx/sites-available/flask_app
    

    Make sure it includes the production hostnames:
    nginx
    server {
        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:
    bash
    sudo ln -s /etc/nginx/sites-available/flask_app /etc/nginx/sites-enabled/
    
  7. Test and reload Nginx
    bash
    sudo nginx -t && sudo systemctl reload nginx
    

    Do not continue until nginx -t passes.
  8. Verify DNS resolution
    From your machine, check the apex record:
    bash
    dig +short example.com A
    

    Check the www host:
    bash
    dig +short www.example.com
    

    The result must match your intended production endpoint.
  9. Verify the domain reaches Nginx
    bash
    curl -I http://example.com
    curl -I http://www.example.com
    

    Expected results include:
    • 200 OK
    • 301 Moved Permanently
    • 404 Not Found from your app or Nginx

    Unexpected results include:
    • timeout
    • connection refused
    • unrelated website response
  10. Open port 80 if DNS resolves but requests fail
    On Ubuntu with UFW:
    bash
    sudo ufw allow 80/tcp
    sudo ufw status
    

    Also confirm your cloud firewall or security group allows inbound TCP 80.
  11. Check for conflicting Nginx virtual hosts
    If multiple sites run on the same server, verify the intended site is enabled:
    bash
    ls -l /etc/nginx/sites-enabled/
    sudo nginx -T | less
    

    Remove or disable conflicting default hosts if necessary.
  12. 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 www recordexample.com works but www.example.com fails → Add a CNAME for www and include it in Nginx server_name.
  • Nginx server_name mismatch → DNS resolves correctly but the wrong site responds → Update server_name and 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 80 and later 443 in both OS and provider firewall.
  • AAAA record misconfigured → IPv6 clients fail while IPv4 works → Remove the AAAA record 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

bash
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
  • www resolves to the expected canonical host
  • public resolvers return the same result after propagation

HTTP reachability checks

bash
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-generated 404
  • expected redirect behavior for canonical host

Nginx validation

bash
sudo nginx -t
sudo nginx -T | less
sudo systemctl reload nginx

What to look for:

  • syntax test passes
  • correct server_name entries are loaded
  • expected site is enabled
  • no conflicting default server block captures traffic

Port and listener checks

bash
sudo ss -tulpn | grep ':80\|:443'

What to look for:

  • Nginx is listening on port 80
  • later, Nginx should also listen on 443 after TLS setup

Live Nginx logs

bash
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 A record to the production IP or an ALIAS/ANAME to the load balancer.
  • www hostname has a correct CNAME or equivalent record.
  • No invalid AAAA record exists unless IPv6 is configured and reachable.
  • Nginx server_name includes the exact production hostnames.
  • Nginx config passes nginx -t and has been reloaded.
  • Port 80 is open in OS firewall and cloud firewall/security group.
  • dig +short returns the expected IP or hostname.
  • curl -I http://domain reaches Nginx successfully.
  • The site is ready for HTTPS setup after HTTP validation.

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.