Containerized .NET chat backend on Azure VMs and Front Door

Technologies
Summary
Real-time chat for tennis clubs on Azure, with a containerized .NET backend and a Vue.js frontend across dev, stg and prod.
This is a real-time chat platform for tennis clubs. It runs in three environments, dev, stg and prod, and each one has its own VM, secrets and container image. GitHub Actions builds the containerized .NET backend, pushes it to Azure Container Registry, and runs it on an Ubuntu VM behind Nginx. The Vue.js frontend is built inside Docker with environment variables injected from GitHub Secrets at build time, and Nginx serves the static output from the same VM. Azure Front Door routes traffic to the VM and serves uploads from Azure Blob Storage. The VM sits in a public subnet on HTTPS 443, and Microsoft SQL Server sits in a private subnet that accepts 1433 only from the app VM. Bulk email goes through SendGrid and DNS is on Cloudflare.
Details — Tech Stack
13 technologies across 5 layers
frontend
backend
database
cloud
tools
Details — Key Features
Three environments (dev, stg, prod), each with its own VM, secrets and container image
.NET backend built in GitHub Actions, pushed to Azure Container Registry and run on an Ubuntu VM behind Nginx
Vue.js frontend built inside Docker with environment variables from GitHub Secrets, served by Nginx
Azure Front Door routes traffic to the VM and serves uploads from Azure Blob Storage
VM in a public subnet on HTTPS 443, with Microsoft SQL Server in a private subnet reachable on 1433 only from the app VM
Backend .env file kept only on the VM and passed to the container with --env-file
SSH deploy: ACR login, pull, replace the container on port 8080 with --restart always, then prune dangling images
Bulk email through SendGrid, with DNS on Cloudflare
Methodology
01
Backend and frontend secrets had to stay out of the Git repository.
The backend .env file lives only on the VM and is passed to the container with --env-file. Frontend variables come from GitHub Secrets and are injected when the Docker build runs.
02
The SQL Server database had to be reachable by the app but not from the internet.
The VM sits in a public subnet that accepts only HTTPS on 443. SQL Server sits in a private subnet and accepts port 1433 only from the app VM.
Gallery
