A full-stack task logging application built with modern DevOps practices, featuring a containerized React frontend, Node.js/Express backend, PostgreSQL database, and automated CI/CD to an AWS VPS.
Live app: https://tasklogging.codes
API : https://tasklogging.codes/api
This project implements a simple task logging system where users can:
- Create tasks with a message and timestamp
- View a list of existing tasks
The focus is on production ready architecture and DevOps:
- Containerized services (frontend, backend, database, nginx)
- Nginx reverse proxy and load balancing
- GitHub Actions CI/CD pipeline
- Deployment to Linux VPS with a custom domain and SSL
- React + TypeScript
- Axios / fetch for API calls
- Node.js, Express, TypeScript
- PostgreSQL client (
pg)
- PostgreSQL (Dockerized)
- Initialized on startup, persistent via Docker volume
- Docker, Docker Compose
- Nginx reverse proxy
- AWS EC2 (Ubuntu)
- GitHub Actions
- Docker Hub for container registry
The system consists of four main Docker services:
- React SPA served as static files behind Nginx
- Uses a dynamic API base URL:
- Development:
REACT_APP_API_BASE_URL - Production: relative
/api
- Development:
- Express REST API
- Endpoints:
POST /api/task– Create a taskGET /api/task– List tasksGET /health– Simple health check for tests
- Uses environment variables for DB configuration:
DB_HOST,DB_PORT,DB_USER,DB_PASSWORD,DB_NAME
- PostgreSQL running in an internal Docker network
- Not exposed to the public internet
- Data persisted via Docker volume
- Entry point for all HTTP/HTTPS traffic
- Routing:
/→ frontend/api→ backend
- Load balances across multiple backend instances when scaled
- Handles SSL termination (Let’s Encrypt certificates)
- Forces HTTP → HTTPS redirection
- Node.js 18+ (for local dev)
- Docker & Docker Compose
- Git
From the project root: docker compose up -d
This will start:
frontendon port80(via nginx)backendon internal Docker networkpostgreson internal Docker networknginxonlocalhost:80
Access the app:
- App:
http://localhost:8080 - API (proxied):
http://localhost:8080/api/task
cd apps/backend npm install npm run dev
Environment variables can be configured via .env in apps/backend.
cd apps/frontend npm install npm start
Configure API base URL via: REACT_APP_API_BASE_URL=https://tasklogging.codes/api
GitHub Actions is used for both Continuous Integration and Continuous Deployment.
For each push to main:
Backend
npm installnpm run lintnpm test
Frontend
npm installnpm run lintnpm test
Docker build
- Build production images for frontend and backend
On successful CI:
- Build and push images to Docker Hub:
mindiya/task-frontendmindiya/task-backend
- SSH into the AWS VPS using GitHub Secrets:
SSH_HOST,SSH_USER,SSH_PRIVATE_KEY
- On VPS:
docker compose pulldocker compose up -d
All sensitive values (Docker Hub credentials, SSH key, DB credentials) are stored in GitHub Secrets.
Platform: AWS EC2 (Ubuntu)
On the VPS:
-
Install dependencies:
- Docker
- Docker Compose
- Git
- Certbot
-
Clone the repository: git clone https://github.com/mindiya12/task-logging-app.git cd task-logging-app
-
Run the stack: docker compose up -d
-
Scale backend horizontally:
docker compose up -d --scale backend=2
Nginx’s upstream configuration automatically load-balances between backend instances.
Domain: taskLogging.codes
- A record
@→ EC2 public IP - A record
www→ EC2 public IP
- Certbot (
certbot certonly --standalone) used to obtain certificates for:taskLogging.codeswww.taskLogging.codes
- Certificates stored under:
/etc/letsencrypt/live/tasklogging.codes/
- Mounted into nginx container and referenced in
nginx.conf
listen 443 ssl;with cert/key paths- HTTP server on port 80 returns:
return 301 https://$host$request_uri;
for forced HTTPS redirection.
- App:
https://tasklogging.codes - API:
https://tasklogging.codes/api
Frontend image:
mindiya/task-frontend:latest
Backend image:
mindiya/task-backend:latest
docker compose up -d --scale backend=2
docker ps