Getting rid of if directive in nginx configuration

Hassan Baig asked:

I have a Django app which has nginx as a reverse proxy with gunicorn as an application web server (upstream).

In the location / block of my nginx virtual host file, I refer to a unix socket in the web application server like so:

if (!-f $request_filename) {
    proxy_pass http://application_server;

Idea being that don’t need to get gunicorn to serve static assets, nginx ought to take care of them.

I have two related questions:
1) Performance wise, having that kind of if else type check on nginx can be costly. Have you seen that in your experience? My web app is a high traffic social forum and lots of static assets require serving. Thoughts, do’s and dont’s (if any)? Need more info?

2) It’s well documented that if is evil in an nginx context. How do I change the if directive with a try_files one? I gave it a shot myself; it looked straight-forward. But crashed and burnt every time. Here’s what I try:

  • Replace the entire if directive by try_files $uri @application_server;
  • Include a location @application_server block below location /; this contains proxy_pass http://application server.
  • There’s an upstream application_server block at the top of the config file (outside server), this contains a reference to the unix socket and fail_timout=0;.

Should have worked, no? Ask me for more info if you need it.

My answer:

The error you posted is returned by Django, because it cannot figure out the hostname part of the URL.

When you proxy from a web server, you have to pass through this header explicitly.

The critical line you are missing is:

location @application_server {
    proxy_set_header Host $http_host;

See also the sample nginx configuration in the gunicorn documentation.

View the full question and answer on Server Fault.

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.