# Networking Fundamentals: The Guide for Developers

URL: https://www.devopsness.com/blog/networking-fundamentals-guide
Author: Kiril Urbonas
Published: 2026-08-07
Updated: 2026-10-31
Categories: Infrastructure
Tags: Networking, DNS, TCP, TLS, Infrastructure

Summary: You don't need a CCNA to ship reliable services, but you do need the core ideas. This is the map: DNS, TCP, TLS, proxies, and CDNs, minus the jargon.

---
# Networking Fundamentals: The Guide for Developers

Networking for developers comes down to one pipeline: resolve the name (DNS), open a connection (TCP), secure it (TLS), route it (proxy or load balancer), then serve it (origin or CDN). Most "mysterious" bugs live in one stage: a slow first request is DNS, a hang is a firewall, a certificate warning is TLS, a 502 is a proxy.

> [!VERIFIED]
> curl 8.23.0 and OpenSSL 4.1.0, against the curl man page, the OpenSSL `s_client` docs, RFC 9293 (TCP) and RFC 9846 (TLS 1.3, published July 2026, obsoleting RFC 8446). Checked October 2026.

## One command that shows the whole pipeline

Before reading about each layer, look at all of them at once. `curl -w` prints how long each stage took:

```
$ curl -s -o /dev/null https://example.com -w \
  'dns=%{time_namelookup} tcp=%{time_connect} tls=%{time_appconnect} ttfb=%{time_starttransfer} total=%{time_total}\n'
dns=0.012 tcp=0.031 tls=0.068 ttfb=0.142 total=0.143
```

The numbers (an illustrative run) are cumulative seconds since the start, so subtract neighbours: here DNS took 12 ms, the TCP handshake 19 ms, TLS 37 ms, and the server spent 74 ms before the first byte. If `dns` is large, look at resolvers. If `ttfb` dominates, the network is fine and the app is slow. That one line ends a lot of arguments.

## Names: DNS

Before anything connects, the name has to become an IP address. Resolvers cache answers for the record's TTL, which is why a changed record can take minutes or hours to reach everyone. [How DNS works](/blog/how-dns-works) covers the lookup chain; ask the resolver directly with `dig`:

```
$ dig +noall +answer +comments api.example.com A
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4127
api.example.com.   300   IN   A   203.0.113.10
$ dig @1.1.1.1 api.example.com A +short
203.0.113.10
```

`status: NXDOMAIN` means the name doesn't exist; `SERVFAIL` means the resolver couldn't get an answer, often a DNSSEC or upstream failure. Comparing your default resolver with a public one tells you whether the problem is local. On Linux hosts, [DNS troubleshooting with resolvectl and dig](/blog/dns-troubleshooting-linux) goes further.

## Connections: TCP and UDP

TCP, specified in RFC 9293, is reliable and ordered: a three-way handshake, retransmission, flow control. It carries the web, APIs and databases. UDP sends datagrams with no handshake or delivery guarantee, which suits DNS, video, games and QUIC, the transport under HTTP/3. Which to pick is in [TCP vs UDP](/blog/tcp-vs-udp).

Two connection failures look alike but mean different things. **Connection refused** is fast: the host answered with a reset because nothing listens on that port. **Timed out** is slow: packets vanish, almost always a firewall or security group dropping them. Check what is actually listening:

```
$ ss -ltnp
State   Recv-Q  Send-Q  Local Address:Port  Peer Address:Port  Process
LISTEN  0       4096        127.0.0.1:8080       0.0.0.0:*     users:(("app",pid=812,fd=7))
```

An app bound to `127.0.0.1` is reachable only from the same machine, which is the most common "works locally, refused remotely" cause. Bind to `0.0.0.0` (or the right interface) and check the host firewall; [iptables vs nftables](/blog/iptables-vs-nftables-linux-firewall-guide) explains which one your distro uses. For CIDR maths on security groups and subnets, the [CIDR and subnet calculator](/tools/cidr-subnet-calculator) shows the network, broadcast, mask and usable hosts for any block.

## Security: the TLS handshake

The padlock is a negotiation. Client and server agree on keys and the client verifies the certificate chain and hostname before any application data flows. TLS 1.3 does this in one round trip. The step-by-step is in [how the TLS handshake works](/blog/tls-handshake-explained), which pairs with the response-side controls in [HTTP security headers](/blog/security-headers-guide). Inspect what a server actually presents:

```
$ openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
    | openssl x509 -noout -subject -issuer -dates
subject=CN=example.com
issuer=C=US, O=Let's Encrypt, CN=R11
notBefore=Oct  1 00:00:00 2026 GMT
notAfter=Dec 30 23:59:59 2026 GMT
```

`-servername` sends SNI. Leave it off and a server hosting many sites may return its default certificate, which then "doesn't match" and sends you chasing the wrong problem.

## Getting to the app: proxies and load balancing

Real traffic rarely hits your app directly. A **reverse proxy** terminates TLS, routes and buffers, set up in [how to set up an Nginx reverse proxy](/blog/nginx-reverse-proxy-guide). A **load balancer** spreads requests across backends using an algorithm, compared in [load balancing algorithms explained](/blog/load-balancing-algorithms). The three terms are untangled in [proxy vs reverse proxy vs load balancer](/blog/proxy-vs-reverse-proxy-vs-load-balancer).

The status code tells you which side failed. A **502 Bad Gateway** means the proxy reached out and got garbage or a refused connection from the backend. A **504 Gateway Timeout** means the backend accepted but didn't answer before the proxy's timeout. In both cases the proxy works and the backend doesn't; on Kubernetes, [fixing ingress 502 and 504 errors](/blog/fix-ingress-502-504) walks the checks.

## Speed at the edge: CDNs

A **CDN** serves cached copies from locations near the user, cutting latency and origin load. [What is a CDN](/blog/what-is-a-cdn) covers the model; [CDN cache invalidation strategies](/blog/cdn-cache-invalidation-strategies) covers keeping it fresh. When users see stale content, compare response headers such as `Age` and `Cache-Control` between the CDN hostname and the origin with `curl -sI`.

## The error strings, by layer

| Error you see | Layer | Usual cause | First check |
|---|---|---|---|
| `curl: (6) Could not resolve host` | DNS | Typo, missing record, broken resolver | `dig name +short` against two resolvers |
| `curl: (7) Failed to connect ... Connection refused` | TCP | Nothing listening, or bound to localhost | `ss -ltnp` on the server |
| `curl: (28) Connection timed out` | TCP / firewall | Security group or firewall dropping packets | Rules for that port and source CIDR |
| `curl: (60) SSL certificate problem: unable to get local issuer certificate` | TLS | Server omits intermediate cert, or private CA | `openssl s_client -showcerts` |
| `502 Bad Gateway` / `504 Gateway Timeout` | Proxy / backend | Backend down, wrong port, too slow | Proxy error log, backend health |

## Where this breaks

The pipeline model assumes a plain client-to-server path. Corporate proxies, VPNs and service meshes add hops that terminate TLS or rewrite DNS, so `curl` from your laptop and from inside the cluster can disagree; always test from where the failing client runs. HTTP/3 runs over QUIC on UDP, so TCP tools like `ss -t` won't show those connections. And `curl -w` timings are a single sample: measure several times before blaming a layer.

## Questions people ask

### What networking concepts should every developer know?

Know the request pipeline and which layer owns each symptom: DNS turns names into addresses, TCP or UDP carries the bytes, TLS encrypts and authenticates, reverse proxies and load balancers route, and CDNs cache at the edge. Add CIDR notation for reading firewall rules, and four tools: `dig`, `curl -v`, `ss` and `openssl s_client`. That covers most production debugging.

### What is the difference between connection refused and connection timed out?

Connection refused arrives immediately: the host is reachable but nothing listens on that port, or the service only listens on 127.0.0.1, so the kernel replies with a reset. Connection timed out takes seconds: packets are silently dropped, usually by a firewall, security group or wrong route. Refused points at the service; timed out points at the network path.

### How do I find which layer is slowing down a request?

Run `curl -s -o /dev/null -w` with `time_namelookup`, `time_connect`, `time_appconnect`, `time_starttransfer` and `time_total`. Each is cumulative, so subtract consecutive values to get DNS, TCP handshake, TLS handshake and server think time. A large DNS gap points to resolvers; a large first-byte gap means the network is fine and the application is slow.

## The call we'd make

Learn the request path once and networking stops being magic. You don't need every RFC; you need to know which layer owns which symptom and which command inspects it. Start with DNS and TLS, the two behind most "it's slow" and "it's broken" reports, keep the `curl -w` one-liner in your shell history, then go deeper on proxies and CDNs as traffic grows. Read the linked guides in request-path order and the whole stack clicks into place.

## Sources

- [curl man page (write-out variables and exit codes)](https://curl.se/docs/manpage.html)
- [OpenSSL documentation: openssl-s_client](https://docs.openssl.org/3.5/man1/openssl-s_client/)
- [RFC 9293: Transmission Control Protocol (TCP)](https://www.rfc-editor.org/info/rfc9293/)
- [RFC 9846: The Transport Layer Security (TLS) Protocol Version 1.3](https://www.rfc-editor.org/info/rfc9846/)

