How to deploy Django and Vue using Nginx

Fran Lendínez
4 min readAug 27, 2019
Photo by Carlos Muza on Unsplash

Deployment is an art. We can do it as difficult and complex as we can, but we can’t forget that complexity and maintainability usually are opposite concepts.

To do it easy, we will follow the KISS philosophy. So we go:

Prepare the ingredients

As a kitchen recipe, we need ingredients and these are the ones we need:

  • Django project ready to prod
  • Vue project ready to prod
  • An instance of UNIX-Like server (I pref Ubuntu)

Prepare the instance

Create a user to run the application

For security reasons, it is a good practice to run the application with a non-root user.

$ sudo adduser <app_name> # Add user
$ sudo passwd -l <app_name> # Look login via username-password

Install Docker

Docs

We can use this script-like block to install Docker. You can follow step by step or copypaste it.

# Update apt first as a good practice
sudo apt-get update
# Install docker dependencies
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
# Add docker GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# Setting up the repository
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
# Update the package index
sudo apt-get update
# Install docker
sudo apt-get install docker-ce docker-ce-cli containerd.io
# Try if it works
sudo docker run hello-world

Once we install Docker we must give the <app_name> permissions to run it.

# Create docker group
sudo groupadd docker
# Add <app_name> to group
sudo usermod -aG docker <app_name>
# Start on boot docker
sudo systemctl enable docker

Install docker-compose

Docs

sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-composesudo chmod +x /usr/local/bin/docker-compose

Add repositories into the server

In a real-world project, we normally use tools to make the continuous delivery of the code. But in this guide, we will focus only on the deploy phase.

$ scp -r django_project username@myhost_or_ip:/home/<app_name>/backend/

$ scp -r vue_project username@myhost_or_ip:/home/<app_name>/frontend/

Recipe for backend

Using docker-compose we can build all we need. This docker-compose configuration is just an example, build what you need.

docker-compose.yml

version: '3'

volumes:
local_postgres_data: {}
local_postgres_data_backups: {}

services:
django:
image: python:3.7
container_name: <app_name>_django
depends_on:
- postgres
volumes:
- .:/app
- ./static:/static
working_dir: /app
env_file:
- .env
ports:
- "8000:8000"
command: bash -c "pip install -r requirements.txt && python manage.py migrate --noinput && python manage.py collectstatic --noinput && gunicorn -w 4 -t 180 -b 0.0.0.0:8000 config.wsgi"

postgres:
image: postgres:11
container_name: <app_name>_postgres
volumes:
- local_postgres_data:/var/lib/postgresql/data
- local_postgres_data_backups:/backups
env_file:
- .env

redis:
image: redis:5
container_name: <app_name>_redis

Now we can execute and let it run over 8000 port.

# Change user to app_name
sudo -u <app_name> -i
# Go to backend directory
cd backend
# execute docker-compose
docker-compose up -d

To verify that everything is ok:

docker-compose ps
Name Command State Ports
---------------------------------------------------------------------------------------<app_name>_redis docker-entrypoint.sh redis ... Up 6379/tcp<app_name>_django bash -c pip install -r req ... Up 0.0.0.0:8000->8000/tcp<app_name>_postgres docker-entrypoint.sh postgres Up 5432/tcp

Recipe for frontend

In the same way, we use docker-compose to build without installing any dependency over the server.

version: '3'

services:
vue:
image: node:12
container_name: <app_name>_vue
volumes:
- ./:/code
working_dir: /code
env_file:
- .env
command: bash -c "npm i && npm run build"

Install and configure NGINX

The installation process is simple.

sudo apt install nginx

Let’s create a configuration file for our app

sudo nano /etc/nginx/sites-available/<app_name>

This configuration is an example, modify it what you need.

server {
server_name <domain>;

access_log /home/<app_name>/logs/nginx-access.log;
error_log /home/<app_name>/logs/nginx-error.log;

root /home/<app_name>/frontend/dist/;

client_max_body_size 10M;

location /static { # Serve the statics of backend
alias /home/<app_name>/backend/static;
}

location /media { # Serve the media of backend
alias /home/<app_name>/backend/media;
}
location / { # Catch all but defined routes to serve the frontend
try_files $uri $uri/ /index.html;
}

location ^~ /api/ { # Define routes to be directed to backend as proxy
include proxy_params;
proxy_pass http://0.0.0.0:8000;
}

location ^~ /admin {
include proxy_params;
proxy_pass http://0.0.0.0:8000;
}

location ^~ /sitemap.xml { # For example if you use django.contrib.sitemaps
include proxy_params;
proxy_pass http://0.0.0.0:8000;
}

}

Once you are ready, you must link the sites-available conf to sites-enabled and test the configuration.

sudo ln -s /etc/nginx/sites-available/<app_name> /etc/nginx/sites-enabled/<app_name>sudo nginx -t

If everything is ok, we can just restart NGINX

sudo service nginx restart

PLUS: Serve your content via HTTPS

First, we need to install dependencies of Certbot.

sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository universe
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update

Then, install Certbot

sudo apt-get install certbot python-certbot-nginx

And execute Certbot:

sudo certbot --nginx

Once you execute it, Certbot asks you if the content must be redirected to HTTPS, say yes.

We deploy it successfully, don’t we?

Take it into account that this approach is extremely simple but a good point to start. For example, we can build the images with our code and save it into a repository to pull and run the containers but in this guide, I tried to make it an example without building anything.

And that’s all. I hope you enjoy this guide and feel free to let some comments to give me feedback. This is my first post and I hope to contribute frequently.

--

--