A production-ready, Dockerized three-tier e-commerce application for iPhones and Apple accessories.
GitHub: https://github.com/sufyanwithcode/shopx-ecommerce
Author: @sufyanwithcode
┌─────────────────────────────────────────────────────────────────┐
│ INTERNET (Users) │
└─────────────────────────┬───────────────────────────────────────┘
│ Port 80/443
┌─────────────────────────▼───────────────────────────────────────┐
│ TIER 1 — NGINX REVERSE PROXY │
│ • SSL Termination • Rate Limiting • Gzip • Load Balancing │
└──────────────┬──────────────────────────┬───────────────────────┘
│ /api/* │ /*
┌──────────────▼────────────┐ ┌─────────▼─────────────────────┐
│ TIER 2a — BACKEND API │ │ TIER 2b — REACT FRONTEND │
│ Node.js + Express │ │ React 18 + Redux Toolkit │
│ Port 5000 │ │ Served by Nginx on port 80 │
│ │ │ │
│ • JWT Auth │ │ • Shopping Cart (Redux) │
│ • Stripe Payments │ │ • Stripe Checkout │
│ • Cloudinary Uploads │ │ • Admin Dashboard │
│ • Email (Nodemailer) │ │ • Framer Motion Animations │
└──────────┬────────────────┘ └────────────────────────────────┘
│
┌──────────▼────────────────────────────────────┐
│ TIER 3 — DATA LAYER │
│ │
│ PostgreSQL 15 Redis 7 │
│ ───────────── ──────── │
│ • Users • Session Cache │
│ • Products • Rate Limiting │
│ • Orders • API Response Cache │
│ • Reviews • JWT Blocklist │
│ • Cart / Wishlist │
│ • Coupons │
└───────────────────────────────────────────────┘
| Layer | Technology | Purpose |
|---|---|---|
| Frontend | React 18, Redux Toolkit, Framer Motion | SPA with state management |
| Backend | Node.js 20, Express 4 | REST API |
| Database | PostgreSQL 15 | Persistent storage |
| Cache | Redis 7 | Sessions, API cache |
| Proxy | Nginx 1.25 | Reverse proxy, SSL |
| Payments | Stripe | Card payments |
| Images | Cloudinary | Product image CDN |
| Nodemailer + Gmail | Transactional email | |
| CI/CD | GitHub Actions | Automated pipeline |
| Containers | Docker + Docker Compose | Deployment |
| Registry | GitHub Container Registry | Docker image hosting |
shopx-ecommerce/
├── .github/
│ └── workflows/
│ └── ci-cd.yml # GitHub Actions CI/CD
├── backend/
│ ├── src/
│ │ ├── config/ # DB, Redis, Cloudinary
│ │ ├── controllers/ # Business logic
│ │ ├── middleware/ # Auth, Error, Upload, Validate
│ │ ├── models/ # (schema in config/database.js)
│ │ ├── routes/ # Express routers
│ │ ├── services/ # Email service
│ │ ├── utils/ # Logger, slugify
│ │ ├── app.js # Express app
│ │ └── server.js # Entry point
│ ├── Dockerfile
│ └── package.json
├── frontend/
│ ├── src/
│ │ ├── components/ # Reusable UI components
│ │ ├── pages/ # Route-level pages
│ │ ├── store/ # Redux slices
│ │ └── utils/ # API client
│ ├── Dockerfile
│ ├── Dockerfile.dev
│ └── package.json
├── nginx/
│ ├── nginx.conf # Main Nginx config
│ └── conf.d/
│ └── shopx.conf # Virtual host + SSL
├── database/
│ └── seeds/
│ └── seed.js # Sample products & admin
├── docker-compose.yml # Production compose
├── docker-compose.dev.yml # Dev overrides
├── .env.example # Environment template
└── README.md
Step 1.1 — Clone the repository
git clone https://github.com/sufyanwithcode/shopx-ecommerce.git
cd shopx-ecommerceStep 1.2 — Create your .env file
cp .env.example .envEdit .env with your values:
nano .envMinimum required for local dev:
POSTGRES_DB=shopx_db
POSTGRES_USER=shopx_user
POSTGRES_PASSWORD=dev_password_123
REDIS_PASSWORD=redis_dev_123
JWT_SECRET=dev_jwt_secret_at_least_32_chars_long_here
JWT_REFRESH_SECRET=dev_refresh_secret_at_least_32_chars_here
STRIPE_SECRET_KEY=sk_test_your_key_from_stripe_dashboard
REACT_APP_STRIPE_KEY=pk_test_your_key_from_stripe_dashboard
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
SMTP_USER=your@gmail.com
SMTP_PASS=your_gmail_app_password
FRONTEND_URL=http://localhost:3000
REACT_APP_API_URL=http://localhost:5000/apiStep 1.3 — Start with Docker (recommended)
# Start full dev stack (hot reload enabled)
docker compose -f docker-compose.yml -f docker-compose.dev.yml up --buildOr start services individually:
# Start only database services
docker compose up postgres redis -d
# Run backend locally
cd backend && npm install && npm run dev
# Run frontend locally (new terminal)
cd frontend && npm install && npm startStep 1.4 — Seed the database
# In another terminal (after containers are up)
docker compose exec backend node database/seeds/seed.js
# Or if running backend locally:
cd backend && node ../database/seeds/seed.jsStep 1.5 — Verify everything works
# API health check
curl http://localhost:5000/api/health
# Expected response:
# {"status":"ok","service":"ShopX API","version":"1.0.0",...}Now open:
- Frontend: http://localhost:3000
- API: http://localhost:5000/api
- Admin login: admin@shopx.com / Admin@ShopX2024!
Step 2.1 — Create the GitHub repository
# Create repo at: https://github.com/new
# Name: shopx-ecommerce
# Visibility: Private (recommended for production)Step 2.2 — Initialize git and push
cd shopx-ecommerce
git init
git add .
git commit -m "feat: initial ShopX e-commerce application"
git branch -M main
git remote add origin https://github.com/sufyanwithcode/shopx-ecommerce.git
git push -u origin mainStep 2.3 — Add GitHub Secrets
Go to: https://github.com/sufyanwithcode/shopx-ecommerce/settings/secrets/actions
Add these Repository Secrets:
| Secret Name | Value |
|---|---|
DEPLOY_HOST |
Your server IP (e.g. 45.33.32.156) |
DEPLOY_USER |
ubuntu or root |
DEPLOY_SSH_KEY |
Contents of your ~/.ssh/id_rsa private key |
DEPLOY_PORT |
22 (default SSH port) |
Add these Repository Variables (Settings → Variables → Actions):
| Variable | Value |
|---|---|
REACT_APP_API_URL |
https://yourdomain.com/api |
REACT_APP_STRIPE_KEY |
pk_live_your_stripe_public_key |
Step 3.1 — Provision a server
Recommended specs:
- OS: Ubuntu 22.04 LTS
- RAM: 4 GB minimum (8 GB recommended)
- CPU: 2 vCPUs
- Storage: 40 GB SSD
- Provider: DigitalOcean, AWS EC2, Linode, Vultr, Hetzner
Step 3.2 — Connect to your server
ssh ubuntu@YOUR_SERVER_IPStep 3.3 — Update system packages
sudo apt update && sudo apt upgrade -yStep 3.4 — Install Docker
# Install Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
newgrp docker
# Install Docker Compose plugin
sudo apt install docker-compose-plugin -y
# Verify
docker --version
docker compose versionStep 3.5 — Install Git
sudo apt install git -y
git --versionStep 3.6 — Generate SSH key for GitHub Actions deployment
# On your LOCAL machine (not the server):
ssh-keygen -t ed25519 -C "shopx-deploy" -f ~/.ssh/shopx_deploy
# Copy public key to server:
ssh-copy-id -i ~/.ssh/shopx_deploy.pub ubuntu@YOUR_SERVER_IP
# Add private key contents to GitHub Secret DEPLOY_SSH_KEY:
cat ~/.ssh/shopx_deployStep 3.7 — Set up the project directory on server
# SSH into server
ssh ubuntu@YOUR_SERVER_IP
# Create project directory
sudo mkdir -p /opt/shopx
sudo chown ubuntu:ubuntu /opt/shopx
cd /opt/shopx
# Clone repository
git clone https://github.com/sufyanwithcode/shopx-ecommerce.git .
# Create production .env
cp .env.example .env
nano .env # Fill in all production valuesStep 3.8 — Configure production .env on server
nano /opt/shopx/.envCritical production values:
# Generate strong secrets:
# openssl rand -hex 64
JWT_SECRET=<64-char-random-hex>
JWT_REFRESH_SECRET=<64-char-random-hex-different>
POSTGRES_PASSWORD=<strong-password-no-special-chars>
REDIS_PASSWORD=<strong-redis-password>
STRIPE_SECRET_KEY=sk_live_your_live_key
REACT_APP_STRIPE_KEY=pk_live_your_live_key
CLOUDINARY_CLOUD_NAME=your_cloud
CLOUDINARY_API_KEY=your_key
CLOUDINARY_API_SECRET=your_secret
FRONTEND_URL=https://yourdomain.com
REACT_APP_API_URL=https://yourdomain.com/api
SSL_DOMAIN=yourdomain.com
SSL_EMAIL=admin@yourdomain.comStep 3.9 — Configure domain DNS
In your domain registrar, add:
A @ YOUR_SERVER_IP TTL: 300
A www YOUR_SERVER_IP TTL: 300
Step 3.10 — Obtain SSL certificate (Let's Encrypt)
# Install Certbot
sudo apt install certbot -y
# Stop any service on port 80 first
# Get certificate (standalone mode)
sudo certbot certonly --standalone \
-d yourdomain.com \
-d www.yourdomain.com \
--email admin@yourdomain.com \
--agree-tos \
--non-interactive
# Certificates are at:
# /etc/letsencrypt/live/yourdomain.com/fullchain.pem
# /etc/letsencrypt/live/yourdomain.com/privkey.pem
# Copy certs for Docker
sudo cp /etc/letsencrypt/live/yourdomain.com/fullchain.pem /opt/shopx/nginx/ssl/
sudo cp /etc/letsencrypt/live/yourdomain.com/privkey.pem /opt/shopx/nginx/ssl/
sudo chown ubuntu:ubuntu /opt/shopx/nginx/ssl/*
# Set up auto-renewal
echo "0 3 * * * certbot renew --quiet" | sudo crontab -Step 3.11 — Update Nginx config with your domain
# On server
sed -i 's/yourdomain.com/YOUR_ACTUAL_DOMAIN.com/g' /opt/shopx/nginx/conf.d/shopx.confStep 3.12 — First manual deploy
cd /opt/shopx
# Login to GitHub Container Registry
echo $GITHUB_TOKEN | docker login ghcr.io -u sufyanwithcode --password-stdin
# Build and start all services
docker compose up --build -d
# View logs
docker compose logs -f
# Check all containers are running
docker compose psStep 3.13 — Seed the production database
# Run seed inside backend container
docker compose exec backend node database/seeds/seed.jsStep 3.14 — Verify production deployment
# API health check
curl https://yourdomain.com/api/health
# Check all containers
docker compose ps
# View backend logs
docker compose logs backend --tail=50
# View nginx logs
docker compose logs nginx --tail=50Every push to main branch now automatically:
- Runs backend tests (Jest + PostgreSQL + Redis services)
- Runs frontend tests (React Testing Library)
- Builds Docker images and pushes to
ghcr.io/sufyanwithcode/shopx-* - SSH deploys to your server — pulls new images, restarts containers with zero downtime
- Health check — verifies
/api/healthafter deploy
Trigger a deployment:
git add .
git commit -m "feat: your feature description"
git push origin main
# Watch it deploy at: github.com/sufyanwithcode/shopx-ecommerce/actionsView real-time logs:
docker compose logs -f backend
docker compose logs -f nginx
docker compose logs -f postgresDatabase backup:
# Manual backup
docker compose exec postgres pg_dump -U shopx_user shopx_db > backup_$(date +%Y%m%d).sql
# Automated daily backup (add to crontab)
0 2 * * * docker compose -f /opt/shopx/docker-compose.yml exec -T postgres \
pg_dump -U shopx_user shopx_db > /opt/backups/shopx_$(date +\%Y\%m\%d).sqlRestore from backup:
docker compose exec -T postgres psql -U shopx_user shopx_db < backup_20240101.sqlScale backend (multiple instances):
docker compose up --scale backend=3 -dUpdate a single service:
docker compose pull backend
docker compose up -d --no-deps --force-recreate backendAccess database shell:
docker compose exec postgres psql -U shopx_user -d shopx_dbAccess Redis CLI:
docker compose exec redis redis-cli -a $REDIS_PASSWORDMonitor resource usage:
docker statsPOST /api/auth/register Create account
POST /api/auth/login Sign in
POST /api/auth/refresh-token Refresh JWT
POST /api/auth/logout Sign out
POST /api/auth/forgot-password Request reset link
POST /api/auth/reset-password/:token Reset password
GET /api/auth/verify-email/:token Verify email
GET /api/auth/me Get current user
GET /api/products List products (filters, pagination)
GET /api/products/featured Featured products
GET /api/products/search?q= Search products
GET /api/products/:idOrSlug Get product detail
GET /api/products/:id/variants Get variants
GET /api/products/:id/related Related products
POST /api/products Create product [admin/seller]
PUT /api/products/:id Update product [admin/seller]
DELETE /api/products/:id Delete product [admin]
GET /api/cart Get cart
POST /api/cart Add to cart
PUT /api/cart/:itemId Update quantity
DELETE /api/cart/:itemId Remove item
DELETE /api/cart Clear cart
POST /api/cart/apply-coupon Apply coupon code
POST /api/orders Create order
GET /api/orders My orders
GET /api/orders/:id Order detail
POST /api/orders/:id/cancel Cancel order
PUT /api/orders/:id/status Update status [admin]
PUT /api/orders/:id/tracking Add tracking [admin]
POST /api/payments/create-intent Create Stripe intent
POST /api/payments/confirm Confirm payment
POST /api/payments/webhook Stripe webhook
GET /api/users/profile Get profile
PUT /api/users/profile Update profile
PUT /api/users/change-password Change password
POST /api/users/avatar Upload avatar
GET /api/users/addresses Get addresses
POST /api/users/addresses Add address
GET /api/users/wishlist Get wishlist
POST /api/users/wishlist/:id Add to wishlist
DELETE /api/users/wishlist/:id Remove from wishlist
GET /api/admin/dashboard Dashboard stats
GET /api/admin/stats Revenue + top products
GET /api/admin/users All users
PUT /api/admin/users/:id/role Change user role
PUT /api/admin/users/:id/status Toggle active/suspended
GET /api/admin/orders All orders
GET /api/admin/products/low-stock Low stock alert
After seeding:
| Role | Password | |
|---|---|---|
| Admin | admin@shopx.com | Admin@ShopX2024! |
Test Stripe card: 4242 4242 4242 4242, any future date, any CVC
Test coupon code: WELCOME10 (10% off, min order $50)
Containers not starting:
docker compose logs
docker compose down && docker compose up --buildDatabase connection refused:
# Check postgres is healthy
docker compose ps
# Wait for health check to pass
docker compose logs postgresPort already in use:
sudo lsof -i :80
sudo kill -9 PIDSSL cert issues:
sudo certbot renew --force-renewal
sudo cp /etc/letsencrypt/live/yourdomain.com/*.pem /opt/shopx/nginx/ssl/
docker compose restart nginxOut of disk space:
docker system prune -af
docker volume prune- GitHub Issues: https://github.com/sufyanwithcode/shopx-ecommerce/issues
- GitHub Profile: https://github.com/sufyanwithcode
Built with ❤️ by @sufyanwithcode