What Is a Reverse Proxy?
If you are new to networking, a reverse proxy sounds more complex than it really is.
In very simple words:
- A reverse proxy is a middle layer between your browser and an app.
- You talk to the reverse proxy first.
- The reverse proxy forwards your request to the real backend service.
- Then it sends the backend response back to you.
So your browser does not talk directly to the backend. It talks to the reverse proxy.
Simple Diagram
Browser
↓
localhost:8181
↓
Nginx Reverse Proxy
↓
Backend service on TARGET_HOST:TARGET_PORT
Why Use a Reverse Proxy?
Common reasons:
- Keep one public entry point
- Route traffic to different backend services
- Hide backend details from users
- Add SSL/TLS, caching, or rate limits later
For this post, we keep it minimal and practical.
Local Example (Docker Compose + Nginx)
Scenario:
- You open
http://localhost:8181 - Nginx listens on port
8181 - Nginx forwards to a backend service on port
80 - Backend host and port are configurable from
.env
This runs locally on any developer machine with Docker and Docker Compose.
Project Files
Create a folder (for example reverse-proxy-demo) and add these files.
1) docker-compose.yml
services:
reverse-proxy:
image: nginx:alpine
container_name: reverse-proxy
ports:
- "8181:8181"
environment:
TARGET_HOST: ${TARGET_HOST}
TARGET_PORT: ${TARGET_PORT}
volumes:
- ./nginx.conf.template:/etc/nginx/templates/default.conf.template:ro
depends_on:
- backend
backend:
image: nginx:alpine
container_name: demo-backend
What it does:
- Starts two containers:
reverse-proxyandbackend - Maps your machine port
8181to Nginx reverse proxy - Injects
TARGET_HOSTandTARGET_PORTfrom.env - Uses the Nginx template file to generate runtime config
2) nginx.conf.template
server {
listen 8181;
server_name _;
location / {
proxy_pass http://${TARGET_HOST}:${TARGET_PORT};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
What it does:
- Nginx listens on
8181 - Forwards every request to
TARGET_HOST:TARGET_PORT - Sends useful headers to backend
3) .env
TARGET_HOST=backend
TARGET_PORT=80
What it does:
- Defines where Nginx should forward traffic
- Easy to change without editing YAML or Nginx config
Commands to Run
Inside your project folder:
docker compose up -d
Open:
http://localhost:8181
You should see the default Nginx backend page.
Stop everything:
docker compose down
Changing Target Host or Port
Edit .env:
TARGET_HOST=backend
TARGET_PORT=80
Then recreate containers:
docker compose down
docker compose up -d
Quick Troubleshooting
1) Port 8181 is already used
Error usually looks like: bind: address already in use.
Fix:
- Stop the process using
8181, or - Change mapping in
docker-compose.yml(example:8282:8181)
2) Bad Gateway (502)
Usually means Nginx cannot reach backend.
Check:
- Is backend container running?
docker compose ps - Are
TARGET_HOSTandTARGET_PORTcorrect in.env? - Recreate containers after changes:
docker compose down && docker compose up -d
3) Config changes not applied
If you changed .env or template and behavior did not change, restart stack:
docker compose down
docker compose up -d
Final Takeaway
A reverse proxy is simply a traffic forwarder in front of your backend.
With Docker Compose + Nginx + .env, you get a clean local setup where backend target host/port are easy to change and test.