1.Addresses, ports, sockets and the transport underneath
An **IP address** identifies a machine; a **port** identifies which program on it. **DNS** turns a name like `api.example.com` into an address. A **socket** is one end of a connection, identified by the pair of address-and-port on each side. **TCP** delivers a reliable, ordered byte stream and retransmits what is lost; **UDP** just sends packets and makes no promises, which is why DNS uses it and your database does not.
Key features
- A connection is a four-tuple: source IP, source port, destination IP, destination port
- `0.0.0.0:8000` listens on every interface; `127.0.0.1:8000` only on loopback
- A Unix socket is a file — permissions replace firewall rules, and the TCP stack is skipped
- Ports below 1024 need root to bind; nginx binds 80/443, gunicorn never should
- TCP handshakes before data, so connect and read timeouts are separate numbers
- DNS failure is its own failure class — resolution happens before any connection exists
The path the roadmap draws, hop by hop
TCP or UDP — and where each shows up in this stack
- A vertical chain of six boxes showing one request path, each labelled with the address and port it listens on.
- Browser at the top, then a DNS lookup drawn to one side over UDP port 53, whose answer is cached for its TTL.
- Then the load balancer listening on 0.0.0.0 port 443, and nginx listening on 0.0.0.0 ports 80 and 443. These two are inside a shaded band marked "public".
- Below a dividing line marked "the public surface ends here" are gunicorn, bound to the Unix socket file /run/gunicorn.sock, and PostgreSQL and Redis on the private addresses 10.0.1.20 port 5432 and 10.0.1.30 port 6379.
- A note states that binding gunicorn to 0.0.0.0 port 8000 moves it above the line and exposes it directly.
Command
gunicorn config.wsgi --bind unix:/run/gunicorn.sock # not reachable off-box
gunicorn config.wsgi --bind 127.0.0.1:8000 # loopback onlyWalk the path: browser → DNS → load balancer → nginx → gunicorn → Django → PostgreSQL/Redis. Every hop is an address and a port, and the bind address is the security decision — `0.0.0.0` is every interface, `127.0.0.1` is loopback, and a Unix socket is a file whose permissions replace a firewall rule. Keep the application off the public surface so the proxy cannot be bypassed. TCP handshakes and retransmits, which is why connect and read timeouts are separate and why connection reuse is worth so much; UDP promises nothing, which suits DNS and metrics. And treat resolution as its own step, because a DNS failure and a refused connection look identical in a traceback and need opposite fixes.