Building a Virtual Host and Reverse Proxy Simulator with Docker
May 12, 2026
This project demonstrates how to manage multiple domains on a single server using Nginx as a Reverse Proxy and Docker for infrastructure isolation. The goal is to route traffic for domain-a.com (static content) and domain-b.com (dynamic containerized service) through a single entry point.
Core Concepts
Virtual Hosting & HTTP Host Headers
Web servers use the HTTP Host Header to distinguish between multiple domains sharing the same IP address. When a browser sends a request, it includes a header like Host: domain-a.com. Nginx inspects this header and matches it against the server_name directive in its configuration to decide which content to serve.
Reverse Proxy
Instead of serving files directly, a Reverse Proxy intercepts requests and forwards them to another backend server or container. This is essential for load balancing, security, and managing microservices.

Project Architecture
- Entry Point: Port 80 on
127.0.0.1(Localhost). - Web Server: Nginx (Containerized).
- Backend Service: A lightweight HTTP Echo container.
- Network: A custom Docker bridge network (
proxy-net) for secure internal communication.
Project Structure
simulator-proxy/
├── docker-compose.yml # Infrastructure Orchestration
├── default.conf # Nginx Routing Logic
└── html/ # Static Content Folders
├── domain-a/index.html
└── domain-b/index.html
Implementation Details
Docker Infrastructure (docker-compose.yml)
We define two services. Notice the networks block, which enables Service Discovery, allowing Nginx to find the app container by its name.
services:
web-server:
image: nginx:alpine
container_name: nginx-simulator
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
- ./default.conf:/etc/nginx/conf.d/default.conf
networks:
- proxy-net
app-service:
image: hashicorp/http-echo
container_name: internal-app
command: ["-text=Hello! I am the internal application."]
networks:
- proxy-net
networks:
proxy-net:
driver: bridge
Nginx Configuration (default.conf)
The configuration handles two different routing strategies:
- Direct Root: Serving static files for Domain A.
- Proxy Pass: Forwarding traffic for Domain B to the
internal-appcontainer.
server {
listen 80;
server_name domain-a.com;
location / {
root /usr/share/nginx/html/domain-a;
index index.html;
}
}
server {
listen 80;
server_name domain-b.com;
location / {
proxy_pass http://internal-app:5678;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Deployment Steps

- Simulate DNS: Edit your local
/etc/hosts(Linux/Mac) orC:\Windows\System32\drivers\etc\hosts(Windows) to map the domains to your local machine:Plaintext127.0.0.1 domain-a.com 127.0.0.1 domain-b.com - Launch Containers:
docker compose up -d - Verify Connectivity:
- Visit
http://domain-a.comto see the static HTML. - Visit
http://domain-b.comto see the response proxied from the internal app.
- Visit

Conclusion
By using Docker and Nginx, we successfully simulated a production-grade environment. We learned that Port 80 acts as the gateway, the Host Header acts as the sorter, and Docker Networks act as the internal communication lines that keep the services connected yet isolated.