Education › DevOps › Stage 1: Foundations

Networking essentials

DNS, HTTP, TLS, ports, proxies, and load balancing — enough to debug "it can't connect".

Beginner ~30 min read Module 3 of 17

"It can't connect" is the most common failure you will ever debug, and it hides a dozen different causes: a DNS record that has not propagated, a closed port, an expired certificate, a load balancer sending traffic to a dead instance. This module gives you the layered model and the handful of tools that let you find which one it is in minutes instead of guessing.

After this module you can
  • Trace a request from hostname to response: DNS, TCP, TLS, HTTP
  • Read IP addresses, CIDR ranges and ports, and tell private from public addresses
  • Query DNS with dig and explain record types, TTLs and caching
  • Interpret HTTP status codes and headers, and inspect a TLS certificate from the command line
  • Explain what reverse proxies and load balancers do and how health checks drive them

One request, four steps

When a client calls https://api.example.com/orders, four things happen in order, and each can fail separately.

  1. DNS turns the name api.example.com into an IP address.
  2. TCP opens a connection to that IP on a port (443 for HTTPS).
  3. TLS verifies the server's certificate and sets up encryption.
  4. HTTP sends the request and receives a response with a status code.
1. name to IP2. TCP 3. TLS 4. HTTPHTTP :8000out of rotationSQLDNS resolvercached for the TTLClientbrowser or serviceLoad balancerTLS ends hereApp instancehealthyApp instancehealthyApp instancefailed checkDatabase:5432, private
The four steps behind one HTTPS request: DNS turns the name into an address, then TCP, TLS and HTTP happen against the load balancer, which forwards plain HTTP to whichever backends pass its health checks.

Debugging is walking those steps in order and finding the first one that fails. The error message usually tells you which, if you know how to read it.

What you seeFailing stepTypical cause
Could not resolve hostDNSWrong name, missing record, broken resolver
Connection refusedTCPHost reachable, but nothing is listening on that port
Connection timed outTCPA firewall or security group is silently dropping packets, or wrong IP
certificate has expired / doesn't matchTLSExpired or wrong certificate, missing intermediate
502 / 503 / 504HTTPThe proxy answered, but the backend behind it did not
Tip

Refused and timed out mean different things. Refused is an active answer: the machine is there and rejected you, so look at the service. Timed out is silence: something dropped the packets, so look at firewalls, security groups and routing.

Addresses, CIDR and ports

An IPv4 address is 32 bits written as four numbers, such as 10.0.1.25. CIDR notation describes a range: 10.0.1.0/24 means the first 24 bits are fixed, leaving 8 bits, so 256 addresses. Each step down in the prefix doubles the size: a /23 holds 512, a /16 holds 65,536. 0.0.0.0/0 means every address, which is why it is the dangerous value in a firewall rule.

Three ranges are reserved as private and are never routed on the internet: 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16. Cloud networks and home routers use them internally and reach the internet through NAT, which rewrites the private source address to a public one. 127.0.0.1 (localhost) is the machine itself.

A port identifies which program on the host should receive the traffic. A server listens on a port; a client connects to it. Ports below 1024 need elevated privileges to bind.

PortProtocol
22SSH
53DNS
80HTTP
443HTTPS
5432PostgreSQL
6379Redis
bash
ip addr                      # this machine's interfaces and addresses
ip route                     # routing table; 'default via' is the gateway
ss -tlnp                     # listening TCP ports and the owning process
nc -vz db.internal 5432      # can I open a TCP connection to that port?
ping -c 3 10.0.1.25          # basic reachability (ICMP is often blocked)
Watch out

A service listening on 127.0.0.1:8080 accepts connections only from the same machine. To be reachable from other hosts, or from outside its container, it must listen on 0.0.0.0 or a specific interface address. This is a classic reason a containerised app works locally and is unreachable once deployed.

DNS

DNS is a distributed, cached lookup table. Your machine asks a resolver, which walks the hierarchy (root, then .com, then the authoritative nameservers for example.com) and caches the answer for the record's TTL, in seconds.

RecordMaps
A / AAAAName to IPv4 / IPv6 address
CNAMEName to another name (an alias). Not allowed at the zone apex.
MXDomain to its mail servers
TXTFree text: domain verification, SPF, DKIM
NSZone to its authoritative nameservers
bash
dig api.example.com                  # full answer, including TTL
dig +short api.example.com           # just the addresses
dig api.example.com @1.1.1.1         # ask a specific resolver
dig +trace api.example.com           # walk the hierarchy from the root
dig NS example.com +short            # who is authoritative?
cat /etc/resolv.conf                 # which resolver does this host use?

"DNS propagation" is really cache expiry: after you change a record, resolvers keep serving the old answer until its TTL runs out. Before a planned migration, lower the TTL a day ahead so that the switch takes effect in minutes. If two resolvers disagree, compare them with dig @RESOLVER and query the authoritative server directly to see the truth.

Inside Kubernetes, DNS is how services find each other: a Service named orders in namespace shop resolves as orders.shop.svc.cluster.local.

HTTP

An HTTP request is a method, a path, headers, and an optional body. GET reads and must be safe to repeat; POST creates or triggers; PUT replaces; PATCH modifies; DELETE removes. The response carries a status code, and its first digit tells you whose problem it is.

ClassMeaningExamples
2xxSuccess200 OK, 201 Created, 204 No Content
3xxGo elsewhere301 permanent redirect, 302 temporary, 304 not modified
4xxThe client's request is wrong400 bad request, 401 not authenticated, 403 not allowed, 404 not found, 429 rate limited
5xxThe server side failed500 app error, 502 bad gateway, 503 unavailable, 504 gateway timeout

The three gateway codes matter most in operations. 502 means the proxy reached the backend and got garbage or a reset connection, often a crashed or restarting app. 503 means no healthy backend is available. 504 means the backend did not answer within the proxy's timeout.

bash
curl -i https://api.example.com/health        # include response headers
curl -v https://api.example.com/health        # show DNS, TCP, TLS and headers
curl -sS -o /dev/null -w '%{http_code} %{time_total}s\n' https://api.example.com/
curl -X POST -H 'Content-Type: application/json' -d '{"qty": 2}' \
  https://api.example.com/orders
curl -H 'Host: api.example.com' http://10.0.1.25/health   # hit one backend directly

TLS

TLS gives you encryption and, just as important, identity. The server presents a certificate that binds its hostname to a public key and is signed by a certificate authority (CA). The client checks three things: the signature chains up to a CA it trusts, the current date is inside the validity period, and the hostname it asked for appears in the certificate's Subject Alternative Names.

Failures map directly onto those checks: an expired certificate, a hostname mismatch, or a server that forgot to send its intermediate certificate, in which case browsers may cope but curl and application clients reject it. SNI lets one IP address serve certificates for many hostnames, because the client names the host it wants at the start of the handshake.

bash
# show the certificate chain the server actually sends
openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null

# just the validity dates and the names it covers
openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null \
  2>/dev/null | openssl x509 -noout -dates -subject -ext subjectAltName
Watch out

curl -k and "verify: false" turn off the identity check and leave you open to interception. Use them to confirm a diagnosis, never as the fix. Expired certificates are a preventable outage: automate renewal and alert on days-to-expiry.

Proxies and load balancers

A reverse proxy (NGINX, HAProxy, Envoy, a cloud load balancer, a Kubernetes Ingress controller) sits in front of your application. It terminates TLS, routes by hostname and path, and spreads requests over several backends. A forward proxy is the opposite: it sits in front of clients and makes outbound requests for them.

  • A layer 4 balancer forwards TCP connections and knows nothing about HTTP. A layer 7 balancer understands HTTP, so it can route on path or header, retry, and add headers.
  • Health checks decide which backends receive traffic. The balancer probes each one on an interval and removes those that fail. A missing or wrong health-check path is a common reason for a 503 with perfectly healthy apps.
  • Behind a proxy your app sees the proxy's IP as the client. The real address arrives in the X-Forwarded-For header, and the original scheme in X-Forwarded-Proto.
  • Timeouts exist at every hop. If the proxy's timeout is shorter than the app's slowest request, users get a 504 while the app finishes work nobody is waiting for.

When a request through the balancer fails, take it out of the picture: curl a backend directly, as in the Host header example above. If the backend answers, the problem is the balancer's configuration, health check or firewall rules, not your application.

Hands-on practice

Walk the four steps by hand

  1. Pick any public HTTPS site. Resolve it with dig +short, then run dig +trace and identify its authoritative nameservers and the TTL of its A record.
  2. Run curl -v against it and mark in the output where DNS, TCP connect, the TLS handshake and the HTTP response each appear.
  3. Use the openssl s_client pipeline to print the certificate's expiry date and Subject Alternative Names. Work out how many days remain.
  4. Start a local server with python3 -m http.server 8080 --bind 127.0.0.1. Confirm with ss -tlnp what it listens on, and explain why another machine could not reach it. Restart it bound to 0.0.0.0 and compare.
  5. Produce a refused connection and a timeout on purpose: nc -vz localhost 9999 for the first, and nc -vz -w 5 10.255.255.1 80 for the second. Note how differently they behave.
  6. Write down the size of 10.0.0.0/16, 10.0.4.0/22 and 10.0.4.0/28, then check yourself: a /N network holds 2^(32-N) addresses.
Cheat sheet

Networking essentials — at a glance

Main things to focus on

  • Debug in order: DNS, then TCP, then TLS, then HTTP. Find the first step that fails.
  • Refused means nothing is listening. Timed out means something is dropping packets.
  • A /N network has 2^(32-N) addresses; 0.0.0.0/0 is everyone. Know the three private ranges.
  • Listening on 127.0.0.1 is local only; listen on 0.0.0.0 to be reachable.
  • DNS changes take effect when cached TTLs expire. Lower the TTL before a migration.
  • 4xx is the client's fault, 5xx is the server side. 502 bad response, 503 no healthy backend, 504 backend too slow.
  • TLS validates chain, dates and hostname. Never ship with verification disabled.

Is it reachable?

ip addr / ip routeLocal addresses and routing table
ss -tlnpListening TCP ports with owning process
nc -vz HOST PORTTest a TCP connection without sending data
ping -c 3 HOSTICMP reachability (often blocked; failure proves little)
traceroute HOSTThe hops between you and the host

DNS

dig +short NAMEResolve a name to addresses
dig NAME @RESOLVERAsk one specific resolver
dig +trace NAMEFollow delegation from the root
dig TYPE NAMEQuery a record type: A, AAAA, CNAME, MX, TXT, NS
dig -x IPReverse lookup
cat /etc/resolv.confWhich resolver this host uses

HTTP with curl

curl -i URLShow response headers and body
curl -v URLVerbose: connection, TLS and headers
curl -L URLFollow redirects
curl -H 'Name: value' URLSend a request header
curl -X POST -d 'BODY' URLSend a request body
curl -o /dev/null -s -w '%{http_code}' URLPrint only the status code
curl --resolve HOST:443:IP https://HOST/Force a hostname to one IP, keeping TLS valid

TLS

openssl s_client -connect HOST:443 -servername HOSTShow the handshake and certificate chain
openssl x509 -noout -datesValidity period of a certificate on stdin
openssl x509 -noout -ext subjectAltNameHostnames the certificate covers
openssl x509 -in cert.pem -noout -textDecode a certificate file in full

Numbers worth knowing

10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16Private IPv4 ranges
/24 = 256, /16 = 65,536Addresses in common prefix sizes
22, 53, 80, 443SSH, DNS, HTTP, HTTPS
401 vs 403Not authenticated vs authenticated but not allowed
502 / 503 / 504Bad backend response / no healthy backend / backend timeout

Common pitfalls

  • Binding a service to 127.0.0.1 inside a container and wondering why nothing can reach it.
  • Opening a firewall rule to 0.0.0.0/0 for a database or SSH port "just to test".
  • Changing a DNS record with a long TTL and expecting the change to be instant.
  • Fixing a certificate error with curl -k or verify=false and leaving it in the code.
  • Blaming the application for a 503 when the load balancer's health-check path is wrong.
  • Treating a failed ping as proof that a host is down, when ICMP is simply blocked.
Quiz

Check your understanding

5 questions · 4 to pass · answers are explained as you go. Your best score is saved on this device only.

Progress and quiz scores are saved in this browser only. Back up or restore on the hub.

Was this lesson useful? Tell me what to improve →