DjangoServer

Run Multiple Django Projects behind Nginx Proxy

You have 2 or more Django applications. You wish to hook each to a separate domain. Behind the scenes, they’re two or more separate gunicorn instances. How do you proxy to the gunicorn instances via Nginx? Here’s how it works.

A few assumptions

  • Our domains are one.example.com and two.example.com
  • We’re using Gunicorn
  • We’re using Nginx
  • It’s a Django Project we’re handling.
  • This won’t teach you how to setup your Django
  • This assumes you know your stuff around your VPS.
  • We’re using virtualenvwrapper
  • Django project One is in the folder, /home/yourUsername/One
  • Django project Two is in the folder, /home/yourUsername/Two

SystemD, baby

Previously, it used to be Upstart. Nowadays, it is SystemD. In case you don’t know the difference, just assume SystemD is better.

SystemD will be responsible to start our applications whenever the system is restarted. Now, open your eyes.

/etc/systemd/system/one.example.service

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=yourUsername
Group=www-data
WorkingDirectory=/home/yourUsername/One
ExecStart=/home/yourUsername/.virtualenvs/one/bin/gunicorn --workers 3 --bind unix:/home/yourUsername/One/one.sock One.wsgi:application

[Install]
WantedBy=multi-user.target

Don’t worry, here are what the above means:

  • yourUsername is your username. That’s the logged in user.
  • one is where the root project of the Django application is. In this case, where the manage.py is as well
  • We’re using virtualenvwrapper thus our virtual environments for pip are within the ~/.virtualenvs You could put it literally anywhere you want. Just point to it.
  • We’re using unix:sock approach here. You can read about what that is.
  • If you created your Django project using the command, django-admin.py startproject One, the One.wsgi:application would be found within the One/One/wsgi.pyfile. Notice we’re pointing to the file without the extension. In the wsgi.py file, there’s the application function
  • The virtual environment for the one above was created using the command, mkvirtualenv one

The rest of the file is just straightforward.

Create the above file too for the Django project two. Just change the parts to point to the Django Project Two directory instead.

‘Boosu Keena’, Nginx

Don’t worry what the ‘Boosu Keena’ means. The focus is on Nginx.

Here will be our Nginx configuration that will proxy the requests to Gunicorn internally. Now since we’re using unix socks instead of HTTP (used for proxying to NodeJS-like run apps), there’s no need to define our upstream server block.

‘Unix socks’? What a lovely term!

So, here we go:

server {
    listen    443 ssl http2;
    root /home/yourUsername/One;
    index index.html index.htm;

    server_name one.example.com; 

    include /etc/nginx/ssl/ssl-params.conf;
    include /etc/nginx/ssl/one.example.ssl;

    error_log /var/log/nginx/one.example_error.log;
    access_log /var/log/nginx/one.example_access.log;

    location /media/  {
        alias /home/yourUsername/One/media/;
    }

    location /static/ {
	alias /home/yourUsername/One/static/;
    }

    # Below is the juice. We're proxying the request to the sock we created
    # earlier via the gunicorn process via SystemD
    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://unix:/home/yourUsername/One/one.sock;
    }
   
     location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
	expires 30d;
    }

    location /robots.txt {
        alias /home/yourUsername/One/static/robots.txt;
    }

    location /favicon.ico {
        alias /home/yourUsername/One/static/favicon.ico;
    }
}

server {
        listen 80;
        server_name one.example.com;
        return 301 https://$server_name$request_uri;
}

Some Litmus test

At this stage, what we’ve done, is it working?

We don’t know yet, so let’s find out

sudo systemctl start gunicorn
sudo systemctl enable gunicorn

Of course none of the above commands would work if you don’t have gunicorn installed. Then,

sudo systemctl daemon-reload

Doing the daemon-reload ensures new service files added, in our case, one.example.service and two.example.service are tucked into the SystemD fold and recognized.

At this point, if all is good, you should be able to run,

sudo systemctl status one.example.service

If it ain’t running, then sudo systemctl start one.example.service should bring it up.

Do check the status if any errors are coming up. If none, then we’re good on the site of gunicorn. Hurray!

Nginx

On the side of Nginx, let’s link the one.example.com and two.example.com files into the /etc/nginx/sites-enabled/folder. We do that via

sudo ln -s /etc/nginx/sites-available/one.example.com /etc/nginx/sites-enabled/

Then, we run

sudo nginx -t

If all passes, we’re good to go.

Reload Nginx. sudo service nginx reload

Conclusion

Is it working?

Now you noticed only the files for the Django Project One were created in the above explanations. Simply duplicate whatever the file, and replace with details related to the Django Project Two.

Lemme know in the comments if any issues.

Related Articles

Back to top button