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 portproxy_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:
- Test Nginx configuration:
sudo nginx -t
- Reload Nginx:
sudo systemctl reload nginx
- 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;
}