A production-ready, multi-service web application demonstrating containerization, service isolation, internal networking, and persistent storage using Docker.
📌 Executive Summary
The Parent Registration Portal is a containerized full-stack web application that enables parents to register themselves and their children via a web interface.
The application demonstrates:
Multi-container architecture
Service isolation
Docker networking
Persistent database storage
Environment-based configuration
Secure service communication
The entire system is orchestrated using Docker Compose, making deployment reproducible and environment-agnostic.
🏗️ Architecture Overview
The application follows a three-tier architecture model:
Presentation Layer – Nginx (Frontend)
Application Layer – Node.js/Express (Backend API)
Data Layer – PostgreSQL (Database)
Each component runs in an isolated container and communicates via a custom Docker bridge network.
🖥️ Architecture Diagram
┌──────────────────────┐
│ User │
│ Browser Client │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ Frontend │
│ Nginx Container │
│ Port: 3103 → 80 │
└──────────┬───────────┘
│ HTTP API Calls
▼
┌──────────────────────┐
│ Backend │
│ Node.js + Express │
│ Port: 3100 │
└──────────┬───────────┘
│ Internal Docker Network
▼
┌──────────────────────┐
│ Database │
│ PostgreSQL 13 │
│ Port: 5432 (internal)
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ Docker Volume │
│ postgres_data │
│ Persistent Storage │
└──────────────────────┘
🔄 Request Lifecycle Flow
User submits registration form.
Frontend sends POST request to backend API.
Backend validates request and connects to PostgreSQL.
Data is inserted into database.
Backend returns success response.
Frontend updates UI accordingly.
🐳 Containerization Strategy
Backend Dockerfile (Node.js Service)
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3100
CMD ["node", "server.js"]
Design Considerations
Uses lightweight Alpine image for smaller footprint.
Dependency caching optimization via layered build.
Exposes only required port.
No hardcoded credentials.
Runtime configuration via environment variables.
Frontend Dockerfile (Nginx Service)
FROM nginx:alpine
COPY . /usr/share/nginx/html
Design Considerations
Static file serving via Nginx.
Minimal attack surface.
No application runtime dependencies.
🧩 Docker Compose Orchestration
services:
db:
image: postgres:13-alpine
restart: always
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_NAME}
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- app-network
backend:
build: ./backend
restart: always
ports:
- "3100:3100"
environment:
DB_HOST: db
DB_USER: ${DB_USER}
DB_PASSWORD: ${DB_PASSWORD}
DB_NAME: ${DB_NAME}
depends_on:
- db
networks:
- app-network
frontend:
build: ./frontend
restart: always
ports:
- "3103:80"
depends_on:
- backend
networks:
- app-network
volumes:
postgres_data:
networks:
app-network:
driver: bridge
🔐 Networking Design
Custom Docker bridge network (app-network)
Internal DNS resolution via service names (db, backend)
Database not exposed to public network
Only required services expose host ports
Reduced attack surface
💾 Persistent Storage Strategy
The PostgreSQL container uses a named Docker volume:
postgres_data:/var/lib/postgresql/data
Benefits:
Data persistence across container restarts
Separation of state from compute
Safe container rebuilds without data loss
⚙️ Configuration Management
Database credentials injected via .env
No hardcoded secrets
Environment-based configuration pattern
Improved portability across environments
🚀 Deployment Process
Prerequisites
Docker
Docker Compose
Setup
git clone https://github.com/passolateam/eden_reg_portal.git
cd eden_reg_portal
docker compose up --build
Access application:
⚠️ Challenges & Engineering Lessons
1️⃣ CORS & Cross-Origin Security
Problem:
Frontend could not communicate with backend due to browser security restrictions.
Resolution:
Implemented proper CORS middleware.
Understood difference between host, container, and browser network contexts.
2️⃣ Localhost Misconfiguration
Problem:
Using localhost inside containerized environments caused communication failures.
Lesson:
localhost refers to the container itself.
Service names must be used within Docker networks.
Public IP required when accessed externally.
3️⃣ Internal vs External Networking
Learned to distinguish between:
Internal container ports
Host-exposed ports
Docker bridge networking
This significantly improved understanding of microservice communication patterns.
4️⃣ Environment Variable Scope
Attempted to use process.env in static frontend JavaScript.
Lesson:
Environment variables are injected at build/runtime.
Static frontend must use proper configuration strategy.
📈 DevOps Principles Demonstrated
Infrastructure as Code (Docker Compose)
Immutable Infrastructure
Service Isolation
Persistent Data Management
Secure Configuration
Network Segmentation
Reproducible Deployments
Log-based Debugging
Container Lifecycle Management
🔮 Future Improvements
Reverse proxy (Nginx API gateway pattern)
HTTPS via Let's Encrypt
Multi-stage Docker builds
Health checks
CI/CD integration
Container registry deployment
Kubernetes migration readiness
🎯 Conclusion
The Parent Registration Portal is more than a simple web form application — it is a demonstration of practical DevOps engineering principles applied to a real-world containerized architecture.
This project strengthened expertise in:
Containerization strategy
Network debugging
Cross-service communication
Secure configuration
Deployment reproducibility
It reflects readiness to design, containerize, and deploy production-grade applications using Docker-based workflows.
Top comments (0)