Case Study
End-to-End Deployment of Guidra Backend on Azure VM
Azure VM → Nginx → Node.js → MongoDB Atlas
Executive Summary
This case study documents the production deployment of the Guidra backend API on Microsoft Azure infrastructure. The implementation demonstrates production-oriented deployment practices including security hardening, reverse proxy configuration, SSL termination, process management, and cloud database integration.
Technologies Used: Azure VM (Ubuntu 24.04), Nginx, Node.js, PM2, MongoDB Atlas, Let's Encrypt
Key Metrics:
- API latency: ~150–230ms
- Memory usage: ~600MB (idle)
- Uptime tested: 7+ days
- SSL rating: A (Qualys SSL Labs)
- Deployment time: less than 30 seconds (automated script)
- Availability: 24/7 production uptime
1. System Architecture
Internet → Azure NSG → UFW → Nginx (reverse proxy) → PM2 → Node.js App → MongoDB Atlas
| Layer | Technology | Purpose |
|---|---|---|
| Cloud | Azure VM (B2als v2) | Compute infrastructure |
| Network | Azure NSG + UFW | Defense-in-depth firewall |
| Web Server | Nginx | Reverse proxy, SSL termination |
| Runtime | Node.js 20 LTS | Application execution |
| Process | PM2 | Process management, auto-restart |
| Database | MongoDB Atlas | Cloud database service |
| Security | fail2ban, SSH hardening | Intrusion prevention |
| SSL | Let's Encrypt | Free automated certificates |
2. Deployment Phases
Infrastructure Foundation
- Azure VM provisioning with static public IP
- SSH key authentication (password-less)
- Deploy user creation (non-root)
- UFW configuration (ports 22, 80, 443 only)
Security Implementation
- SSH hardening (/etc/ssh/sshd_config modifications)
- fail2ban configuration with custom jail
- Automatic security updates enabled
- Azure NSG rules configured
Application Stack
- NVM + Node.js LTS installation
- PM2 process manager setup
- MongoDB Atlas connection with SRV string
- Environment variable management
Web Server Configuration
- Nginx reverse proxy setup
- SSL certificates via Let's Encrypt
- HTTP → HTTPS redirection
- Custom domain configuration
Deployment Automation
- Git-based deployment script
- SSH config for GitHub authentication
3. Challenges & Solutions
| Challenge | Solution | Engineering Impact |
|---|---|---|
| SSH lockout during fail2ban testing | Azure portal emergency SSH key reset | Understood cloud recovery paths |
| Nginx only listening on IPv6 | Added listen 0.0.0.0:80; directive | Learned socket binding nuances |
| Domain DNS propagation delay | Used dnschecker.org for verification | Real-world DNS debugging |
| Azure NSG blocking port 80 | Added inbound rule in portal | Cloud firewall configuration |
| GitHub SSH key confusion | Created ~/.ssh/config with explicit IdentityFile | SSH client mastery |
| fail2ban config overwrite risk | Used jail.local instead of modifying jail.conf | Configuration best practices |
Key Incident: Self-inflicted SSH ban led to Azure emergency recovery—validated both fail2ban functionality and cloud provider fallback mechanisms.
4. Security Hardening
Defense in Depth Implementation
| Layer | Technology | Configuration |
|---|---|---|
| Network Edge | Azure NSG | Inbound rules: 22,80,443 only |
| Host Firewall | UFW | Default deny, explicit allow |
| Intrusion Prevention | fail2ban | 3 strikes → 1 hour ban |
| Access Control | SSH | Keys only, root disabled |
| Updates | unattended-upgrades | Automatic security patches |
| Encryption | Let's Encrypt | 90-day certs, auto-renewal |
SSH Hardening Parameters
PermitRootLogin no PasswordAuthentication no PubkeyAuthentication yes MaxAuthTries 3 AllowUsers deploy
fail2ban Configuration
[sshd] enabled = true maxretry = 3 bantime = 3600 findtime = 600
5. Production Validation
Tests Performed
| Test | Method | Result |
|---|---|---|
| Server reboot persistence | sudo reboot followed by SSH | ✅ PM2 auto-restart verified |
| Process crash recovery | kill -9 <node-pid> | ✅ PM2 respawned within 2s |
| Nginx auto-start | Server reboot check | ✅ Nginx active post-reboot |
| SSL auto-renewal | certbot renew --dry-run | ✅ Successful |
| Firewall rules | nmap -p 22,80,443 from external | ✅ Only specified ports open |
| DNS resolution | dig guidra.tech | ✅ Correct A record |
| Reverse proxy | Direct port 3000 vs 443 | ✅ Headers preserved |
| Health endpoint | Continuous monitoring | ✅ 200 OK response |
Logging Infrastructure
/var/www/guidra/logs/ # Application logs (out/err/combined) /var/log/nginx/ # Web server access/error logs /var/log/fail2ban.log # Intrusion attempts /var/log/auth.log # Authentication events
6. Deployment Workflow
Simple, Reliable Deployment
# Local development git add . git commit -m "feature update" git push # Server deployment (single command) ssh deploy@guidra.tech './deploy-guidra.sh'
Deploy Script Logic
cd /var/www/guidra/current git pull npm ci --only=production || npm install --production pm2 restart guidra-api --update-env
CI/CD Philosophy: Manual trigger with automation—balance of control and efficiency for solo development.
Deployment is triggered manually from the local machine using SSH and a deployment script.
7. Key Lessons & Engineering Insights
Technical Mastery Gained
- Network layering: NSG vs UFW vs application-level filtering
- DNS mechanics: Propagation, TTL, record types
- Socket binding: localhost vs 0.0.0.0 implications
- Process management: PM2's role in production reliability
- Configuration management: Never edit original config files
Operational Wisdom
- Always test security features with backup access
- Document recovery procedures before needing them
- Monitor logs before monitoring metrics
- Simple automation beats complex tooling
"The day I banned myself from my own server taught me more about fail2ban, Azure recovery, and SSH than any tutorial could."
8. Future Improvements
| Priority | Improvement | Rationale |
|---|---|---|
| High | Automated backups to S3 | Data durability |
| High | Rate limiting implementation | API abuse prevention |
| Medium | PM2 monitoring dashboard | Visual metrics |
| Medium | GitHub Actions CI/CD | Fully automated deploys |
| Low | Docker containerization | Environment consistency |
| Low | Multi-instance scaling | Horizontal scalability |
Live System
Frontend: https://guidra.tech
Backend API: https://api.guidra.tech
Health Endpoint: https://api.guidra.tech/health
9. Conclusion
This deployment transformed a fresh Azure VM into a production-tested backend deployment hosting the Guidra API. The implementation encompasses security hardening, reverse proxy configuration, SSL termination, process management, and cloud database integration—all providing a reliable and maintainable production environment.
The experience provided invaluable hands-on learning in system administration, networking, and DevOps that textbooks cannot replicate. From recovering from self-inflicted SSH bans to debugging Nginx listen directives, each challenge reinforced practical engineering skills.
The experience provided hands-on learning in system administration, networking, and DevOps beyond textbook environments.
Engineering Competencies Demonstrated
- Linux System Administration
- Cloud Infrastructure (Azure)
- Network Security (NSG, UFW, fail2ban)
- Web Server Configuration (Nginx)
- Process Management (PM2)
- Database Integration (MongoDB Atlas)
- SSL/TLS Implementation
- DNS Configuration
- Deployment Automation
- Incident Recovery