From 87bc8e4c1732b311665c29abc1e0d4d899386064 Mon Sep 17 00:00:00 2001 From: Rishabh Mishra Date: Tue, 10 Feb 2026 20:49:59 +0530 Subject: [PATCH] Add Docker setup for frontend, backend & MongoDB Introduce containerization: add .dockerignore, client and server Dockerfiles, and an Nginx config for the frontend. Replace the previous single-service compose with a docker-compose defining frontend (Nginx), backend (Node.js) and mongo services, add a mongo data volume, environment variables and env_file for the backend, and set restart policies. Port mappings: frontend 3000:80, backend 3001:3000. Nginx proxies /api and /socket.io to the backend and applies basic security headers/CSP. Also adjust compose version to 3.8 to support the layout. --- .dockerignore | 10 ++++++++++ client/Dockerfile | 18 ++++++++++++++++++ client/nginx.conf | 40 ++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 46 ++++++++++++++++++++++++++++++++++++++++------ server/Dockerfile | 20 ++++++++++++++++++++ 5 files changed, 128 insertions(+), 6 deletions(-) create mode 100644 .dockerignore create mode 100644 client/Dockerfile create mode 100644 client/nginx.conf create mode 100644 server/Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..90952f82 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +node_modules +npm-debug.log +Dockerfile +.dockerignore +.git +.gitignore +README.md +client +server +docker-compose.yml diff --git a/client/Dockerfile b/client/Dockerfile new file mode 100644 index 00000000..616363f8 --- /dev/null +++ b/client/Dockerfile @@ -0,0 +1,18 @@ +# Use official Nginx image +FROM nginx:alpine + +# Remove default Nginx website +RUN rm -rf /usr/share/nginx/html/* + +# Copy static files from public directory to Nginx html root +# Note: This copies the contents of 'public' directly to '/usr/share/nginx/html' +COPY public/ /usr/share/nginx/html/ + +# Copy custom Nginx configuration +COPY client/nginx.conf /etc/nginx/conf.d/default.conf + +# Expose port 80 +EXPOSE 80 + +# Start Nginx +CMD ["nginx", "-g", "daemon off;"] diff --git a/client/nginx.conf b/client/nginx.conf new file mode 100644 index 00000000..98d1be95 --- /dev/null +++ b/client/nginx.conf @@ -0,0 +1,40 @@ +server { + listen 80; + server_name localhost; + + root /usr/share/nginx/html; + index index.html; + + # Serve static files from root + # Serve static files from root + location / { + try_files $uri $uri/ $uri.html /index.html; + + # Security Headers (Matching Helmet config from server.js) + add_header X-Frame-Options "SAMEORIGIN"; + add_header X-Content-Type-Options "nosniff"; + add_header Referrer-Policy "strict-origin-when-cross-origin"; + # CSP is complex to replicate exactly in Nginx without dynamic values, + # but we add a baseline here. The backend API responses will still carry their own CSP. + add_header Content-Security-Policy "default-src 'self' https: data: blob: 'unsafe-inline' 'unsafe-eval'; img-src 'self' data: https:; font-src 'self' https: data:;"; + } + + # Proxy API requests to the backend service + location /api/ { + proxy_pass http://backend:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + } + + # Proxy Socket.IO requests + location /socket.io/ { + proxy_pass http://backend:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + } +} diff --git a/docker-compose.yml b/docker-compose.yml index 7ea6444e..1a0e5a8e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,43 @@ -version: "3.9" +version: '3.8' services: - expenseflow: - build: . - image: expenseflow:latest + # Frontend Application (Nginx) + frontend: + build: + context: . + dockerfile: client/Dockerfile ports: - - "8080:80" - restart: unless-stopped + - "3000:80" + depends_on: + - backend + restart: always + + # Backend Application (Node.js/Express) + backend: + build: + context: . + dockerfile: server/Dockerfile + ports: + - "3001:3000" # Expose on 3001 to avoid conflict with frontend on host + environment: + - PORT=3000 + - MONGODB_URI=mongodb://mongo:27017/expenseflow + - NODE_ENV=development + - FRONTEND_URL=http://localhost:3000 + env_file: + - .env + depends_on: + - mongo + restart: always + + # Database (MongoDB) + mongo: + image: mongo:latest + ports: + - "27017:27017" + volumes: + - mongo-data:/data/db + restart: always + +volumes: + mongo-data: diff --git a/server/Dockerfile b/server/Dockerfile new file mode 100644 index 00000000..92968c7f --- /dev/null +++ b/server/Dockerfile @@ -0,0 +1,20 @@ +# Use official Node.js image +FROM node:18-alpine + +# Set working directory +WORKDIR /app + +# Copy package files first for better caching +COPY package*.json ./ + +# Install dependencies +RUN npm install + +# Copy the rest of the application code +COPY . . + +# Expose the port the app runs on +EXPOSE 3000 + +# Start the application +CMD ["npm", "run", "dev"]