Module 10: Networking Basics
🎯 Goal: Diagnose how a client reaches a service: name, address, route, port, protocol, and process.
By the end of this module, you should be able to distinguish an IP address from a port and hostname, test DNS and HTTP separately, identify local listening sockets, and reason about the WSL-to-Windows boundary without treating networking as magic.
Why this matters
Almost nothing you'll do next in this curriculum - pulling Docker images, exposing container ports, reaching services inside a Kubernetes cluster, or hitting an AKS endpoint - makes sense without a working mental model of IP addresses, ports, and DNS. WSL2 also has its own private network identity separate from Windows, which trips up nearly every beginner the first time they try to reach a service running inside it. Getting comfortable with ip, curl, ss, and dig now means you'll actually understand why a container's port mapping works instead of just memorizing the syntax later.
Concepts
Debug one layer at a time
For a connection failure, do not jump straight to changing firewall rules. First confirm the service is running and listening on the expected address and port; then test locally; then verify DNS, routing, and network policy. curl, ss, ip, and dig answer different questions. A focused check makes a network problem explainable and prevents broad, unsafe workarounds.
IP addresses identify a machine on a network. Just as a postal address identifies a building, an IP address (like 192.168.1.15 or 172.20.10.2) identifies a device on a network so traffic knows where to go. Your WSL2 Ubuntu instance has its own IP address, separate from your Windows host's IP address, because WSL2 runs as a lightweight virtual machine with its own virtual network adapter.
Ports identify a specific service on that machine. An IP address gets you to the right building; a port number gets you to the right door. A single machine can run many services at once (a web server, a database, an SSH daemon), each listening on a different port number - port 80 for HTTP, 443 for HTTPS, 22 for SSH, by long-standing convention, though any program can choose any free port.
https://google.com/search
│ │ │
│ │ └── path: which resource on that service
│ └── hostname → resolved via DNS to an IP address
└── protocol: HTTPS (TCP under the hood), implies port 443 by convention
Full picture for one request:
hostname → DNS lookup → IP address → : port → protocol conversation
google.com (dig) 142.250... 443 TLS + HTTP
Protocols are the agreed "rules of conversation." TCP and UDP are the two most common transport protocols. TCP is connection-oriented and reliable (used by HTTP, SSH, most everyday traffic) - it guarantees delivery and order. UDP is connectionless and faster but doesn't guarantee delivery - used for things like DNS queries and video streaming where occasional loss is tolerable.
Routing decides which path traffic takes. When your machine sends a packet destined for an address outside its local network, it needs to know which "next hop" to send it to - this is the routing table, and the default route is essentially "if you don't know a more specific path, send it here" (usually your router/gateway).
DNS translates names into addresses. You type google.com, not an IP address, because DNS (Domain Name System) is a distributed lookup service that translates human-readable names into IP addresses. Your machine also has a local override file, /etc/hosts, that's checked before DNS is consulted - useful for testing or for pointing a hostname at a specific IP without touching real DNS.
WSL2 networking is a virtual machine behind the scenes. WSL2 runs Linux inside a lightweight, real virtual machine (unlike WSL1, which translated Linux syscalls directly on Windows). That means WSL2 gets its own virtual network adapter and its own IP address, distinct from Windows' IP address. Microsoft added "localhost forwarding" so that, in most default configurations, a service listening on localhost/127.0.0.1 inside WSL2 is also reachable at localhost from Windows (and vice versa) - but this forwarding is a convenience layer, not literally the same network stack, and it can behave differently depending on Windows version, WSL version, and firewall/VPN software. Understanding that WSL2 has its own IP is the key to debugging when localhost forwarding doesn't behave as expected.
┌─────────────────────────┐ ┌─────────────────────────┐
│ Windows host │ │ WSL2 (own lightweight │
│ its own IP on your │◄───────►│ VM, own virtual NIC, │
│ physical/Wi-Fi network │ vEthernet│ own IP - e.g. 172.x.x.x)│
│ │ (WSL) │ │
│ ipconfig → "vEthernet │ │ ip a → eth0 inet ... │
│ (WSL)" adapter shows │ │ │
│ the bridge's own subnet │ │ hostname -I → the same │
└─────────────────────────┘ │ address, from inside │
└─────────────────────────┘
both sides: localhost forwarding makes 127.0.0.1 usually
reach across this boundary automatically - convenience,
not evidence they share one network stack
Command reference
| Command | What it does | Example |
|---|---|---|
ip addr / ip a |
Shows all network interfaces and their assigned IP addresses. | ip a lists interfaces like lo (loopback) and eth0, each with an inet line showing its IPv4 address. |
ip route |
Shows the routing table - which network destinations go through which interface/gateway. | ip route - the line starting default via ... shows your default gateway. |
ifconfig |
Legacy command that shows interface configuration; largely superseded by ip addr, and may need sudo apt install net-tools to be available. |
ifconfig - mentioned here because you'll see it in older tutorials, but prefer ip a going forward. |
ping host |
Sends ICMP echo requests to a host and reports whether/how fast it responds; stops with Ctrl+C. | ping -c 4 google.com - the -c 4 limits it to 4 pings instead of running forever. |
curl url |
Fetches a URL and prints the response body (a basic GET request) - the general-purpose HTTP client. | curl https://example.com - prints the raw HTML of the page. |
curl -I url |
Fetches only the HTTP response headers, not the body (a HEAD-style request). | curl -I https://example.com - shows status code and headers like Content-Type without downloading the page body. |
curl -o file url |
Saves the response body to a file instead of printing it. | curl -o page.html https://example.com - saves the page as page.html. |
wget url |
Downloads a file from a URL, saving it to disk by default (unlike plain curl, which prints to stdout). |
wget https://example.com/file.tar.gz - downloads and saves file.tar.gz in the current directory. |
ss |
Shows active sockets (network connections and listening ports) - the modern replacement for netstat. |
ss -tulwn - -t TCP, -u UDP, -l listening only, -n show numeric ports instead of resolving service names. |
netstat |
Older tool showing network connections/listening ports; may need sudo apt install net-tools. |
netstat -tulpn - similar flags to ss (-p also shows the owning process, needs sudo for full detail). |
dig host |
Queries DNS and shows detailed resolution information for a hostname. | dig google.com - shows the ANSWER SECTION with the resolved IP address(es). |
nslookup host |
Simpler, older DNS lookup tool. | nslookup google.com - prints the resolved IP address in a shorter format than dig. |
traceroute host |
Shows the network hops (routers) a packet passes through to reach a destination; may need sudo apt install traceroute. |
traceroute google.com - lists each hop with its response time; useful for diagnosing where connectivity slows down or breaks. |
cat /etc/hosts |
Views the local hostname-to-IP override file, checked before DNS. | cat /etc/hosts - typically shows 127.0.0.1 localhost plus any custom entries. |
hostname -I |
Prints the IP address(es) assigned to this machine. | hostname -I inside WSL2 - prints your WSL2 instance's own IP address. |
Hands-on exercises
Open your WSL2 Ubuntu terminal. Run
ip aand find the entry foreth0(or similar). Note theinetaddress - this is your WSL2 instance's own IP address, separate from Windows'.Run
hostname -Ias a quicker way to get just the IP address. Confirm the address matches what you saw in step 1.In a Windows PowerShell or Command Prompt window (not WSL2), run
ipconfigand look for the "vEthernet (WSL)" adapter. Compare its IP range to the address you found in WSL2 - they'll typically be on the same subnet but with different host addresses, confirming WSL2 has its own address on a virtual network Windows also has an interface into.Back in WSL2, run
ip routeand identify thedefault via ...line. This tells you the gateway address your WSL2 instance uses to reach anything outside its own local network (including the internet).Test basic connectivity:
ping -c 4 8.8.8.8. Expect 4 replies with round-trip times. Then tryping -c 4 google.com- this additionally requires DNS resolution to succeed before ping can even send a packet, so it tests both DNS and connectivity at once.Break DNS on purpose to see the error, then understand it: run
ping -c 2 not-a-real-domain-xyz123.com. Read the error message closely - it should indicate the name could not be resolved. This is a DNS failure, not a network failure - contrast it with what you'd see if you pinged a valid domain but had no internet at all (a timeout instead of a resolution error).Use
digto inspect DNS resolution in detail:dig google.com. Find theANSWER SECTIONand note the IP address(es) returned. Then runnslookup google.comand compare - it should show the same resolved address in a simpler format.Fetch a real web page with curl:
curl -I https://example.com. Confirm you see a status line likeHTTP/2 200along with headers. Then runcurl https://example.com(no-I) and note the difference - this time you get the full HTML body.Download a file with
wgetand compare it tocurl -o. Runwget https://example.com -O example1.htmlthencurl -o example2.html https://example.com. Runls -l example1.html example2.htmland confirm both downloaded successfully and are similar in size.Check listening services on your WSL2 instance:
ss -tulwn. Look at theLocal Address:Portcolumn - if nothing is listening yet, that's expected at this stage; you'll revisit this command once you run actual services (starting in module 11, and heavily in Docker/Kubernetes).Explore
/etc/hosts: runcat /etc/hosts. Note the127.0.0.1 localhostline - this is whyping localhostorcurl localhostresolves without needing real DNS. Then test the WSL2-to-Windows localhost forwarding behavior: if you have any web server available on Windows (or skip to just understanding the concept), note that in modern WSL2 setups, a service bound tolocalhostinside WSL2 is generally also reachable vialocalhostfrom Windows and vice versa - this is a convenience feature layered on top of WSL2's separate networking, not evidence that WSL2 and Windows literally share one network stack.(Optional, if
tracerouteis installed - install withsudo apt install tracerouteif needed) Runtraceroute google.comand observe the list of hops. Some hops may show* * *(no response) - this is common for routers that don't reply to traceroute probes and doesn't necessarily indicate a problem.
Production practice: trace a request end to end
A hostname, an IP address, a port, and a URL are different pieces of a connection. Diagnose them separately: name resolution, reachability, listener, protocol, and application response.
Reaching a web service is like finding an apartment: DNS finds the building address, routing gets you to the street, the port identifies a door, and HTTP is the conversation at that door. A failure at one step says little about the others.
flowchart LR
N["Hostname"] --> D["DNS → IP"] --> R["Route"] --> P["Port / listener"] --> H["HTTP response"]
The request path shows the layers. The diagnostic path prevents changing a firewall or application setting before the failing layer is known.
flowchart TD
A["Connection fails"] --> B{"Localhost works?"}
B -->|No| C["Check process + listener"]
B -->|Yes| D{"Hostname resolves?"}
D -->|No| E["Check DNS"]
D -->|Yes| F["Check bind address, route, firewall"]
curl -v http://127.0.0.1:8080/health bypasses DNS and tests a local HTTP listener. ss -ltnp then identifies which process owns 8080. If localhost works but a remote client fails, investigate bind address, firewall, and route before changing application code.
Do not expose a service by binding to 0.0.0.0 or opening a firewall port simply to make a local test pass. First decide whether the service should be reachable only from the same machine, a private network, or the public internet.
Layered connection checklist
getent hosts example.com # name resolution
ip route # routing context
ss -ltnp # local TCP listeners
curl -v http://localhost:PORT # HTTP exchange
Use the least invasive check first. Record the exact host, port, and protocol; “the API is down” is not enough information to reproduce a network problem.
Start a local HTTP server on a non-default port. Prove it responds through localhost, identify its listener with ss, then stop it and confirm the same curl error now reflects a missing listener. If using WSL, compare the result from Ubuntu and Windows deliberately.
A hostname resolves successfully but curl times out. Name three layers that may still be failing and one command or observation for each.
- Can you distinguish “connection refused” from a timeout?
- Can you state which process owns a local port?
- Can you explain why a service that works on localhost may fail remotely?
Independent challenge
No commands given here — figure it out yourself using what you know from this module and earlier ones.
Task: For a website of your choice, determine three separate things and be able to state which tool answered each: the IP address the name resolves to, whether the host is reachable at the network level at all, and what HTTP status code the web service returns. Then deliberately reason through how you would tell apart three different failure modes using these tools — a DNS resolution failure, a network-connectivity failure, and a "host is up but the web service is down" situation. If you want the check to be repeatable, wrap the whole sequence in a small script using module 09's skills.
Stuck? One hint
dig gives you the resolved address, ping (against both a name and a raw IP) separates DNS problems from connectivity problems, and curl -I reports the HTTP status without downloading the whole page body.
Common mistakes & troubleshooting
- Assuming WSL2's IP address is fixed. WSL2's virtual network adapter IP can change between reboots or
wsl --shutdowncycles. If a script or bookmark hardcodes WSL2's IP, it may break later - preferlocalhostwhere forwarding applies, or re-checkhostname -Iwhen something stops connecting. - Confusing WSL2's IP with Windows' IP. Beginners often try to reach a Windows-side service using the IP shown by
ip ainside WSL2, or vice versa - these are different addresses on different (though bridged) virtual interfaces. - Expecting
pingto always confirm a working web service. A host can block ICMP (ping) traffic entirely while still serving HTTP/HTTPS just fine, and conversely a host can respond to ping but have its web service down. Usecurlto actually test the specific service/protocol you care about. - Not distinguishing a DNS failure from a connectivity failure. "Could not resolve host" means DNS lookup failed (check
/etc/hosts,dig, and your DNS configuration). A timeout with no such error usually means the name resolved fine but the destination didn't respond - a different problem entirely. - Forgetting
-cwithpingon Linux. Unlike some tools, Linux'spingruns forever by default until you press Ctrl+C - always use-c Nin scripts or quick tests to avoid it hanging your terminal. ifconfig/netstatnot found. These legacy tools live in thenet-toolspackage, which isn't installed by default on modern Ubuntu.sudo apt install net-toolsfixes it, but preferipandssgoing forward since they're the actively maintained tools.- Assuming
wgetandcurlbehave identically by default.wgetsaves to a file by default;curlprints to stdout by default (requiring-o/-Oto save). Mixing up the default behavior is a common source of "why did it dump garbage in my terminal" or "where did my file go" confusion.
Checkpoint quiz
Write down your answer to each question before expanding it — checking without attempting first is the single easiest way to fool yourself into thinking you've learned this.
- Why does WSL2 have its own IP address separate from the Windows host's IP address?
- What's the practical difference between what an IP address identifies versus what a port number identifies?
- If
ping google.comfails with "could not resolve host" butping 8.8.8.8succeeds, what does that tell you about where the problem lies? - Why might a server respond normally to
curlbut not respond topingat all? - What is
/etc/hostsfor, and why is it checked before DNS? - What does the "default route" in
ip routeactually represent? - Why would you use
curl -Iinstead of plaincurlwhen you just want to check if a site is up and returning a 200 status? - What's a plausible reason a hardcoded WSL2 IP address in a script might stop working after a Windows reboot?
Show answers
- WSL2 runs Linux inside an actual lightweight virtual machine with its own virtual network adapter, distinct from WSL1's approach of translating Linux syscalls directly on Windows - so it gets a genuinely separate network identity, bridged to Windows via a virtual network rather than sharing Windows' interface directly.
- An IP address identifies a specific machine (or network interface) on a network - which device to reach. A port number identifies a specific service or process running on that machine - which "door" on that device to knock on, since one machine can run many services simultaneously.
- It tells you DNS resolution is broken or unreachable (the hostname could not be translated to an IP), while basic network connectivity is fine, since a raw IP address like 8.8.8.8 works without needing any name resolution.
- Servers can be configured to ignore or block ICMP (ping) traffic for security/traffic-shaping reasons while still fully serving HTTP/HTTPS requests normally - ping and a web request use completely different protocols, so one being blocked doesn't imply the other is down.
/etc/hostsis a local, manual file mapping hostnames to IP addresses, checked before the system falls back to real DNS lookups. It's useful for testing, overriding a specific hostname's resolution, or working without a DNS server at all.- It's the "catch-all" next hop - the gateway/router traffic is sent to when the destination doesn't match any more specific route in the routing table, typically used to reach anything outside the local network (like the internet).
curl -Ifetches only the response headers (including the status code) without downloading the full response body, which is faster and sufficient when you only need to confirm the site responds and what status it returns.- WSL2's virtual network adapter can be assigned a different IP address after a reboot or after
wsl --shutdown, since the address isn't guaranteed to be static across restarts - a script relying on the old hardcoded IP would then fail to connect.
Further reading & sources
- Microsoft: Accessing network applications with WSL - the official, current explanation of WSL2 networking modes (NAT vs. mirrored) and localhost forwarding behavior, including known limitations.
man7.org: ip(8) and ss(8) - full option references for the modernip/sstoolset this module favors over the legacyifconfig/netstat.man7.org: curl(1) - curl has dozens of flags beyond-I/-o; worth a skim once you start scripting HTTP checks.- Cloudflare Learning: What is DNS? - a clear, vendor-neutral explanation of the DNS resolution process
dig's output represents. - Julia Evans: "A few reasons DNS is slow" / networking zines - practitioner-written, approachable deep dives if you want more networking intuition beyond this module.
Next
Continue to 11-systemd-services to learn how Linux manages background services - and how to enable and use systemd inside WSL2.