A containerized Node.js + Express backend service — built, tagged, and published to Docker Hub. Demonstrates the full Docker workflow from writing a Dockerfile to running a portable container from a public registry.
Docker Hub:
kuhata/testrepo:latest· Image size: 55.9 MB · Port: 3000
Pull and run the image directly from Docker Hub:
docker pull kuhata/testrepo:latest
docker run -p 3000:3000 kuhata/testrepo:latestThen visit: http://localhost:3000
You'll get a JSON response confirming the service is running.
Dockerfile
│
▼
docker build → Local Image
│
▼
docker push → Docker Hub (kuhata/testrepo:latest)
│
▼
docker pull + run → Container running on port 3000
The app is a lightweight Node.js + Express server. Docker packages it with all its dependencies into a portable image that runs identically on any machine — no "works on my machine" issues.
| Layer | Tool |
|---|---|
| Runtime | Node.js + Express |
| Containerization | Docker |
| Image Registry | Docker Hub |
| Port | 3000 |
| Image Size | 55.9 MB |
dockerized-backend/
├── index.js # Express server — main app entry point
├── dockerfile # Docker build instructions
├── .dockerignore # Excludes node_modules and other files from image
├── package.json # Node.js dependencies
└── package-lock.json
# Use official Node.js base image
FROM node:18-alpine
# Set working directory inside container
WORKDIR /app
# Copy dependency files first (layer caching optimization)
COPY package*.json ./
# Install dependencies
RUN npm install
# Copy rest of the source code
COPY . .
# Expose the port the app runs on
EXPOSE 3000
# Start the app
CMD ["node", "index.js"]Why alpine? The Alpine-based Node image is significantly smaller than the default, keeping the final image lean.
Why copy package.json before source code? Docker caches each layer — by copying dependencies first, npm install only re-runs when dependencies actually change, not on every code change. This speeds up builds.
.dockerignore — Prevents node_modules/ from being copied into the image. The image installs its own clean dependencies via npm install, keeping the build reproducible and avoiding OS-incompatible binaries from the host machine.
Port mapping (-p 3000:3000) — Maps port 3000 on your local machine to port 3000 inside the container. Format is host:container.
Image tagging — The image is tagged as kuhata/testrepo:latest, following the Docker Hub naming convention of username/repository:tag.
Public registry — Published to Docker Hub so the image can be pulled and run by anyone on any machine without needing the source code.
# Build the image locally
docker build -t kuhata/testrepo:latest .
# Run the container
docker run -p 3000:3000 kuhata/testrepo:latest
# Run in detached (background) mode
docker run -d -p 3000:3000 kuhata/testrepo:latest
# List running containers
docker ps
# Stop a running container
docker stop <container-id>
# Push to Docker Hub (requires docker login)
docker login
docker push kuhata/testrepo:latest
# Pull from Docker Hub
docker pull kuhata/testrepo:latest- Add a
docker-compose.ymlto orchestrate the app with a MongoDB container - Set up GitHub Actions to auto-build and push the image on every commit (CI/CD)
- Deploy the container on AWS EC2 instead of a raw Node.js process
- Add multi-stage builds to further reduce image size
- Node.js AWS EC2 Deployment — Deployed Node.js on EC2 with Nginx + PM2
- Weather App — Live frontend on Vercel
Harsh Thakur LinkedIn · GitHub · Docker Hub