How to deploy Angular with SSR and Django Rest Framework separately but on the same server

Most of the tutorials say that you have to integrate Angular into Django but I do not want to do that.

I want to deploy both on the same server with Angular using Node.js Express and Django using Gunicorn.

But I do not know how to do it. I know how to deploy Angular with SSR and Django but not both on the same server.


I will tell you how to do what you have asked, but I will also tell you about a method that is more efficient, stable and fast.

Skip to Recommended Method for my recommended method.


Most of the tutorials say that you have to integrate Angular into Django

I don't know why these tutorials say you need to integrate Angular into Django, as they do not integrate with each other, they work together. The frontend (in this case Angular) will make requests to a backend (in this case Django Rest Framework) and display information to the user. They don't exist together as a single code base.

I want to deploy both on the same server

Before I begin, I should say that I have lots of industry experience in managing production services, and I advise against this. Usually, you would have each service sitting behind load balancers, since running backend code requires more resources than delivering frontend bundles.

You can either have the frontend and backend on the same server or on different servers, but both solutions will require a reverse proxy and load balancer like NGINX, which can deliver the frontend bundle and data from the backend, with two configuration files.

This NGINX config would return the index.html file from the frontend in /var/www/example:

# example.com.conf
server {
    root /var/www/example;
    index index.html;

    server_name example.com;
    location / {
        try_files $uri $uri/ = 404;
    }

    listen 443 ssl;
    ssl_certificate /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;
    include /path/to/options-ssl-nginx.conf;
}

server {
    listen       80;
    listen [::]:80;
    server_name  example.com;

    include /path/to/encrypt.conf;

    location / {
        return 301 https://example.com$request_uri;
    }
}

And this NGINX config would allow the frontend to make requests to the backend via the endpoint api.example.com:

# api.example.com.conf
server {
    server_name api.example.com;

    listen 443 ssl;
    ssl_certificate /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;
    include /path/to/options-ssl-nginx.conf;

    location / {
        proxy_pass http://0.0.0.0:8000;
        proxy_set_header Host $myhost;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_redirect off;
    }
}

server {
    listen       80;
    listen [::]:80;
    server_name  api.example.com;

    include /path/to/encrypt.conf;

    location / {
        return 301 https://api.example/com$request_uri;
    }
}

Deployment

There are a few ways to do this:

Run the services on a server

This is the more traditional method, and involves installing all your app's dependencies such as Node.js, Python and NGINX on a server yourself. Since the production server environment is different from your development environment (e.g. production is an Ubuntu server and development is a Macbook), there is a high chance of something breaking.

And whenever you update your code, you don't want to mess with the production server, so you will need to create a new server, install all the dependencies again ... It's a lot of work.

Run the services on a server with Docker

I can't express enough how amazing and useful Docker is! It allows you to run your code inside virtualised, isolated containers that run the same no matter the host environment, and without slowing down your app.

This is great, you can do exactly the same as above, but containerise the frontend and backend, and containerise the NGINX proxy, and then let the NGINX container route requests to different containers or servers, with this config for example:

    location / {
        proxy_pass http://drf-container:8000;

This means that you can now run the same code in development, staging, and production knowing that the results will be the same even when deploying.

Run the services on a cluster with Docker (most popular)

I have managed servers on both AWS and DigitalOcean.

AWS allows you to start a cluster of servers and upload Docker images to their repository, and start Docker container instances with pre-allocated resource limits, and AWS will automatically deploy them to the cluster. This is great because AWS also allows you to seamlessly create a new container, and if it is healthy, AWS will automatically drain connections from the old container to the new container, and remove the old container. This means extremely fast, safe and efficient deployments.

DigitalOcean now offers something similar. DigitalOcean Kubernetes can do exactly the same as what I described AWS does above, but with just a little more manual setup.

Summary

I hope the above helped clear up the deployment of Django and Angular. It boils down to having the following three Docker containers:

  1. Angular container (containing the Angular app dependencies and codebase)
  2. Django container (containing the Django Rest Framework dependencies and codebase)
  3. NGINX container (containing the production bundle from the Angular container, and a .conf file containing the configuration to proxy-pass to the Django container)

And then deploying those containers to a server or cluster.

Recommended Method

With serverless becoming popular, my personal setup is a microservices backend (in Python or Go) hosting GraphQL APIs in a Docker cluster as described above. Apollo can run serverless or in a server, and combines all my microservice GraphQL APIs into a single endpoint that my frontend can query. No need for NGINX, very scalable and very easy development and deployment.