NestJS course Β· Module 9: Deployment and Infrastructure
PROJECT: Full deployment of a NestJS application to production
In this lesson2
Legate! Your application runs on your laptop, but Consul Caesar.js asks the questions that come up in every real deployment: what happens when the server goes dark at three in the morning? Who will notice that the database is slowing down? How do you know yesterday's backup can be restored? The Consul entrusts you with the greatest challenge - a complete deployment of the Roman legion to production. It is the true test of the skills you have gained during our NestJS campaign.
Project Specification
Your task is to create a complete deployment system for the Legionary Legion API application. Every part builds on the lessons of this and earlier modules, so before you start, go back to them like to staff maps. The hours given are an approximate amount of work.
1. Infrastructure (4-5 hours)
- Docker and Docker Compose configuration
- Kubernetes/Helm charts setup
- CI/CD pipeline configuration
- Monitoring and logging
Start with an image built in a multi-stage build and a Compose file that brings up the application together with MongoDB and Redis. In Kubernetes describe the replicas, the rolling update strategy and the readiness and liveness probes. The pipeline should run the tests, build the image and deploy it only after the tests are green.
2. Security (2-3 hours)
- SSL/TLS implementation
- Security headers and rate limiting
- Secrets management
- Vulnerability scanning
You already know HTTPS, Helmet headers and throttler limits. Keep secrets outside the repository and the image, and let the application refuse to start when one of them is missing. Add a vulnerability scanner, e.g. Trivy, to the pipeline, so that an image with a critical flaw never reaches production.
3. Performance (2-3 hours)
- Load balancing and auto-scaling
- Caching strategy
- Database optimization
- CDN setup
Measure before you optimize: a load test result before and after your changes is the best evidence. Match indexes to the most frequent queries, add a Redis cache with well-thought-out invalidation, and cache headers for the CDN. Autoscaling adds replicas based on metrics such as CPU, so the application must be stateless: sessions and caches live in Redis, not in process memory.
4. Monitoring (2-3 hours)
- Health checks
- Metrics collection
- Alerting system
- Log aggregation
Split health endpoints into liveness and readiness, expose metrics for Prometheus, and write logs in JSON with a request identifier. An alert should wake someone up only when something needs to be done - an alarm that is too loud quickly stops being heard.
5. Backup & Recovery (1-2 hours)
- Automated backups
- Disaster recovery plan
- Data integrity checks
Run backups automatically, set your RTO and RPO, then carry out one full restore on a fresh environment and write down how long it took.
Evaluation Criteria
- Completeness - all components work together
- Security - proper safeguards on every layer, from TLS to secrets
- Performance - the application handles production traffic, as a load test confirms
- Monitoring - full observability: metrics, logs and alerts
- Documentation - deployment and recovery runbooks
The mentor will assess the project from the repository, so the README must contain the start-up commands, an architecture description and the results of the restore test. I recommend writing the runbook alongside the configuration not at the end - whatever you do not write down straight away will be mere guesswork at three in the morning.
Good luck, legate! Your legion is counting on you, and you will send the finished system to your mentor at the end of the module.
Code for this lesson: deployment-project/docker-compose.yml
1# PROJECT: Full NestJS Application Deployment to Production
2
3version: '3.8'
4
5services:
6 # === API NestJS ===
7 api:
8 build:
9 context: .
10 dockerfile: Dockerfile
11 container_name: roman-api
12 restart: unless-stopped
13 ports:
14 - "4000:4000"
15 environment:
16 NODE_ENV: production
17 PORT: 4000
18 MONGO_URI: mongodb://mongo:27017/roman_empire
19 REDIS_HOST: redis
20 REDIS_PORT: 6379
21 JWT_SECRET: ${JWT_SECRET}
22 ALLOWED_ORIGINS: https://roman-empire.com
23 depends_on:
24 mongo:
25 condition: service_healthy
26 redis:
27 condition: service_healthy
28 healthcheck:
29 test: ["CMD", "node", "-e",
30 "require('http').get('http://localhost:4000/health', (r) => { process.exit(r.statusCode === 200 ? 0 : 1) })"]
31 interval: 30s
32 timeout: 10s
33 retries: 3
34 start_period: 40s
35 networks:
36 - roman-network
37
38 # === MongoDB ===
39 mongo:
40 image: mongo:7
41 container_name: roman-mongodb
42 restart: unless-stopped
43 volumes:
44 - mongo-data:/data/db
45 - ./scripts/backup.sh:/scripts/backup.sh
46 environment:
47 MONGO_INITDB_DATABASE: roman_empire
48 healthcheck:
49 test: ["CMD", "mongosh", "--eval", "db.runCommand('ping').ok"]
50 interval: 10s
51 timeout: 5s
52 retries: 5
53 networks:
54 - roman-network
55
56 # === Redis Cache ===
57 redis:
58 image: redis:7-alpine
59 container_name: roman-redis
60 restart: unless-stopped
61 command: redis-server --appendonly yes
62 volumes:
63 - redis-data:/data
64 healthcheck:
65 test: ["CMD", "redis-cli", "ping"]
66 interval: 10s
67 timeout: 3s
68 retries: 3
69 networks:
70 - roman-network
71
72 # === Nginx Reverse Proxy ===
73 nginx:
74 image: nginx:alpine
75 container_name: roman-nginx
76 restart: unless-stopped
77 ports:
78 - "80:80"
79 volumes:
80 - ./nginx.conf:/etc/nginx/nginx.conf:ro
81 depends_on:
82 - api
83 networks:
84 - roman-network
85
86# Volumes
87volumes:
88 mongo-data:
89 driver: local
90 redis-data:
91 driver: local
92
93# Network
94networks:
95 roman-network:
96 driver: bridge
97
98# Commands:
99# docker-compose up -d # Run
100# docker-compose logs -f api # API logs
101# docker-compose down # Stop
102# docker-compose ps # Status
103Spotted a mistake in this lesson?