Configuring Nginx Without Domain: Static IP and Port-Based Access for Django/Gunicorn Deployment


3 views

When setting up Nginx as a reverse proxy for Django/Gunicorn without a domain name, the server_name directive becomes optional. Here's what you need to know:

server {
    listen 9050;  # Your desired port
    server_name _;  # Wildcard catch-all
    
    location / {
        proxy_pass http://localhost: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;
    }
}

The underscore (_) is a conventional placeholder when no domain is specified. The critical elements are:

  • listen 9050 - Matches your desired access port
  • proxy_pass - Points to your Gunicorn server
  • Header forwarding - Essential for Django to handle requests properly

Here's a more robust configuration including static files and error handling:

server {
    listen 9050;
    server_name _;
    client_max_body_size 4G;

    location /static/ {
        alias /path/to/your/static/files/;
        expires 30d;
    }

    location / {
        proxy_pass http://localhost:8000;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
        proxy_buffering off;
        
        # Timeout settings
        proxy_connect_timeout 300s;
        proxy_send_timeout 300s;
        proxy_read_timeout 300s;
        send_timeout 300s;
    }

    error_page 500 502 503 504 /500.html;
    location = /500.html {
        root /path/to/error/pages;
    }
}

After implementing this configuration:

  1. Test Nginx configuration: sudo nginx -t
  2. Reload Nginx: sudo systemctl reload nginx
  3. Verify accessibility: curl http://your.static.ip:9050

When exposing your server via IP address only:

  • Implement firewall rules to restrict access
  • Consider using HTTPS even without a domain (Let's Encrypt supports IP addresses)
  • Regularly monitor server logs for suspicious activity

When deploying a Django application with Nginx+Gunicorn, many developers face confusion about the server_name directive when they only want to expose the service via a static IP address without domain names. The key question is whether this directive is mandatory or can be omitted.

For IP-only access, you can completely omit the server_name directive or use an underscore as placeholder. Here's the most basic working configuration:

server {
    listen 9050;
    # server_name _;  # This line can be included or omitted
    server_tokens off;

    location / {
        proxy_pass http://localhost: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;
    }
}

When exposing via IP only, pay special attention to:

# Always disable server tokens in production
server_tokens off;

# Consider limiting access by IP if possible
allow 192.168.1.0/24;
deny all;

Here's a full configuration for Django with Gunicorn:

server {
    listen 9050;
    client_max_body_size 4G;
    
    location /static/ {
        alias /path/to/your/static/files/;
    }
    
    location /media/ {
        alias /path/to/your/media/files/;
    }
    
    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://localhost:8000;
    }
    
    error_page 500 502 503 504 /500.html;
    location = /500.html {
        root /path/to/your/templates/;
    }
}

If you can't access via IP:Port, check:

1. Verify Nginx is running: sudo systemctl status nginx
2. Check firewall rules: sudo ufw status
3. Test Gunicorn separately: curl http://localhost:8000
4. Examine Nginx logs: tail -f /var/log/nginx/error.log

For better performance with static IP access:

location / {
    proxy_buffering on;
    proxy_buffer_size 4k;
    proxy_buffers 24 4k;
    proxy_connect_timeout 30s;
    proxy_read_timeout 86400s;
    proxy_send_timeout 30s;
    keepalive_timeout 65;
}