Skip to content

Latest commit

ย 

History

19 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿš€ Dockerised MERN Stack Application

A complete MERN stack application containerised using Docker and Docker Compose.

This project demonstrates how to run a modern full-stack JavaScript application with:

  • โš›๏ธ React + Vite
  • ๐ŸŸข Node.js
  • ๐Ÿš‚ Express.js
  • ๐Ÿƒ MongoDB
  • ๐Ÿณ Docker
  • ๐Ÿ™ Docker Compose
  • ๐Ÿ”„ Nodemon for backend development
  • ๐Ÿ’พ Persistent MongoDB storage

The entire application can be started with a single Docker Compose command.


๐Ÿ“Œ Table of Contents


๐Ÿ—๏ธ Architecture

The application consists of three main services:

                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚       Browser        โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                               โ”‚
                               โ”‚ :3000
                               โ–ผ
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚   React + Vite       โ”‚
                    โ”‚     Frontend         โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                               โ”‚
                               โ”‚ API Requests
                               โ–ผ
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚   Node.js + Express  โ”‚
                    โ”‚      Backend         โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                               โ”‚
                               โ”‚ MongoDB
                               โ–ผ
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚       MongoDB        โ”‚
                    โ”‚      Database        โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Docker Compose creates an internal network where services can communicate using their service names.

For example, the backend connects to MongoDB using:

mongodb://mongo:27017/mern_db

The hostname mongo refers to the MongoDB service defined in docker-compose.yml.


๐Ÿงฐ Technology Stack

Technology Purpose
React Frontend UI
Vite Frontend build tool and development server
Node.js JavaScript runtime
Express.js Backend API framework
MongoDB NoSQL database
Mongoose MongoDB ODM
Nodemon Backend development auto-reload
Docker Application containerization
Docker Compose Multi-container orchestration

๐Ÿ“ Project Structure

mern-app/
โ”‚
โ”œโ”€โ”€ backend/
โ”‚   โ”œโ”€โ”€ Dockerfile
โ”‚   โ”œโ”€โ”€ .dockerignore
โ”‚   โ”œโ”€โ”€ package.json
โ”‚   โ”œโ”€โ”€ package-lock.json
โ”‚   โ””โ”€โ”€ server.js
โ”‚
โ”œโ”€โ”€ frontend/
โ”‚   โ”œโ”€โ”€ Dockerfile
โ”‚   โ”œโ”€โ”€ .dockerignore
โ”‚   โ”œโ”€โ”€ package.json
โ”‚   โ”œโ”€โ”€ package-lock.json
โ”‚   โ”œโ”€โ”€ vite.config.js
โ”‚   โ”œโ”€โ”€ index.html
โ”‚   โ”‚
โ”‚   โ”œโ”€โ”€ public/
โ”‚   โ”‚
โ”‚   โ””โ”€โ”€ src/
โ”‚       โ”œโ”€โ”€ App.jsx
โ”‚       โ”œโ”€โ”€ main.jsx
โ”‚       โ””โ”€โ”€ ...
โ”‚
โ”œโ”€โ”€ docker-compose.yml
โ”œโ”€โ”€ .gitignore
โ””โ”€โ”€ README.md

๐Ÿ“‹ Prerequisites

Before starting, make sure you have the following installed:

1. Node.js

Download and install Node.js from:

Node.js

Check the installation:

node --version
npm --version

2. Docker

Install Docker Desktop:

Docker

Verify:

docker --version

3. Docker Compose

Modern Docker Desktop includes Docker Compose.

Check:

docker compose version

Note: Modern Docker uses docker compose instead of the older docker-compose command.


๐Ÿš€ Getting Started

Clone the repository:

git clone <your-repository-url>

Navigate into the project:

cd mern-app

Build and start all services:

docker compose up --build

Docker will:

  1. Build the backend image
  2. Build the frontend image
  3. Pull the MongoDB image
  4. Create the Docker network
  5. Create the MongoDB volume
  6. Start MongoDB
  7. Start the backend
  8. Start the frontend

๐ŸŸข Backend Setup

Navigate into the backend directory:

cd backend

Initialise the Node.js project:

npm init -y

Install dependencies:

npm install express mongoose

Install Nodemon:

npm install --save-dev nodemon

Backend package.json

Make sure the scripts contain:

{
  "scripts": {
    "start": "nodemon server.js"
  }
}

Backend server.js

const express = require("express");
const mongoose = require("mongoose");

const app = express();

app.use(express.json());

const PORT = 5000;
const MONGO_URI = "mongodb://mongo:27017/mern_db";

mongoose
  .connect(MONGO_URI)
  .then(() => {
    console.log("โœ… MongoDB Connected");
  })
  .catch((error) => {
    console.error("โŒ MongoDB Connection Error:", error);
  });

app.get("/", (req, res) => {
  res.json({
    message: "๐Ÿš€ MERN Backend running in Docker!",
  });
});

app.listen(PORT, "0.0.0.0", () => {
  console.log(`โœ… Server running on port ${PORT}`);
});

๐Ÿณ Backend Dockerfile

Create:

backend/Dockerfile
FROM node:18

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 5000

CMD ["npm", "start"]

๐Ÿšซ Backend .dockerignore

Create:

backend/.dockerignore
node_modules
npm-debug.log
Dockerfile
.dockerignore
.git
.gitignore
.env

โš›๏ธ Frontend Setup

Create the Vite React application:

cd frontend

If the directory is empty:

npm create vite@latest . -- --template react

Install dependencies:

npm install

โš™๏ธ Vite Configuration

Create/update:

frontend/vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  server: {
    host: "0.0.0.0",
    port: 3000,
  },
});

The important part for Docker is:

host: "0.0.0.0"

This allows the Vite development server to accept connections from outside the container.


๐Ÿณ Frontend Dockerfile

Create:

frontend/Dockerfile
FROM node:18

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 3000

CMD ["npm", "run", "dev"]

๐Ÿšซ Frontend .dockerignore

Create:

frontend/.dockerignore
node_modules
npm-debug.log
Dockerfile
.dockerignore
.git
.gitignore
.env
dist

๐Ÿ™ Docker Compose

Create the following file in the project root:

docker-compose.yml
services:

  # -------------------------
  # MongoDB
  # -------------------------
  mongo:
    image: mongo:6
    container_name: mongo
    restart: unless-stopped

    ports:
      - "27017:27017"

    volumes:
      - mongo-data:/data/db


  # -------------------------
  # Backend
  # -------------------------
  backend:
    build: ./backend
    container_name: backend
    restart: unless-stopped

    ports:
      - "5000:5000"

    volumes:
      - ./backend:/app
      - /app/node_modules

    depends_on:
      - mongo


  # -------------------------
  # Frontend
  # -------------------------
  frontend:
    build: ./frontend
    container_name: frontend
    restart: unless-stopped

    ports:
      - "3000:3000"

    volumes:
      - ./frontend:/app
      - /app/node_modules

    depends_on:
      - backend


# -------------------------
# Persistent Volumes
# -------------------------
volumes:
  mongo-data:

๐Ÿ”— Docker Service Communication

One of the most important concepts in Docker Compose is service-to-service communication.

The services are:

mongo
backend
frontend

Inside the Docker network, the backend can access MongoDB using:

mongodb://mongo:27017/mern_db

Do not use:

mongodb://localhost:27017/mern_db

for the backend's MongoDB connection when both are running in separate containers.

Why?

Inside the backend container:

localhost

means:

backend container

not the MongoDB container.

Docker Compose provides DNS resolution so:

mongo

automatically points to the MongoDB container.


โ–ถ๏ธ Running the Application

Build and Start

docker compose up --build

Start in Background

docker compose up -d

Rebuild Containers

docker compose up --build

Stop Containers

docker compose stop

Stop and Remove Containers

docker compose down

Stop and Remove Containers + Volumes

โš ๏ธ This deletes the MongoDB data stored in the Compose volume.

docker compose down -v

๐ŸŒ Access the Application

After starting the application:

Frontend

http://localhost:3000

Backend

http://localhost:5000

MongoDB

From the host:

mongodb://localhost:27017

From the backend container:

mongodb://mongo:27017/mern_db

๐Ÿ” Useful Docker Commands

View Running Containers

docker ps

View All Containers

docker ps -a

View Images

docker images

View Docker Networks

docker network ls

View Volumes

docker volume ls

View Container Logs

Backend:

docker logs backend

Frontend:

docker logs frontend

MongoDB:

docker logs mongo

Follow Logs

docker logs -f backend

Execute Commands Inside a Container

Backend:

docker exec -it backend sh

MongoDB:

docker exec -it mongo mongosh

Stop a Container

docker stop <container_id>

Remove a Container

docker rm <container_id>

Remove an Image

docker rmi <image_id>

Clean Unused Docker Resources

docker system prune

To remove unused volumes as well:

docker system prune --volumes

โš ๏ธ Use this carefully because unused resources may contain data you still need.


๐Ÿ’พ MongoDB Persistence

MongoDB uses a named Docker volume:

volumes:
  - mongo-data:/data/db

The volume is defined at the bottom of docker-compose.yml:

volumes:
  mongo-data:

This means MongoDB data survives container recreation.

For example:

docker compose down

does not delete the MongoDB volume.

Starting the application again:

docker compose up -d

will reuse the existing MongoDB data.

However:

docker compose down -v

removes the volume and therefore deletes the stored MongoDB data.


๐Ÿ”„ Hot Reloading

This project is configured for development.

The backend mounts:

volumes:
  - ./backend:/app
  - /app/node_modules

The frontend mounts:

volumes:
  - ./frontend:/app
  - /app/node_modules

This allows files on your host machine to be synchronized with the containers.

Backend

Nodemon automatically restarts the server when files change.

Frontend

Vite automatically updates the application when React files change.

Therefore, you can edit:

frontend/src/App.jsx

or:

backend/server.js

without manually rebuilding the containers for every code change.


๐Ÿ” Environment Variables

For a real application, MongoDB credentials and configuration should not be hardcoded.

Instead of:

const MONGO_URI = "mongodb://mongo:27017/mern_db";

use:

const MONGO_URI = process.env.MONGO_URI;

Then create:

backend/.env

Example:

PORT=5000
MONGO_URI=mongodb://mongo:27017/mern_db

For production, use a secured MongoDB connection string.

Never commit sensitive .env files to Git.

Add this to .gitignore:

.env
.env.*
!.env.example

๐Ÿงช Testing the Backend

After starting the containers, open:

http://localhost:5000

You should receive:

{
  "message": "๐Ÿš€ MERN Backend running in Docker!"
}

You can also test the API using tools such as Postman or curl.

Example:

curl http://localhost:5000

๐Ÿ› ๏ธ Troubleshooting

1. Port Already in Use

If you see an error such as:

port is already allocated

check which process is using the port.

Windows:

netstat -ano | findstr :3000

or:

netstat -ano | findstr :5000

You can either stop the process or change the port mapping.

For example:

ports:
  - "3001:3000"

The application would then be accessible at:

http://localhost:3001

2. Frontend Cannot Be Accessed

Make sure Vite is configured with:

server: {
  host: "0.0.0.0",
  port: 3000
}

Without host: "0.0.0.0", the development server may only listen inside the container.


3. Backend Cannot Connect to MongoDB

Check MongoDB:

docker ps

Then check its logs:

docker logs mongo

Check backend logs:

docker logs backend

Make sure the connection string uses:

mongodb://mongo:27017/mern_db

and not:

mongodb://localhost:27017/mern_db

4. Changes Are Not Updating

Restart the services:

docker compose restart

If necessary, rebuild:

docker compose down
docker compose up --build

5. node_modules Problems

If dependencies become corrupted, remove the containers and rebuild:

docker compose down
docker compose build --no-cache
docker compose up

6. MongoDB Data Disappeared

Check whether the volume exists:

docker volume ls

Avoid using:

docker compose down -v

unless you intentionally want to delete MongoDB data.


๐Ÿ“ฆ Development vs Production

This repository is primarily configured for development.

The frontend currently runs:

npm run dev

and the backend uses:

nodemon

This is convenient during development but is not the ideal production setup.


๐Ÿš€ Production Architecture

For production, a more appropriate architecture would be:

                    Internet
                       โ”‚
                       โ–ผ
                โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                โ”‚    Nginx      โ”‚
                โ”‚ Reverse Proxy โ”‚
                โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                        โ”‚
              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
              โ”‚                   โ”‚
              โ–ผ                   โ–ผ
        React Static         Express API
        Production Build       Backend
              โ”‚                   โ”‚
              โ”‚                   โ–ผ
              โ”‚              MongoDB
              โ”‚
              โ–ผ
           Browser

The React application should generally be built:

npm run build

and served as static files rather than running the Vite development server.

The backend should also run without Nodemon.

For example:

{
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js"
  }
}

๐Ÿ”’ Production Security Checklist

Before deploying this application to production:

  • Do not expose MongoDB publicly unless required
  • Use environment variables for secrets
  • Use strong MongoDB credentials
  • Use HTTPS
  • Use a reverse proxy such as Nginx
  • Do not use Nodemon in production
  • Build the React application for production
  • Restrict exposed Docker ports
  • Configure CORS properly
  • Add API authentication where required
  • Add request validation
  • Add rate limiting
  • Configure database backups
  • Keep Docker images updated
  • Do not commit .env files

๐Ÿงน Useful Docker Cleanup

Remove stopped containers:

docker container prune

Remove unused images:

docker image prune

Remove unused networks:

docker network prune

Remove unused volumes:

docker volume prune

Remove unused Docker resources:

docker system prune

For a more aggressive cleanup:

docker system prune -a

โš ๏ธ Review what Docker plans to remove before using aggressive cleanup commands.


๐Ÿ“Š Container Overview

After running:

docker compose up -d

you should have three containers:

Container Technology Port
frontend React + Vite 3000
backend Node.js + Express 5000
mongo MongoDB 27017

The communication flow is:

Browser
   โ”‚
   โ”‚ localhost:3000
   โ–ผ
Frontend
   โ”‚
   โ”‚ API
   โ–ผ
Backend
   โ”‚
   โ”‚ mongodb://mongo:27017
   โ–ผ
MongoDB

๐Ÿง  Key Docker Concepts Demonstrated

This project is useful for learning several important Docker concepts.

Containers

Each application component runs in its own container.

Frontend โ†’ Container
Backend  โ†’ Container
MongoDB  โ†’ Container

Images

Dockerfiles define how application images are built.

Dockerfile โ†’ Docker Image โ†’ Container

Volumes

Volumes provide persistent storage.

MongoDB Container
       โ”‚
       โ–ผ
mongo-data volume

Networks

Docker Compose automatically creates a network allowing services to communicate.

frontend โ”€โ”€โ”€โ”€โ”€โ”
              โ”‚
backend โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€ Docker Network
              โ”‚
mongo โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Compose

Docker Compose manages multiple services together.

Instead of running:

docker run ...
docker run ...
docker run ...

you can run:

docker compose up

๐Ÿ”ฎ Future Improvements

This project can be extended with:

  • ๐Ÿ” JWT authentication
  • ๐Ÿ‘ค User registration and login
  • ๐Ÿƒ MongoDB models
  • ๐Ÿ”Œ REST API
  • ๐Ÿ“ก WebSockets
  • ๐Ÿงช Automated testing
  • ๐Ÿ“ฆ Multi-stage Docker builds
  • ๐ŸŒ Nginx reverse proxy
  • ๐Ÿ”’ HTTPS with SSL
  • ๐Ÿš€ CI/CD with GitHub Actions
  • โ˜๏ธ Cloud deployment
  • ๐Ÿ“Š Application monitoring
  • ๐Ÿ“ API documentation with Swagger
  • ๐Ÿ”‘ Secret management
  • ๐Ÿ—„๏ธ MongoDB backup strategy
  • โšก Redis caching

๐Ÿš€ Quick Start

If everything is already configured, simply run:

git clone <your-repository-url>

cd mern-app

docker compose up --build

Then open:

Frontend โ†’ http://localhost:3000
Backend  โ†’ http://localhost:5000

To stop:

docker compose down

๐Ÿ“š Learning Resources

For official documentation:


๐Ÿค Contributing

Contributions are welcome!

  1. Fork the repository
  2. Create a feature branch
git checkout -b feature/my-feature
  1. Make your changes
  2. Commit your changes
git commit -m "Add my feature"
  1. Push the branch
git push origin feature/my-feature
  1. Open a Pull Request

๐Ÿ“„ License

This project is available under the MIT License.

You are free to use, modify, and distribute the project according to the terms of the license.


โญ Support

If this project helped you understand how to Dockerise a MERN application, consider giving the repository a โญ on GitHub.

Happy Coding! ๐Ÿš€๐Ÿณ

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages