DEV Community

Cover image for πŸš€ Deploying a 3-tier Application with Docker and Nginx Proxy Manager 🌐
akintola abdulazeez oladele
akintola abdulazeez oladele

Posted on

πŸš€ Deploying a 3-tier Application with Docker and Nginx Proxy Manager 🌐

Welcome, tech enthusiast!. I’m excited to walk you through deploying a 3-tier application using Docker and Nginx Proxy Manager. If you've ever felt overwhelmed by the complexity of full-stack development, this guide is your friendly companion, designed to make the process smooth and straightforward. Let’s dive in!

πŸ“‚ Project Structure

Our project is neatly organized into two main directories:

  • frontend/: Houses the ReactJS application.
  • backend/: Contains the FastAPI application and PostgreSQL database integration.

Here’s the project structure for a quick reference:

/project-root
/frontend
Dockerfile
package.json
src/
public/
.env
/backend
Dockerfile
pyproject.toml
poetry.lock
app/
.env
docker-compose.yml
Enter fullscreen mode Exit fullscreen mode

Initial Setup: Cloning the Repository

First things first, let’s clone the project repository. Open your terminal and run:

git clone https://github.com/Hayzedak/hng2.git
cd hng2
Enter fullscreen mode Exit fullscreen mode

This repository serves as a demo application, perfect for interns or anyone looking to get their hands dirty with full-stack development.

πŸ–₯️ Manual Deployment: Setting Up on Ubuntu

Step 1: Install Prerequisites

Let’s ensure our system is up-to-date and ready for action:

sudo apt update
Enter fullscreen mode Exit fullscreen mode

Now let's install Git, PostgreSQL, Node.js, and npm:

sudo apt install git postgresql nodejs npm
Enter fullscreen mode Exit fullscreen mode

Step 2: Setting Up Poetry

We’ll use Poetry for managing our Python dependencies:

curl -sSL https://install.python-poetry.org | python3 -
Enter fullscreen mode Exit fullscreen mode

Add Poetry to your system's PATH:

echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
Enter fullscreen mode Exit fullscreen mode
source ~/.bashrc
Enter fullscreen mode Exit fullscreen mode

Step 3: Configuring PostgreSQL

Set up PostgreSQL to match the configuration in the .env file located in the backend directory:

sudo -u postgres psql
Enter fullscreen mode Exit fullscreen mode

Then,

CREATE DATABASE app;
CREATE USER app WITH ENCRYPTED PASSWORD 'changethis123';
GRANT ALL PRIVILEGES ON DATABASE app TO app;
Enter fullscreen mode Exit fullscreen mode

These commands create a new database and user, and grant all privileges on the database to the user.

Step 4: Backend Setup

Navigate to the backend directory and install dependencies.

Install necessary dependencies:

poetry install
Enter fullscreen mode Exit fullscreen mode

Set up the database:

poetry run bash ./prestart.sh
Enter fullscreen mode Exit fullscreen mode

Run the FastAPI server:

poetry run uvicorn app.main:app --reload
Enter fullscreen mode Exit fullscreen mode

Step 5: Frontend Setup

Now, let’s get the frontend up and running.

Install the necessary dependencies, and start the development server:

npm install
npm run dev
Enter fullscreen mode Exit fullscreen mode

Update your .env files with your machine's IP address:

VITE_API_URL=http://<your_ip>:8000
BACKEND_CORS_ORIGINS=http://<your_ip>:5173

Now let's test by going to the browser:

http://:5173 => Frontend

http://:8000/api => Backend

http://:8000/docs => Backend Docs

http://:8000/redoc => Backend Redoc

http://:8080 => Adminer

http://:8090 => Proxy Manager GUI

☁️ Deploying to EC2

Deploying our application to AWS EC2 involves a few additional steps.

Step 1: Clone Repository and Update .env Files

SSH into your EC2 instance and clone the repository.

git clone https://github.com/Hayzedak/hng2.git
cd hng2
Enter fullscreen mode Exit fullscreen mode

Update the .env files with your domain information:

VITE_API_URL=https://<your_domain>
BACKEND_CORS_ORIGINS=http://<your_domain>:5173, https://<your_domain>:5173

Step 2: 🐳 Docker Setup

Install Docker on your EC2 instance.

Update the package list:

sudo apt-get update
Enter fullscreen mode Exit fullscreen mode

Install required packages:

sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
Enter fullscreen mode Exit fullscreen mode

Add Docker's official GPG key:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
Enter fullscreen mode Exit fullscreen mode

Add the Docker repository to APT resources:

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
Enter fullscreen mode Exit fullscreen mode

Update package list:

sudo apt-get update
Enter fullscreen mode Exit fullscreen mode

Install Docker:

sudo apt-get install docker-ce
Enter fullscreen mode Exit fullscreen mode

Verify Docker is properly installed and running:

sudo systemctl status docker
Enter fullscreen mode Exit fullscreen mode

Add user to Docker group:

sudo usermod -aG docker $USER
Enter fullscreen mode Exit fullscreen mode

Step 3: Docker Compose Setup

Install Docker Compose:

sudo curl -L "https://github.com/docker/compose/releases/download/$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep -oP '"tag_name": "\K(.*)(?=")')" /usr/local/bin/docker-compose
Enter fullscreen mode Exit fullscreen mode

Apply executable permission:

sudo chmod +x /usr/local/bin/docker-compose
Enter fullscreen mode Exit fullscreen mode

Verify Docker Compose is installed:

docker-compose --version
Enter fullscreen mode Exit fullscreen mode

Step 4: Dockerfile Configuration

Let’s create Dockerfiles for our frontend and backend applications.

Frontend Dockerfile

# Official Node.js runtime as a parent image
FROM node:20.15.0-alpine

# Set the working directory in the container
WORKDIR /app

# Copy the rest of the application code
COPY . /app
RUN npm install

# Make port 5173 available to the world outside this container
EXPOSE 5173

CMD ["npm", "run", "dev", "--", "--host"]
Enter fullscreen mode Exit fullscreen mode

Backend Dockerfile

# Official Python runtime as a parent image
FROM python:3.10

RUN set -xe

# Install Poetry
RUN curl -sSL https://install.python-poetry.org | python3 - --git https://github.com/python-poetry/poetry.git@master

ENV PATH="/root/.local/bin:$PATH"

# Confirm poetry version
RUN poetry --version

# Set up the working directory
WORKDIR /app

# Copy and install dependencies
COPY . /app

RUN poetry install

EXPOSE 8000

# Start the application
CMD ["bash", "-c", "poetry run bash ./prestart.sh && poetry run uvicorn app.main:app --reload --host 0.0.0.0"]
Enter fullscreen mode Exit fullscreen mode

Step 5: Docker Compose Configuration

Create a docker-compose.yml file to orchestrate our containers.

version: '3.8'

services:
  nginx-proxy:
    image: jc21/nginx-proxy-manager:latest
    restart: always
    ports:
      - "80:80"
      - "8090:81"
      - "443:443"
    environment:
      DB_SQLITE_FILE: "/data/database.sqlite"
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt

  postgres-db:
    image: postgres:13
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: app
      POSTGRES_PASSWORD: changethis123
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  backend-container:
    build: ./backend
    environment:
      DATABASE_URL: postgres://app:changethis123@postgres-db:5432/app
    depends_on:
      - postgres-db
    ports:
      - "8000:8000"

  frontend-container:
    build: ./frontend
    depends_on:
      - backend-container
    ports:
      - "5173:5173"

  adminer:
    image: adminer
    restart: always
    ports:
      - "8080:8080"
    environment:
      ADMINER_DEFAULT_SERVER: postgres-db

volumes:
  postgres_data:
    driver: local
Enter fullscreen mode Exit fullscreen mode

Step 6: Build and Run Containers

Run the following command to build and start your Docker containers:

docker-compose up -d
Enter fullscreen mode Exit fullscreen mode

Step 7: Configure Nginx Proxy Manager

Set up A records for your domain and sub-domains in Route53 on your AWS dashboard.

Access Nginx Proxy Manager via http://<your_domain:8090> and use the default credentials to log in.

Configure proxy hosts for your frontend and backend on the same proxy. Map your domain name to the respective container service names and ports.

Enable SSL certificates using Let's Encrypt and enforce SSL for secure connections.

Configure the frontend to route API requests to the backend on the same domain, click on 'Advanced' on the frontend proxy host and paste this configuration

location /api {
    proxy_pass http://backend:8000;
    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;
}

location /docs {
    proxy_pass http://backend:8000;
    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;
}

location /redoc {
    proxy_pass http://backend:8000;
    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;
}
Enter fullscreen mode Exit fullscreen mode

Set up a different proxy host for your adminer and Nginx Proxy Manager. Map your subdomain name to the service name of respective containers and ports.

πŸ§ͺ Testing Your Application

Congratulations! Your application is now deployed. You can access it via the following URLs:

Frontend: http://your_domain
Backend: http://your_domain/api
Backend Docs: http://<your_domain/docs
Backend Redoc: http://your_domain/redoc
Proxy Manager GUI: http://proxy.your_domain
Adminer: http://db.your_domain

And there you have it! You've successfully deployed a 3-tier application with Docker and Nginx Proxy Manager. This journey might seem impossible at first, but with each step, you're building a robust understanding of full-stack development and deployment. Keep experimenting, keep learning, and most importantly, have fun!

Feel free to reach out if you have any questions or need further assistance. Happy proxying!πŸ’»πŸŽ‰

#nginx #linux #docker #ubuntu #postgres

Top comments (0)