The labs on this site need JavaScript to run. The same content is written out below.
Fundamentals › Networking
What is a proxy server, and what changes when it sits in between?
A proxy server is a server that stands between a client (the program that sends requests) and the origin server (the server that really produces the response) and passes requests on for it. The code box lists three things. First, the address the client connects to (http://localhost:8080/hello). The 8080 in the middle of the address is a port number, a door number given to each program on one computer. Second, the proxy server waiting on port 8080, which passes the request it receives to the server on 9000. Third, the origin server waiting on port 9000, which returns "Hello". So the client connects to the proxy server, and the proxy server connects again to the origin server, passes the request on, and returns the response. The proxy server in this lab stands in front of the server, and the client connects to it believing it is the server (a reverse proxy). In this lab, you change the address the client connects to, or remove the line of the proxy server or the origin server (that server is not running), send the same request each time, and see what the client receives and who the origin server sees. The code box is not the source of a program that was run. It lists what is waiting on which port, and 8080 and 9000 are example numbers. Load balancers, CDNs, and API gateways are also servers that stand between a client and a server.
Checked against real execution · Ran six combinations with two Node.js 24.18.0 http servers (a proxy server and an origin server) and an http client, and checked them
# The address the client connects to http://localhost:8080/hello # On 8080: the proxy server (passes the request it receives to the server on 9000) # On 9000: the origin server (returns "Hello")
We ran all six combinations for real, only inside 127.0.0.1 on the PC used to write this lab, and checked them against the model. We did not connect to any external network. The origin server and the proxy server are Node.js 24.18.0 http servers, and the client is http.request of the same Node.js (it does not reuse connections). The origin server answers GET /hello with 200 and the text written in the code box, "Hello", and it recorded the port of the peer that connected to it. The proxy server opened a new connection to the server whose port is written in the code box, passed the request it received on as it was, returned the response to the client, and recorded its own port used on that connection. The test program built the same text as the code on the screen, read it (which port has what written on it), and showed it as it was. A server whose line was removed was not started, and connecting to its port meant trying to connect to a free port that nothing was waiting on (a port that had just been closed). 8080 and 9000 on the screen are example numbers and free ports were used in the real run, and the code box is not the source of the programs that were run but a list of what is waiting on which port. What we checked against is what the client received (the status code and body, or the kind of error), who the origin server saw, and the path the request took; who the origin server saw was decided by comparing whether the peer port the server recorded was the same as the client's port or the same as the port the proxy server used when connecting to the server. The three programs were on one computer, so the peer address the server saw was 127.0.0.1 in every combination, and that is why we told them apart by port. In the combinations that went through the proxy server, the only peer that connected to the origin server was one (the proxy server), and in the combinations that connected directly, the proxy server received 0 requests. When nothing was waiting on 8080 (or 9000), the client received a connection refused error (ECONNREFUSED), and when the origin server was down and the request went through the proxy server, the proxy server got the same connection refused error and then returned 502. This 502 is a behavior that comes from how the proxy server of this lab was written, and we did not check what real proxy products return when they cannot connect. What we checked against the documentation is section 3.6 of RFC 9110 (an origin server is a program that can originate authoritative responses for a given target resource), section 3.7 (among intermediaries, a proxy is one that the client chooses by its configuration, and a gateway, also called a reverse proxy, acts as an origin server for the outbound connection and passes the requests it receives on to the inbound server), and section 15.6.3 (502 is the code used when a server acting as a gateway or proxy receives an invalid response from an inbound server). For section 15.6.3, we confirmed the first sentence word for word and the rest from a summary. The proxy server in this lab is the kind the client connects to believing it is the server, so in RFC terms it is closer to a gateway (reverse proxy), and we did not cover the difference from a forward proxy that the client chooses on purpose. We did not examine whether using 502 when the connection itself is refused fits the RFC sentence exactly. The sentence that load balancers, CDNs, and API gateways are also servers that stand between a client and a server is a general explanation, and it was not checked by this run or by the documentation. This lab leaves out many things. We did not look at headers such as X-Forwarded-For that pass the original client's address to the server, a setup that decrypts HTTPS at the proxy server, timeouts and 504 for slow responses, splitting requests among several servers, and keeping copies of responses. The first two are covered in the in-depth lab "Proxies and reverse proxies", splitting among servers in the in-depth lab "Load balancers and scale out", and keeping copies of responses in the in-depth lab "CDN". We did not use a browser, and we sent only one request, GET /hello.
Previous lab: HTTPS · Next lab: Authentication and authorization
Struck-through text was removed from the first version of the code; highlighted text was added.