You type a web address and something answers. Often, it isn’t the server that holds the site.
What is a reverse proxy? A server that stands in front of your web servers, hands each visitor’s request to the right one and sends the answer back. A forward proxy is the mirror image: it sits in front of the people browsing.
We ran nginx in front of three test apps to see what changes.
Most of it helps. One part quietly breaks your visitor logs.
What is a reverse proxy, in plain English?
A reverse proxy is a front desk for servers. Visitors only ever talk to the desk, and the desk decides which room handles each request.
Think of a hotel. You don’t wander the corridors for housekeeping. You ask reception, and you never learn which room the answer came from.
That’s the whole trick. Your browser connects to the proxy. The proxy opens its own connection to a server behind it, called the origin or backend, and relays the reply.
Our guide to proxy servers covers the general idea. This post is about the kind that works for websites, not for the people browsing them.
Forward proxy vs reverse proxy: whose side is it on?
The difference is who the proxy works for. A forward proxy works for the people sending requests. A reverse proxy works for the servers receiving them.

| Forward proxy | Reverse proxy | |
|---|---|---|
| Sits in front of | Clients (your laptop, a scraper, an office network) | Servers (a website, an API, an app) |
| Who sets it up | The user or their company | The site owner or their host |
| What it hides | Who is asking | Who is answering |
| Does the other side know? | The website sees the proxy’s IP, not yours | The visitor sees the proxy’s IP, not the origin’s |
| Typical examples | Residential proxies, a school web filter, Squid | Nginx, HAProxy, Caddy, Cloudflare, a CDN |
The proxies you buy for scraping or managing accounts are forward proxies. Our HTTP vs SOCKS5 proxies guide covers that side.
The quick test: who installed it? If you did, on your device, it’s forward. If the website did, on its servers, it’s reverse.
How we tested it (and what we didn’t)
On 10 November 2026 we built a small lab on our Linux test box and pushed real requests through it.
- The proxy: nginx 1.26.3, listening on port 8080 for plain HTTP and 8443 for HTTPS.
- The servers behind it: three tiny Python apps called app-1, app-2 and app-3. Each one reports which app answered and what it saw about the visitor.
- The visitor: curl, sending from its own local address (127.0.0.5) so we could tell it apart from the proxy.
It all ran on one machine, so timings are best-case. We didn’t test HAProxy, Caddy, Traefik, Cloudflare or Kubernetes; what we say about them comes from their docs.
upstream app {
server 127.0.0.1:9001;
server 127.0.0.1:9002;
server 127.0.0.1:9003;
}
server {
listen 8080;
server_name shop.test;
location / {
proxy_pass http://app;
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;
}
}
That’s the core of the config. upstream lists the servers and proxy_pass sends requests to them. The four proxy_set_header lines matter more than they look; we’ll get to why.
What a reverse proxy does for the servers behind it
A reverse proxy does four main jobs: it spreads traffic, handles HTTPS, caches pages and shields the origin. Most sites use two or three at once.

Load balancing
Load balancing means sharing visitors across several servers so no single one drowns. By default nginx takes turns down the list, which is called round robin.
We sent 30 requests. App-1 answered 10, app-2 answered 11 and app-3 answered 9.
Then we gave app-1 a weight of 3, as you would for a bigger server. It took 18 of the next 30, and the other two took 6 each. Exactly 3:1:1.
The better trick is what happens when a server dies. We put a dead address in the pool next to two live apps and sent 12 requests. All 12 came back fine. Nginx logged one “Connection refused”, retried the next server and stopped sending traffic to the dead one.
Real-world tip: one crashed server behind a proxy often goes unnoticed. When every server is down, you get a 502 instead. Our 502 Bad Gateway fix guide walks through those failures one by one.
TLS termination
TLS termination means the proxy handles HTTPS, so the apps behind it don’t have to. The certificate and the encryption live in one place.
Our curl connected to port 8443 over TLS 1.3. The app behind it received plain HTTP, plus one header from nginx: X-Forwarded-Proto: https.
That header tells your app the visitor was on HTTPS. Skip it, and WordPress can treat every visit as insecure and redirect forever. You’ve probably seen that loop: “too many redirects”.
The trade-off? Traffic between the proxy and your apps travels unencrypted unless you add HTTPS on that leg too. Fine on one machine or a private network. Not fine across the open internet.
Caching
Caching means the proxy keeps a copy of a page and serves it without asking the app again. It’s where the biggest speed gains hide.
We made one page slow on purpose: the app waited 500 milliseconds, like a heavy database query. Then we turned on nginx’s cache and asked for it five times.
| Request | Cache status | Time |
|---|---|---|
| 1st | MISS (asked the app) | 503 ms |
| 2nd | HIT (served from nginx) | 0.31 ms |
| 3rd | HIT | 0.27 ms |
| 4th | HIT | 0.48 ms |
| 5th | HIT | 0.67 ms |
The first visitor waited half a second. Everyone after got the page in under a millisecond, and all five carried the same timestamp: one copy, served five times.
The same layer compresses pages on the way out. We pushed a saved copy of one of our own articles through it with gzip on. In went 321,565 bytes; out came 86,155. That’s 73% less to download.
A WordPress page cache works the same way. Our WordPress speed tests measured it on DroidCrunch itself.
Protection
A reverse proxy protects the origin by being the only thing the internet can reach. Attackers see the proxy’s address, software and rules. Not yours.
We saw it in the headers. Asked directly, our app announced itself as BaseHTTP/0.6 Python/3.13.5. Through the proxy, visitors only saw nginx/1.26.3.
A proxy can also say no. We allowed 5 requests a second per visitor, plus a small burst, then fired 20 at once. Six got through. The other 14 got 429 Too Many Requests, and the app never saw them.
Cloudflare does this at scale, blocking junk before it reaches your hosting bill.
What does your server actually see? The IP address catch
Behind a reverse proxy, your app sees the proxy as the visitor. Every request comes from the same address unless the proxy passes the real one along.
Here’s what our app reported for one visitor, at 127.0.0.5, in four setups.
| Setup | IP the app saw | Forwarded headers |
|---|---|---|
| Visitor talks to the app directly | 127.0.0.5 (correct) | None |
| Through nginx, no extra headers | 127.0.0.1 (the proxy) | None |
| Through nginx, headers set | 127.0.0.1 (the proxy) | X-Forwarded-For: 127.0.0.5 |
| Same, but visitor fakes the header | 127.0.0.1 (the proxy) | X-Forwarded-For: 203.0.113.9, 127.0.0.5 |
Row two is the trap. Without those header lines, your stats, spam filter and login lockouts all see one IP.
Lock that IP out after five bad passwords, and you’ve locked out everyone.
Row four is the sneaky one. Our visitor sent a made-up X-Forwarded-For header, and nginx kept it, adding the real address at the end. An app that trusts the first address believes the lie.
The fix: trust only the address your own proxy added, the last one. In nginx, the real_ip settings do this when they list only your proxy’s addresses. Our X-Real-IP header held the true address every time.
Common mistake: putting WordPress behind Cloudflare and forgetting this step. Comments, security logs and login limits then show Cloudflare’s addresses. Most WordPress security plugins have a setting for which header to read; Cloudflare’s own is CF-Connecting-IP.
Reverse proxy vs load balancer vs API gateway
They overlap. A load balancer is a reverse proxy whose main job is spreading traffic. An API gateway is a reverse proxy for APIs, with keys and usage limits on top.
| Reverse proxy | Load balancer | API gateway | |
|---|---|---|---|
| Main job | Stand in front of servers | Spread traffic, survive failures | Control who calls your API, and how often |
| Typical extras | HTTPS, caching, compression | Health checks, sticky sessions | API keys, per-customer limits, request rewriting |
| Examples | Nginx, Caddy | HAProxy, AWS load balancers | Kong, AWS API Gateway |
Our one nginx file did a little of all three. Our take: don’t shop for three products. Start with one reverse proxy, and split a job out only when it outgrows it.
Reverse proxies you’ve already used without noticing
Most big websites answer through one, so you’ve used dozens today.
- Nginx. The usual choice on a Linux server, and the one we tested. Web server and reverse proxy in one.
- HAProxy. Built for load balancing at high traffic. Pick it when health checks and failover are the main job.
- Caddy. The easiest start. One line,
reverse_proxy localhost:3000, and it fetches HTTPS certificates for you. - Traefik. Made for containers. It watches Docker or Kubernetes and adds routes as apps appear.
- Cloudflare and other CDNs. A reverse proxy spread across hundreds of cities, so visitors hit one nearby.
- Kubernetes ingress. The reverse proxy at the edge of a cluster that sends traffic to the right service.
That last one has news. The popular Ingress NGINX controller was retired on 24 March 2026, so it gets no more security fixes. Kubernetes now points people to its Gateway API instead.
Want to see one live? This page reached you through two. On 10 November 2026, DroidCrunch’s pages answered with server: cloudflare. Its images came from a BunnyCDN host.
The downsides nobody draws on the diagram
Every reverse proxy adds a box that can fail, a hop that costs time and settings you now own.
- A single point of failure. We stopped nginx while all three apps kept running. Visitors got “connection refused” from healthy apps nobody could reach. Big setups run two proxies for this reason.
- An extra hop. Over 500 fresh connections, nginx added 0.18 ms to the median request (0.41 ms direct, 0.59 ms proxied). Tiny on one machine. Across a network, add the distance to your servers.
- The wrong IP. The trap above, and the most common setup mistake.
- The wrong page, cached. Cache a page showing a logged-in user’s name, and the next visitor sees it. Never cache carts, checkouts or account pages.
- Timeouts in a new place. The proxy has its own limits, so a slow app can get cut off with a 504. Our 504 Gateway Timeout guide shows which setting to raise.
None of these is a reason to skip one. They’re your day-one checklist.
Do you need a reverse proxy?
If you run anything bigger than one small app, yes. On managed hosting or a CDN, you probably have one already.
- WordPress on shared hosting. You can’t install nginx there, and you don’t need to. Put a CDN like Cloudflare in front and set your security plugin to read the real visitor IP. On Hostinger shared plans, that’s the realistic route.
- Managed WordPress hosting. The host runs the caching and proxy layer for you. On Pressable it’s part of the platform, with nothing to configure. If the layers confuse you, start with how web hosting works.
- Your own VPS with one app. Put nginx or Caddy in front anyway for free HTTPS, compression and a cache, while your app stays on a private port. A small DigitalOcean droplet is enough.
- Several apps or containers on one server. A reverse proxy lets them all share ports 80 and 443. Traefik or Caddy make this painless.
- More traffic than one server can take. Now you need load balancing. Start with nginx; move to HAProxy or your cloud’s load balancer when failover gets serious.
Disclosure: we may earn from the hosting links above, and you pay the same price. Nginx, Caddy, HAProxy and Traefik are free and open source.
Frequently asked questions
What is a reverse proxy in a Docker setup?
It’s one container that owns ports 80 and 443 and sends each domain to the right app container. Traefik reads labels on each container. So a new app gets its route and HTTPS certificate without anyone editing a config file.
Is Cloudflare’s grey cloud a reverse proxy too?
No. In Cloudflare’s DNS settings, an orange cloud means traffic flows through Cloudflare’s reverse proxy. A grey cloud means DNS only. Visitors connect straight to your server, with no caching or firewall, and anyone who looks up the domain sees your real server IP.
Does a reverse proxy completely hide my server’s IP?
Only if nothing else leaks it. Old DNS records, an unproxied subdomain such as mail, and emails sent from the server can all reveal the origin. Lock your server’s firewall so it accepts web traffic only from your proxy’s IP ranges.
Can a reverse proxy see my passwords?
Yes, when it handles HTTPS. TLS ends at the proxy, so it reads requests in plain text before passing them on. That’s fine when it’s your own server. With a CDN, you’re trusting that company with everything visitors type into your site.
Do WebSockets work through a reverse proxy?
Yes, but nginx needs telling. Add proxy_http_version 1.1 and pass the Upgrade and Connection headers in that location block. Without them, live chat, dashboards and other real-time features connect and then drop, or never connect at all.
Which ports does a reverse proxy use?
The public side listens on 80 for HTTP and 443 for HTTPS. The apps behind it run on any spare internal port, like 3000, 8000 or 8080. Close those internal ports to the outside world, so the proxy stays the only way in.
Can attackers use a reverse proxy for phishing?
Yes. Phishing kits like Evilginx sit as a reverse proxy in front of a real login page. You see the genuine site, log in, approve your 2FA prompt, and the attacker copies your session cookie on the way through. Passkeys and security keys resist this.
Is nginx a web server or a reverse proxy?
Both, in the same program. It can serve files from disk, pass requests to an app, or do both on one site. Many WordPress servers use nginx for images and CSS and hand PHP pages to PHP-FPM.
The bottom line
So, what is a reverse proxy? The front desk for your servers. It shares out the work, handles HTTPS, serves cached pages in under a millisecond and keeps the origin out of sight. A forward proxy is its mirror image, working for the people browsing instead.
On shared WordPress hosting, a CDN like Cloudflare is your reverse proxy. On a VPS, put nginx or Caddy in front. Either way, set up the real-visitor-IP header on day one, or your logs and lockouts will blame one address for everything.
Next step: run curl -sI against your own site and read the server line. You might find a proxy you didn’t know you had.



