Series: From Code to Cloud: Building a Production-Ready .NET Application
By: Farrukh Rehman - Senior .NET Full Stack Developer / Team Lead
LinkedIn: https://linkedin.com/in/farrukh-rehman
GitHub: https://github.com/farrukh1212cs
Source Code Backend : https://github.com/farrukh1212cs/ECommerce-Backend.git
Source Code Frontend : https://github.com/farrukh1212cs/ECommerce-Frontend.git
🎯 Introduction
In modern software engineering, containerization is a fundamental skill for building portable, scalable, and DevOps-friendly applications. By packaging both the .NET 8 backend API and the Angular Admin Panel inside Docker containers, we ensure that the entire application stack can run consistently across any environment—local, QA, staging, or production—without dependency conflicts or manual setup.
This lesson focuses exclusively on:
- Creating a Dockerfile for the .NET 8 E-Commerce API
- Creating a Dockerfile for the Angular Admin App (using the Mantis free template)
- Running both applications in isolated Docker containers
- Configuring docker-compose to orchestrate both services together
After completing this lesson, you will be able to launch the entire backend + admin panel with one command:
docker-compose up --build -d
This is an essential step toward production readiness and CI/CD automation in future lessons.
Section 1 — Dockerizing the .NET 8 Backend API
FIRST OF ALL WE NEED TO UPDATE PROGRAM FILE FOR AUTO RUN MIGRATIONS

We will create a multi-stage Dockerfile that:
- Restores dependencies
- Publishes the project
- Runs the optimized build inside ASP.NET Core runtime
Step 1.1 — Create Dockerfile in your API project root
Location:
Path : "/ECommerce.API/Dockerfile"
Right-click the API project, select Add, and then choose Container Support to enable containerization for the service.
Lets Configure Docker Containers to connect each other.
First Create Docker Network
docker network create ecommerce-net
Lets Connect Postgres to this Network (ecommerce-net)
docker network connect ecommerce-net postgres
Now time to connect RabbitMQ to network (ecommerce-net)
docker network connect ecommerce-net rabbitmq
Its time to connect Redis with the network (ecommerce-net)
docker network connect ecommerce-net ecommerce-redis
Last setp lets verify Network
docker inspect ecommerce-net
All Containers are Connected with our network.now its time to work on api side.
Copy all configuration values from appsettings.json into appsettings.Development.json
Update appsettings.Development.json Replace localhost from ConnectionStrings:PostgreSQL to ContainerName (postgres)
Update Redis localhost to ContainerName (ecommerce-redis)
Update RabbitMQ localhost to ContainerName (rabbitmq)
Lets try to Build Image (make sure docker is running)
docker build -t ecommerce-api -f ECommerce.API/Dockerfile .
docker images
Run the API Container
docker run -p 5000:8080 --name ecommerce-api-container --network ecommerce-net -e ASPNETCORE_ENVIRONMENT=Development ecommerce-api
Its time to Test Swagger our container is accessable on port 5000
Lets start working on angular containerization
we need to create four files
Dockerfile,.dockerignore,nginx.conf,environment.prod.ts
Path: "ecommerce-backoffice\Dockerfile"
FROM node:20.19-alpine AS build
WORKDIR /app
# Install dependencies (use npm ci for reproducible installs)
COPY package.json package-lock.json* ./
RUN npm ci --silent || npm install --silent
# Copy source and build the Angular app
COPY . .
RUN npm run build -- --configuration=production
FROM nginx:stable-alpine
# Remove default nginx static assets
RUN rm -rf /usr/share/nginx/html/*
# Copy built Angular app from the builder stage
COPY --from=build /app/dist/sakai-ng/browser /usr/share/nginx/html
# Expose port 80
EXPOSE 80
# Start nginx in the foreground
CMD ["nginx", "-g", "daemon off;"]
Path: "ecommerce-backoffice.dockerignore"
.dockerignore
node_modules
dist
.git
.gitignore
Dockerfile
docker-compose*.yml
docker-compose*.yaml
README.md
*.log
.vscode
.idea
coverage
tmp
out-tsc
# keep source files included so the build can run
Path: "ecommerce-backoffice\nginx.conf"
nginx.conf
server {
listen 80;
server_name localhost;
# Serve the Angular app
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# Proxy API requests to your backend
location /api/ {
proxy_pass https://host.docker.internal:7104;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
# Disable SSL verification (for self-signed certs in local dev)
proxy_ssl_verify off;
proxy_ssl_session_reuse on;
}
}
Path: "ecommerce-backoffice\src\environments\environment.prod.ts"
environment.prod.ts
export const environment = {
production: true,
// API requests are proxied through nginx to the backend
baseUrl: 'http://localhost:7104/api'
};
Its time to build Angular Image
docker build -t sakai-ng:latest .
docker images
docker run --rm -p 80:80 sakai-ng:latest
Final Step Lets Write docker-compose.yml
networks:
ecommerce-net:
external: true
services:
postgres:
image: postgres:15
container_name: postgres
restart: unless-stopped
environment:
POSTGRES_DB: ECommerceDb
POSTGRES_USER: postgres
POSTGRES_PASSWORD: Admin123!
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- ecommerce-net
rabbitmq:
image: rabbitmq:3-management
container_name: rabbitmq
restart: unless-stopped
ports:
- "5672:5672"
- "15672:15672"
networks:
- ecommerce-net
redis:
image: redis:7
container_name: ecommerce-redis
restart: unless-stopped
ports:
- "6379:6379"
networks:
- ecommerce-net
ecommerce-api:
image: ecommerce-api
container_name: ecommerce-api-container
restart: unless-stopped
ports:
- "7104:8080"
environment:
ASPNETCORE_ENVIRONMENT: Development
ConnectionStrings__PostgreSQL: Host=postgres;Port=5432;Database=ECommerceDb;Username=postgres;Password=Admin123!
Redis__Host: redis
RabbitMQ__Host: rabbitmq
depends_on:
- postgres
- rabbitmq
- redis
networks:
- ecommerce-net
sakai-ng:
image: sakai-ng:latest
container_name: sakai-ng
restart: unless-stopped
ports:
- "80:80"
depends_on:
- ecommerce-api
networks:
- ecommerce-net
volumes:
postgres_data:
Lets Test from UI
Next Lecture Preview
Lecture 11 : Continuous Integration with Jenkins
Creating CI/CD pipelines in Jenkins for automated build, test, and deployment workflows.






















Top comments (0)