Deploying 3-tier Backend Application Using Docker And Nginx

Arun PandeyArun Pandey
3 min read

Introduction

The 3-tier backend application comprises three containers:

  1. NGINX

  2. MySQL

  3. Django-App

This setup demonstrates how these components collaborate to deliver a robust, scalable, and maintainable web application.


What is NGINX?

NGINX acts as a reverse proxy, handling requests from clients and forwarding them to backend servers. Its functionalities include load balancing, caching, and SSL termination.

Key Uses of NGINX:

  1. Load Balancing:
    Distributes incoming requests across multiple servers to optimize resource use and avoid overloading a single server.

  2. Security and Anonymity:

    • Hides backend server details from clients, making it harder for attackers to target backend servers directly.

    • Acts as a security layer by filtering and blocking malicious requests.

  3. SSL/TLS Termination:

    • Handles SSL/TLS encryption for secure HTTPS connections.

    • Offloads this task from backend servers, improving performance.

  4. Caching:

    • Caches responses and serves them directly to clients.

    • Reduces response time and improves speed.

  5. Centralized Access Control and Authentication:
    Enforces authentication and authorization, serving as a single control point for managing access.


Important Things to Remember

  1. MySQL Data Directory:

    • If the MySQL data directory is created in your working directory, either remove it or provide the necessary permissions for the server to access it.
  2. Requirements for Docker-Compose File:

  • Dependency Check: Use depends_on to specify container dependencies.

  • Healthcheck: Ensures dependent containers only start when required services are ready.

  • Networks: Containers must be on the same network to interact.

docker network create --driver bridge my_bridge_network
#Volumes: Specify volumes in the services section of the compose file.
docker volume create my_volume
#Environment Variables: Use a .env file to set variables like:
DB_NAME=test_db
DB_USER=root
DB_PASSWORD=root
DB_PORT=3306
DB_HOST=mysql

NGINX Configuration Directory

The NGINX directory includes:

  1. Dockerfile

  2. default.conf

default.conf File Example

upstream django {
    server django_app:8000;
}

server {
    listen 80; # Default port for NGINX
    server_name localhost; # Replace with your server's IP address

    location / {
        proxy_pass http://django;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Key Points:

  • Upstream: Defines a group of backend servers (e.g., Django).

  • Proxy Settings: Configure headers to manage forwarded requests.

Dockerfile:

FROM nginx:1.23.3-alpine
COPY ./default.conf /etc/nginx/conf.d/default.conf

docker-compose.yml Example

version: "3.8"

services:
  nginx:
    build: ./nginx
    image: nginx
    container_name: "nginx_cont"
    ports:
      - "80:80"
    restart: always
    depends_on:
      - django_app
    networks:
      - three-tier

  mysql:
    image: mysql
    container_name: "mysql-3-tier"
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=test_db
    volumes:
      - three-tier-database:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-proot"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 60s
    networks:
      - three-tier

  django_app:
    container_name: "django_container"
    build:
      context: .
    image: django_app
    ports:
      - "8000:8000"
    restart: always
    command: sh -c "python manage.py migrate --noinput && gunicorn notesapp.wsgi --bind 0.0.0.0:8000"
    env_file:
      - ".env"
    depends_on:
      - mysql
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:8000/admin || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    networks:
      - three-tier

networks:
  three-tier:

volumes:
  three-tier-database:

Command Explanation

sh -c "python manage.py migrate --noinput && gunicorn notesapp.wsgi --bind 0.0.0.0:8000"
python manage.py migrate --noinput:
   # Applies pending database migrations.
   # Ensures database schema syncs with Django models.
gunicorn notesapp.wsgi --bind 0.0.0.0:8000:
    # Launches the Django application using Gunicorn.
    # Listens on all network interfaces (0.0.0.0) and port 8000.

Key Highlights

  1. The .env file manages sensitive configurations (e.g., database credentials).

  2. A named volume (three-tier-database) ensures data persistence for MySQL.

  3. NGINX serves as a central point for load balancing, caching, and security.

  4. Docker Compose simplifies orchestration, ensuring service dependencies are met.

This structured setup ensures a reliable, scalable, and high-performance backend architecture.

0
Subscribe to my newsletter

Read articles from Arun Pandey directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Arun Pandey
Arun Pandey