Introduction
This post will walk you through deploying a web application with NGINX on both local and production environments using a single docker-compose
command.
Main Takeaways
- Deploy a web application using NGINX in both development and production environments.
- Simplify deployment by automating configurations with Docker Compose.
The Norm Way: Deploying on an EC2 Server
If you want to deploy a web application on an EC2 server, hereβs a step-by-step example. Below is the docker-compose
configuration I used:
Docker Compose File
version: '3.8'
services:
mongodb:
image: mongo:latest
container_name: mongodb
volumes:
- /data/test-change-streams:/data/db
ports:
- "27017:27017"
networks:
- app-network
command: mongod --replSet test-change-streams --logpath /data/db/mongodb.log --dbpath /data/db --port 27017
mongodb-setup:
image: mongo:latest
depends_on:
- mongodb
networks:
- app-network
command: >
bash -c "
sleep 10 &&
mongosh --host mongodb:27017 --eval \"
rs.initiate({
_id: 'test-change-streams',
members: [
{_id: 0, host: 'mongodb:27017'}
]
})
\"
"
fastapi-app:
image: multilanguage_invoice_ocr-fastapi-app
build:
context: .
dockerfile: Dockerfile
container_name: fastapi-app
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
- EMAIL_USER=${EMAIL_USER}
- EMAIL_PASSWORD=${EMAIL_PASSWORD}
- SECRET_KEY=${SECRET_KEY}
- ALGORITHM=${ALGORITHM}
- ACCESS_TOKEN_EXPIRE_MINUTES=${ACCESS_TOKEN_EXPIRE_MINUTES}
volumes:
- ./config:/app/config
- ./src:/app/src
ports:
- "8149:8149"
networks:
- app-network
depends_on:
- mongodb
- mongodb-setup
jwt-frontend:
image: multilanguage_invoice_ocr-jwt-frontend
build:
context: ./jwt-auth-frontend
dockerfile: Dockerfile
container_name: jwt-frontend
volumes:
- ./jwt-auth-frontend/src:/app/src
ports:
- "3000:3000"
networks:
- app-network
depends_on:
- fastapi-app
nginx:
build:
context: ./nginx
container_name: nginx
volumes:
- ./nginx/nginx.conf.template:/etc/nginx/nginx.conf.template:ro
ports:
- "80:80"
networks:
- app-network
depends_on:
- fastapi-app
- jwt-frontend
- mongodb
environment:
- CLIENT_MAX_BODY_SIZE=${CLIENT_MAX_BODY_SIZE}
- SERVER_IP=${SERVER_IP}
networks:
app-network:
driver: bridge
Explanation
The nginx
service in the above configuration acts as a reverse proxy connecting to:
- Frontend (
jwt-frontend
) - Backend (
fastapi-app
) - Database (
mongodb
)
Letβs focus on the NGINX service:
Key Features of NGINX in Docker Compose:
-
Service Name:
nginx
-
Build Context: Builds the Docker image from
./nginx
. -
Container Name:
nginx
-
Volumes: Mounts a read-only
nginx.conf.template
for configuration. - Ports: Exposes port 80.
-
Networks: Connects to a custom
app-network
. -
Environment Variables: Passes variables such as
CLIENT_MAX_BODY_SIZE
andSERVER_IP
.
Folder Structure for NGINX Configuration
Create a folder named nginx
for all related configurations:
- Dockerfile:
FROM nginx:latest
COPY start-nginx.sh /start-nginx.sh
RUN chmod +x /start-nginx.sh
ENTRYPOINT ["/start-Nginx.sh"]
-
Startup Script (
start-nginx.sh
):
#!/bin/bash
envsubst '${CLIENT_MAX_BODY_SIZE} ${SERVER_IP}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf
nginx -g 'daemon off;'
-
Nginx Config Template (
nginx.conf.template
):
events {
worker_connections 1024;
}
http {
client_max_body_size ${CLIENT_MAX_BODY_SIZE};
server {
listen 80;
server_name localhost ${SERVER_IP};
location / {
proxy_pass http://jwt-frontend:3000/;
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 /api/ {
proxy_pass http://fastapi-app:8149/;
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
}
location /mongo/ {
proxy_pass http://mongodb:27017/;
}
}
}
The Advanced Way: Handling Multiple Environments
When deploying in production, you might need different configurations compared to local development. For example:
- Production: Requires HTTPS on port 443.
- Development: Simpler HTTP configuration on port 80.
Environment Differences
Feature | Production | Development |
---|---|---|
Port | 443 (HTTPS), 80 (HTTP fallback) | Only 80 (HTTP) |
Protocol | HTTPS (secure) | HTTP (non-secure) |
Server IP | Domain name (e.g., xyz.com ) |
Local or private IP (e.g., xx.xx.xx.xx ) |
SSL/TLS | Enabled, with valid certificates | Typically disabled |
Environment Variables | Loaded with production settings | Uses development-specific configurations |
New Dockerfile
FROM nginx:latest
RUN mkdir -p /etc/nginx/dev /etc/nginx/prod
COPY dev/nginx.conf.template /etc/nginx/dev/
COPY prod/nginx.conf.template /etc/nginx/prod/
COPY start-nginx.sh /start-nginx.sh
RUN chmod +x /start-nginx.sh
ENTRYPOINT ["/start-nginx.sh"]
Updated start-nginx.sh
#!/bin/bash
if [ "$DEBUG" = "True" ]; then
CONFIG_PATH="/etc/nginx/dev/nginx.conf.template"
else
CONFIG_PATH="/etc/nginx/prod/nginx.conf.template"
fi
envsubst '${CLIENT_MAX_BODY_SIZE} ${SERVER_IP}' < $CONFIG_PATH > /etc/nginx/nginx.conf
exec nginx -g 'daemon off;'
.env
Example
DEBUG=True
CLIENT_MAX_BODY_SIZE=5
SERVER_IP=12.13.13.14
Conclusion
With this setup:
- You can deploy NGINX with just one command:
docker compose up -d
- Your application will work seamlessly in both development and production environments.
Reference
Multilanguage Invoice OCR - Mrzaizai2k
More
If youβd like to learn more, be sure to check out my other posts and give me a like! It would mean a lot to me. Thank you.
Top comments (3)
Absolutely incredible! π».
Thanks alot, btw what do u want me to write more Anirudda?
π‘ There are significant differences between development and production environments. Striving to make them as similar as possible ensures faster deployments with fewer errors. π
Some comments may only be visible to logged-in visitors. Sign in to view all comments.