How I deploy and operate .NET applications in production. A complete containerized stack on AWS Lightsail Ubuntu 24 with SSL termination, load balancing, and automatic certificate renewal.
Every service runs in its own container, communicating via Docker's internal network. Only HAProxy exposes ports to the internet.
:443 → internal
:80 internal
:80 internal
:1433 internal
:27017 internal
:6379 internal
:5672 internal
:7687 internal
:9200 internal
:1521 internal
:9443 mgmt
Let's Encrypt
Not a dev environment. This is how real enterprise applications run.
HAProxy handles all HTTPS on port 443, terminates SSL, then forwards plain HTTP to internal containers. .NET apps don't manage certificates.
Clients get HTTP/2 for multiplexed requests and header compression. Backend stays HTTP/1.1 because Docker's internal network doesn't need the overhead.
WebSockets need special handling: sticky sessions, extended timeouts (1 hour vs 30 seconds), and proper upgrade header forwarding.
MongoDB GridFS stores large files. Uploads can take minutes. HAProxy has a separate backend with 5-minute timeouts for /gridfs/* paths.
All services use Docker's internal bridge network with container names as hostnames. The API connects to 'sqlserver:1433', not IP addresses.
Cron job runs daily at 3 AM. If certificates are within 30 days of expiry, Certbot renews them. Zero manual intervention ever.
How a request travels from the internet to your .NET application.
HTTPS :443
SSL termination
/api vs /hub vs /*
HTTP :80
SQL/Mongo/Redis
The actual docker-compose.yml that runs everything. One file, 12 services.
Production-proven infrastructure components.