Hosting Multiple Domains on One Server with Docker, NGINX & SSL (DevOps for Developers)
By Muhammad Sharjeel | Published on Sun Jul 13 2025

Why This Was Worth Learning
As a full-stack developer, I usually focus on building features — not server orchestration. But recently, I needed to deploy three independent services (Alara, PolyX, Langflow) on a single cloud server. Each had its own domain name, microservices, databases, and required HTTPS.
This felt like a DevOps task. But instead of offloading it, I decided to learn it. Here's exactly how I pulled it off with Docker, NGINX, and Certbot.
Problem Statement
- One server (GCP VM)
- Three services: Alara, PolyX, Langflow
- Each must be accessible from its own domain:
https://alara-agents.com
https://poly-x.com
https://langflow.app
- Each service uses microservices (Node.js, Redis, MongoDB)
- Each service is containerized with Docker
- All domains must have valid SSL certificates (Let's Encrypt)
Solution Architecture
I used a centralized NGINX reverse proxy pattern:
- One main NGINX container exposed on ports 80 and 443
- Each app stack runs its own Docker services (on custom ports)
- Domains are routed via NGINX
server_name
blocks - SSL certificates are handled via Certbot and mounted into NGINX
Folder Structure
/projects
├── nginx-proxy/
│ ├── docker-compose.yml
│ └── conf.d/
│ ├── alara.conf
│ ├── polyx.conf
│ └── langflow.conf
├── alara/
│ └── docker-compose.yml
├── polyx/
│ └── docker-compose.yml
└── langflow/
└── docker-compose.yml
Docker Networking Strategy
I created a shared Docker network:
docker network create shared
Each app and the NGINX container are connected to this shared network. This allows NGINX to proxy to containers by name (e.g., alara-api:3000
).
Central NGINX Setup
Here’s a snippet from my main NGINX container’s compose file:
services:
nginx:
image: nginx:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./conf.d:/etc/nginx/conf.d
- /etc/letsencrypt:/etc/letsencrypt
- /var/www/certbot:/var/www/certbot
networks:
- shared
NGINX Domain Config (alara.conf)
server {
listen 80;
server_name alara-agents.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name alara-agents.com;
ssl_certificate /etc/letsencrypt/live/alara-agents.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/alara-agents.com/privkey.pem;
location / {
proxy_pass http://alara-api:3000;
include proxy_params;
}
}
I repeated this setup for poly-x.com
and langflow.app
as well.
App Port Mapping (Avoiding Conflicts)
Each service stack maps its internal ports to unique external ones. For example:
Alara:
3100:3000 (API)
3101:3001 (Auth)
3102:5000 (Alerts)
PolyX:
3200:3000
3201:4000
3202:5000
Langflow:
3300:3000
3301:5000
MongoDB and Redis also get isolated ports per service. This eliminates any conflicts.
SSL via Certbot
I used Certbot in webroot mode (so it works behind NGINX):
docker run --rm -it \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /var/www/certbot:/var/www/certbot \
certbot/certbot certonly \
--webroot --webroot-path=/var/www/certbot \
-d alara-agents.com -d poly-x.com -d langflow.app
Certificates are automatically mounted into the NGINX container.
Auto-Renewal
I set up a cron job to renew certificates and reload NGINX monthly:
0 3 * * * docker run --rm \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /var/www/certbot:/var/www/certbot \
certbot/certbot renew --webroot --webroot-path=/var/www/certbot \
&& docker exec nginx-proxy nginx -s reload
Result: 3 Domains, 1 Server, Full HTTPS
https://alara-agents.com
→ Alara stackhttps://poly-x.com
→ PolyX stackhttps://langflow.app
→ Langflow stack
All isolated, independently scalable, and SSL-secure — running on a single server.
Key Takeaways
- Use one NGINX reverse proxy to handle all domain routing
- Keep Docker networks shared but services isolated
- Use Certbot in webroot mode and mount volumes into NGINX
- Map ports uniquely per app to prevent service collisions
Final Thoughts
This experience taught me that as a full-stack dev, understanding DevOps makes you 10× more effective — especially when working solo or deploying to production. This setup is now part of my go-to deployment playbook.
Hope it helps you as much as it helped me!