Reverse Proxy Architecture: Traefik and Nginx Explained
A reverse proxy is the public-facing entry point that accepts client requests and forwards them to private application services. It lets a self-hosted server expose several websites or APIs through one address while keeping application ports, certificates, routing rules, and access controls in one place. This guide explains reverse proxy architecture, then compares Nginx and Traefik for Docker-based and traditional deployments.
What Is a Reverse Proxy?
A reverse proxy is a server that receives a request on behalf of another server. The client connects to the proxy, not directly to the backend application. The proxy selects an upstream service, forwards the request, and returns the upstream response to the client.
That is the opposite direction from a forward proxy. A forward proxy represents clients when they access external services; a reverse proxy represents servers when external clients access an application. The Nginx proxy module documentation describes the directives used to pass requests to an upstream HTTP server. Traefik’s official documentation describes the same role in a dynamic, provider-driven architecture.
The basic path is:
browser or API client
|
| HTTPS request to app.example.com
v
reverse proxy :443
|
| route selected from host/path and policy
v
private backend service :8080
The backend can listen on a private interface or container network because it does not need its own public port. A proxy is not automatically an API gateway, load balancer, web application firewall, or identity provider, although it can perform some of those functions when configured with the appropriate features.
Why Does a Reverse Proxy Exist?
Without a reverse proxy, each service needs a distinct public port or address. A home server might expose :3000 for a dashboard, :8080 for an API, and :9000 for an administration tool. Users must remember those ports, TLS certificates need to be managed per application, and every exposed service becomes a separate perimeter.
A reverse proxy consolidates those concerns:
- One ingress point: Several hostnames and paths can share ports 80 and 443.
- TLS centralization: Certificates and HTTP-to-HTTPS redirects can be handled at the edge.
- Routing: The proxy maps
app.example.comor/apito a selected upstream. - Reduced exposure: Databases and application ports can remain private.
- Operational control: Logs, request limits, headers, health checks, and access rules have a common location.
- Deployment flexibility: A backend can move between processes, containers, or hosts without changing the public URL.
Centralization also creates a dependency. If the proxy is down, every route behind it may be unavailable. Configuration errors can affect many applications at once, and the proxy can become a bottleneck if buffering, compression, TLS, or connection handling is poorly sized. It should therefore be treated as production infrastructure rather than as a simple port-forwarding command.
How Reverse Proxy Architecture Works
The request lifecycle
A typical HTTPS request passes through several distinct stages:
- DNS returns the address of the proxy or an upstream firewall.
- The client opens a TCP connection, or a QUIC connection for HTTP/3 where supported.
- The proxy completes the TLS handshake and selects a certificate using the requested hostname.
- The proxy parses the HTTP request and matches a router, server block, or location rule.
- The proxy checks applicable authentication, rate, header, and network policies.
- It opens or reuses a connection to the upstream service.
- The upstream response is streamed or buffered back to the client.
- Access and upstream timing data are written to logs and metrics.
HTTP semantics still matter after the proxy is introduced. RFC 9110 defines methods, status codes, request fields, and response behavior. A proxy should not casually change method meaning, cacheability, authentication behavior, or retry safety.
TLS termination and forwarded identity
Most deployments terminate public TLS at the reverse proxy. The proxy presents the certificate, decrypts the request, and sends it to the backend over a private network. That backend connection may use plain HTTP when the network and trust model justify it, or HTTPS when traffic crosses hosts or the backend requires encryption and peer authentication.
The proxy commonly forwards the original request context with headers such as:
X-Forwarded-For: client-ip, prior-proxy-ip
X-Forwarded-Proto: https
X-Forwarded-Host: app.example.com
Applications must trust these headers only when they were added by a known proxy. If a backend accepts arbitrary client-supplied X-Forwarded-For values, access logs, audit decisions, redirect logic, and IP allowlists can be forged. Configure the framework’s trusted proxy list and overwrite, rather than blindly append to, security-sensitive headers at the boundary.
Routing and upstream selection
Host-based routing selects a service by hostname:
app.example.com -> app:8080
grafana.example.com -> monitoring:3000
Path-based routing uses one hostname with different URL prefixes:
/api/ -> api:8080
/static/ -> frontend:80
Host-based routing is usually simpler because applications can generate URLs from their natural root path. Path-based routing may be useful when DNS names are limited, but an application must understand its external base path. Assets, redirects, cookies, WebSocket endpoints, and absolute URLs often fail when the proxy strips or adds a prefix unexpectedly.
Networks and trust boundaries
In a container deployment, the proxy normally joins an edge network and one or more application networks. Only the proxy publishes host ports; application containers use service-name discovery on their private network. This follows the same service-name and network-boundary model described in Docker Compose networking.
internet
|
host ports 80/443
|
proxy: edge + app networks
| |
v v
frontend api + worker
|
v
database
The database should not need to join the edge network. Network attachment limits reachability, but it is not a replacement for application authentication, database authorization, host firewall rules, or encrypted connections.
Nginx and Traefik Compared
Nginx and Traefik can both terminate TLS and proxy HTTP requests, but they optimize for different configuration and deployment models.
| Feature | Nginx | Traefik |
|---|---|---|
| Primary configuration model | Static configuration files | Static install configuration plus dynamic providers |
| Route discovery | Explicit server and location rules | Docker labels, Kubernetes objects, files, and other providers |
| Best fit | Stable sites, edge tuning, traditional servers | Container and orchestrator environments |
| TLS automation | Usually paired with an ACME client or managed workflow | Built-in ACME certificate resolver |
| Reload behavior | Validate and reload configuration | Watches providers and updates dynamic routes |
| Fine-grained HTTP tuning | Extensive directives and modules | Strong common proxy features with a simpler model |
| Operational trade-off | More manual configuration and reload lifecycle | Provider permissions and discovery behavior need careful control |
Nginx architecture
Nginx uses a deliberately explicit configuration. A minimal host-based proxy might look like this:
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}
In a real HTTPS deployment, add a certificate, a port 443 server, an HTTP-to-HTTPS redirect, timeouts, body-size limits, and an explicit WebSocket strategy where needed. Validate before reloading:
sudo nginx -t
sudo systemctl reload nginx
sudo journalctl -u nginx --since "10 minutes ago"
Nginx is a strong choice when routes change infrequently, an operator wants every behavior visible in version-controlled files, or detailed buffering, caching, compression, and connection controls matter. Its explicitness is an advantage for review, but a container deployment must arrange certificate issuance, configuration rendering, and reloads.
Traefik architecture
Traefik separates static configuration from dynamic routing configuration. Static settings define entry points and providers; a provider discovers routers and services. In Docker, labels can describe a service’s hostname and target port:
services:
app:
image: ghcr.io/example/app:1.0
networks:
- proxy
labels:
- traefik.enable=true
- traefik.http.routers.app.rule=Host(`app.example.com`)
- traefik.http.routers.app.entrypoints=websecure
- traefik.http.routers.app.tls=true
- traefik.http.services.app.loadbalancer.server.port=8080
networks:
proxy:
external: true
This model makes a service portable: its route can be deployed with the service rather than edited in a central file. It also means labels become production configuration and should be reviewed like code. If Traefik watches the Docker socket, restrict that socket with a read-only proxy or a carefully scoped provider where possible. Discovery permissions can reveal container metadata and route an unintended service if labels are copied incorrectly.
Traefik is a useful fit when containers are frequently created, replaced, or scaled and automatic route discovery reduces operational work. A file provider can restore a more explicit model for shared middleware, security headers, or routes that should not live beside application code.
Key Components and Design Choices
Entry points and listeners
An entry point is the address and port where the proxy accepts traffic, commonly :80 and :443. Bind only the interfaces that should receive traffic. A management dashboard should not share an unrestricted public entry point with application traffic.
Routers and upstream services
A router matches a request and applies middleware before selecting an upstream service. An upstream may contain one backend or several endpoints. Health checks can remove an unhealthy endpoint, but they do not prove that the application is correct, authorized, or safe to receive traffic.
Middleware and policy
Middleware can redirect HTTP, add security headers, authenticate users, limit request rates, rewrite paths, compress responses, or handle CORS. Keep policy close to the boundary, but avoid hiding business authorization in proxy rules. The application must still authorize the user and validate the request.
Certificates and renewal
Use an automated certificate workflow where possible, monitor expiry, and test renewal before an outage. HTTP-01 challenges need a reachable HTTP route; DNS-01 challenges need controlled DNS credentials. Store certificate state on durable, restricted storage and back it up according to its sensitivity.
Logs, metrics, and timeouts
Record the hostname, route, status, request duration, upstream duration, and a correlation identifier without logging secrets. Set connect, read, send, and idle timeouts deliberately; unlimited body sizes or read timeouts can exhaust proxy resources.
Real-World Use Cases
For a self-hosted home lab, the proxy can publish a dashboard, media server, and file application through separate hostnames while keeping container ports private. The VLAN and firewall design in home lab network segmentation can place the proxy in a server zone and restrict management access to administrator devices.
For a small production application, the proxy can terminate TLS, route /api to the application, serve static files, and forward health checks. A separate load balancer or CDN may sit in front of it when public availability, DDoS absorption, or geographic distribution requires more capacity.
For a multi-service Compose project, Traefik can discover services as they are deployed. For a stable virtual machine fleet, Nginx can provide an explicit and carefully reviewed edge configuration. In both cases, the architecture should document DNS, certificate ownership, upstream networks, trusted proxy addresses, and recovery steps.
Practical Guide: Deploy a Minimal Docker Proxy
Create a shared network once:
docker network create proxy
docker compose config
docker compose up -d
docker compose ps
docker logs reverse-proxy
A proxy service should publish only its edge ports and attach to the network used by the backend:
services:
reverse-proxy:
image: traefik:v3.5
command:
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --providers.docker=true
- --providers.docker.exposedbydefault=false
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- proxy
networks:
proxy:
external: true
Before exposing a service, verify the complete path:
dig +short app.example.com
curl -I http://app.example.com
curl -vkI https://app.example.com
docker network inspect proxy
docker compose logs --tail=100 reverse-proxy
If DNS is correct but the route returns 404, inspect the hostname, entry point, router rule, and provider discovery logs. If the proxy returns 502 or 504, test name resolution and the application port from the proxy’s network namespace. If TLS fails, inspect certificate storage, challenge reachability, system time, and the requested hostname. If the application redirects repeatedly, compare its external scheme and host settings with the forwarded headers.
Start with one service, one hostname, and a known-good health endpoint. Add authentication, rate limits, headers, and additional routes one change at a time. Back up the configuration and certificate state, and keep a direct recovery path that does not depend on the proxy.
Common Misconceptions
“A reverse proxy is a firewall”
It can reject requests and limit exposure, but it is not a complete network firewall. Use host and network firewall rules to control reachability, then use application authentication and authorization for resource access.
“TLS at the proxy encrypts traffic everywhere”
TLS protects the client-to-proxy connection. If the proxy forwards plain HTTP to a different host or an untrusted network, that second segment is not protected. Decide where encryption and peer authentication are required.
“Automatic discovery means no configuration is needed”
Traefik can discover a container, but labels, networks, entry points, certificates, middleware, and application base URLs still need correct configuration. Automation reduces repetitive edits; it does not remove architecture decisions.
“A 200 response means the service is healthy”
The proxy may return a cached, fallback, or shallow health response while a dependency is failing. Monitor the upstream’s meaningful readiness checks and observe both proxy and application metrics.
Related Articles
- Docker Compose networking explains service-name DNS, private networks, and published ports.
- Home lab network segmentation with VLANs covers the firewall and trust zones around self-hosted services.
- API gateway design patterns distinguishes reverse proxy routing from aggregation and gateway policies.
- Container networking explains namespaces, bridges, overlays, and container packet paths.

