A minimal, two-tier web application stack orchestrated using Docker Compose. This project serves as a clear demonstration of managing a decoupled React Frontend (Nginx) and a Flask API Backend within a unified container environment.
This setup is highly portable and resource-efficient, making it ideal for deployment on constrained environments like the AWS EC2 Free Tier.
| Service | Technology | Role |
|---|---|---|
| Frontend | React (Vite Build) | User Interface, bundled into static files. |
| Server | Nginx:Alpine | Extremely lightweight web server to serve the React static build. |
| Backend | Python Flask | Minimal REST API, serving data on port 5000. |
| Orchestration | Docker Compose | Defines, builds, and networks both containers with a single command. |
The project uses a standard multi-service structure, where each application layer lives in its own folder with its own Dockerfile.
DOCKERCOMPOSEPROJECT/
├── backend/ # Python Flask API files
│ ├── Dockerfile
│ ├── app.py
│ └── requirements.txt
├── frontend/ # React UI source code and build files
│ ├── Dockerfile # Multi-stage build for React -> Nginx
│ ├── package.json
├── tanstack-query-weather-app
│ └── src/ # (and other React source folders)
├── .dockerignore # Excludes large or sensitive files from the build context
└── docker-compose.yml # The core orchestration file
You must have Docker and Docker Compose installed on your system or EC2 instance.
Execute this command from the root directory of the project (full-stack-app/).
The --build flag forces Docker Compose to build the images based on the local Dockerfiles. The -d flag runs the containers in detached mode (in the background).
docker-compose up --build -dOnce both containers are running, the application is accessible via the ports defined in docker-compose.yml:
| Service | Host URL (for your browser) | Access Route (Internal) |
|---|---|---|
| Frontend (React) | http://<EC2-Public-IP>:80 |
Serves the web interface |
| Backend (Flask API) | http://<EC2-Public-IP>:5000/ |
Serves a simple "Hello from Flask!" message |
| Internal API | N/A | Frontend uses http://backend:5000/ to talk to Flask |
Use these commands to check, stop, and clean up your container environment:
| Command | Action |
|---|---|
docker ps |
View the running backend and frontend containers. |
docker-compose logs |
View the combined logs for both services in real-time. |
docker-compose down |
Stops and removes all containers and the network created by this stack. |
docker-compose down --rmi all |
Stops containers and removes all images created by this project. |
This file uses a multi-stage build for optimal size:
- Builder Stage: Uses
node:18-alpineto install dependencies and runnpm run build(Vite outputs to thedistdirectory). - Final Stage: Uses the tiny
nginx:alpineimage and copies only the static files from thedistfolder, resulting in a production image under 70MB.
This file creates a lightweight Python environment:
- Uses
python:3.11-alpineas a minimal base image. - Installs only the
Flaskdependency fromrequirements.txt. - Runs the application using
python app.pyon internal port 5000.
Feel free to fork this repository, extend the API, or integrate a database service (like PostgreSQL or Redis) into the docker-compose.yml file.