🚀 Deploying a 3-tier Application with Docker and Nginx Proxy Manager 🌐
akintola abdulazeez oladele
Posted on July 22, 2024
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
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
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
Now let's install Git, PostgreSQL, Node.js, and npm:
sudo apt install git postgresql nodejs npm
Step 2: Setting Up Poetry
We’ll use Poetry for managing our Python dependencies:
curl -sSL https://install.python-poetry.org | python3 -
Add Poetry to your system's PATH:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
Step 3: Configuring PostgreSQL
Set up PostgreSQL to match the configuration in the .env file located in the backend directory:
sudo -u postgres psql
Then,
CREATE DATABASE app;
CREATE USER app WITH ENCRYPTED PASSWORD 'changethis123';
GRANT ALL PRIVILEGES ON DATABASE app TO app;
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
Set up the database:
poetry run bash ./prestart.sh
Run the FastAPI server:
poetry run uvicorn app.main:app --reload
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
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
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
Install required packages:
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
Add Docker's official GPG key:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
Add the Docker repository to APT resources:
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
Update package list:
sudo apt-get update
Install Docker:
sudo apt-get install docker-ce
Verify Docker is properly installed and running:
sudo systemctl status docker
Add user to Docker group:
sudo usermod -aG docker $USER
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
Apply executable permission:
sudo chmod +x /usr/local/bin/docker-compose
Verify Docker Compose is installed:
docker-compose --version
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"]
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"]
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
Step 6: Build and Run Containers
Run the following command to build and start your Docker containers:
docker-compose up -d
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;
}
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!💻🎉
Posted on July 22, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.