This is a robust, production-ready Notes application featuring a React frontend, Node.js Express API, PostgreSQL database and Redis caching.
I designed this project to showcase my understanding on advanced Docker orchestration and container optimization techniques.
- Frontend: React
- Backend: Node.js, Express.js
- Cache: Redis (Key-value store for note caching)
- Database: PostgreSQL (Relational storage)
- Reverse Proxy: Nginx (Serving the React build)
This project goes beyond basic Dockerfile creation, utilizing industry-standard patterns for security, speed and efficiency:
Both the Frontend and Backend utilize multi-stage builds. This allowed me to use large builder images containing build tools and then copy only the necessary artifacts into a slim production-grade Alpine image.
- Result: Significantly smaller image sizes and a reduced attack surface.
In the backend build, I ran npm prune --production before final packaging. This ensures that all devDependencies are excluded from the production image.
Rather than passing sensitive database passwords via insecure environment variables which can be leaked in logs or docker inspect, I used Docker Secrets.
- The password is read from a file on the host (db-password.txt) and mounted as a temporary file in memory at
/run/secrets/database_passwordinside the container.
- Internal Communication: The
Express APIcommunicates withRedisandPostgresusing their service names (redis, postgres_db) defined in thecompose.yaml. - Port Mapping: The frontend is served via
Nginxon port8080, while the API is gated behind port5000.
PostgreSQL data is mapped to a named volume all-notes-data. This ensures that all app notes persist even if the containers are stopped, removed or updated.
- Install
Docker Desktop. - Create a file named
db-password.txtin the project's root directory containing your desired Postgres DB password.
.
├── backend/ # Express API & Dockerfile (Multi-stage)
├── frontend/ # React App, Nginx config & Dockerfile (Multi-stage)
├── compose.yaml # Main Docker orchestration file
├── db-password.txt # Local secret for Postgres DB password (Git ignored)
└── volumes/ # Persistent DB storage (Managed by Docker)Run this command to build and start the entire app stack:
docker compose up -d --buildThe application will be live and available at:
- Frontend:
http://localhost:8080 - Backend:
http://localhost:5000/api/notes
To delete the running app containers only, run:
docker compose downTo tear down all the containers and delete the persistent volumes the app uses, run:
docker compose down --volumes