Full-Stack Deployment on VM Using Docker

Jan 20, 2025

Full-Stack Deployment on VM Using Docker

Full-Stack Deployment on a VM with Docker

A concise guide to deploying a production-ready React + Node.js application using Docker, NGINX reverse proxy, and SSL.


Tech Stack

  • React (Vite) frontend
  • Node.js / Express backend
  • External database (MongoDB Atlas / RDS)
  • Ubuntu VM (AWS / DigitalOcean)
  • Docker + Docker Compose
  • Host NGINX + Certbot (HTTPS)

Project Structure

project-root/
├── frontend/ (Dockerfile, nginx.conf, .env)
├── backend/  (Dockerfile, .env, index.js)
└── docker-compose.yml

Docker Setup

Frontend Dockerfile

FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Backend Dockerfile

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
CMD ["node", "index.js"]

Docker Compose

services:
  frontend:
    build: ./frontend
    ports:
      - "127.0.0.1:3000:80"
    depends_on: [backend]
    restart: always

  backend:
    build: ./backend
    ports:
      - "127.0.0.1:8080:8080"
    env_file: ./backend/.env
    restart: always

Containers bind to 127.0.0.1 so only NGINX can access them.


VM Setup

apt update && apt upgrade -y
apt install docker.io nginx certbot python3-certbot-nginx -y
systemctl enable docker nginx

Clone and run:

git clone <repo>
cd project-root
docker compose up --build -d

NGINX Reverse Proxy

server {
  server_name yourdomain.com;

  location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  location /api/ {
    proxy_pass http://127.0.0.1:8080;
  }
}

Enable and reload:

ln -s /etc/nginx/sites-available/app /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx

HTTPS (SSL)

certbot --nginx -d yourdomain.com

Certbot auto-renews certificates via system timer.


Auth & Cookies

Backend:

app.set("trust proxy", 1);
res.cookie("token", token, {
  httpOnly: true,
  secure: true,
  sameSite: "none",
});

Frontend Axios:

const api = axios.create({
  baseURL: "/api",
  withCredentials: true,
});

Deploy Updates

git pull
docker compose down
docker compose up --build -d

Production Checklist

  • Backend not publicly exposed
  • HTTPS enabled
  • Secure cookies (httpOnly + secure)
  • Secrets excluded from Git
  • Firewall allows only 22 / 80 / 443

Architecture Overview

Browser → HTTPS → Host NGINX
         → Frontend Container (3000)
         → Backend Container (8080)

This setup provides a secure, scalable deployment pipeline using containers and reverse proxy routing.

@ 2026 Shailesh