How to configure nginx as a reverse proxy to a gunicorn socket

June 10, 2017 08:43am
by Thomas Tran



In the previous tutorial, we learned how to configure gunicorn to run our WSGI (Django) app to a socket. In this tutorial, we'll use nginx as a reverse-proxy to relay external web requests to that socket. We'll also configure nginx to serve static files.

Why nginx? A reverse proxy server sits behind a firewall in a private machine a directs client requests to the appropriate backend server. In our case, nginx will forward external requests to the gunicorn socket. There are many reasons why nginx is a good choice. Firstly, by intercepting requests toward the backend, it protects the identities of the backend. For instance, nginx buffers slow clients which, among other things, prevents denial-of-service attacks from malicious parties. Secondly, nginx can compress inbound and outbound data, so it speeds up the flow of traffic between clients and servers. Thirdly, it helps with load balancing, distributing client requests across a group of servers to maximizee speed and capacity utilization. This will be helpful with high traffic sites and multiple machines will be necessary to handle that many requests.


Install nginx

Firstly, we need to install nginx. Run the following command to install it:

sudo apt-get update
sudo apt-get install nginx

nginx will by default have its config files in the directory /etc/nginx/. The file /etc/nginx/nginx.conf contains default global nginx configs.


Configuring nginx

We'll create a additional server block which will tell nginx how to direct external requests to our gunicorn socket.

The directory /etc/nginx/sites-available/ contains additional configs servers on the machine. We'll create a file, which will contain our server block:

sudo vim /etc/nginx/sites-available/djangoapp

Now paste the following into that file and then save:


server {
	listen 80;
	server_name [your domain name or public ip];

	location /static/ {
		root /var/www/djangoapp/static/;
	}

	location / {
		include proxy_params;
		proxy_pass http://unix:/var/www/djangoapp/djangoapp.sock;
	}
}

In the file above, the directive listen 80 sets the port on which the server will accept requests. It will list to to port 80 by default for external requests.

The server_name directive specifies which server block is used for a given request. For instance, if you are serving your app to an IP, input your machine's public IP. If you are serving your app to a domain name, such as www.example.com, input that instead.

The directive location /static/ specifies where our static files are located. If you are serving to a domain name, static files will be served as www.example.com/static/example.css, for instance.

Finally, the location / directive tells nginx to relay any other requests in this server block to our socket, meaning that all other requests besides static files will be directed toward the socket, which will then be picked up by gunicorn and then processed. proxy_params contains somes useful header parameters which we definitely want to use.


Enabling and starting nginx

To enable these new configs, we'll connect this file to the sites-enabled directory. To do so, input the following commands:

sudo ln -s /etc/nginx/sites-available/djangoapp /etc/nginx/sites-enabled

Then, restart nginx with the command:

service nginx restart

Useful commands and troubleshooting

When working with systemctl, some systems allow you to use the service command to control services. In our case, the following comands are available to us:

service nginx start
service nginx stop
service nginx restart

If you run into permission errors, you probably have insufficient rights to run nginx with the djangoappuser. ngix also uses the security group www-data, so make sure to add djangoappuser to www-data. To do so, you can do the following:

sudo useradd -g www-data djangoappuser