Lesson 0001

When a service runs in a sandbox, who can reach it?

This lesson teaches one practical skill: trace the path from a listening process to a browser, another device, or physical hardware. If you can trace that path, container networking and hardware deployment stop feeling random.

15 minute lesson

The Skill

You will learn to say this clearly

"The service is listening in one network namespace. To reach it from somewhere else, I need the right bind address, port publication or forwarding, host interface, and route."

Why this matters for hardware

A Raspberry Pi, Jetson, local server, or robot is just another host on a network. The same checks apply, but the host is a physical device instead of your laptop or a container.

The Reachability Chain

A network failure is usually one broken link in this chain. Do not debug it as "Docker is weird" or "the Pi is weird". Debug one link at a time.

1. Process The app must listen on the port you think it is using.
2. Bind address 127.0.0.1 is local to that namespace. 0.0.0.0 means every IPv4 interface in that namespace.
3. Sandbox boundary A container, VM, or dev sandbox may need explicit port publishing or a tunnel.
4. Host interface The host must expose the port on an address the client can reach.
5. Client route The browser, laptop, or hardware device must have a route to that host address.
Docker's official docs describe port publishing as the step that makes a container port available through a host address. Linux network namespaces explain the deeper reason: network devices, routing, firewall rules, and port numbers can be isolated per namespace.

The Three Addresses To Stop Confusing

127.0.0.1

Loopback. It means "this network namespace itself". If a container binds to 127.0.0.1, that is the container's own loopback, not your Mac's loopback.

0.0.0.0

All IPv4 interfaces in the current namespace. It is not an address you browse to. It is a listening choice.

192.168.x.y or 10.x.y.z

A private LAN address. This is often what another laptop or hardware device uses to reach your machine.

Container IP

An address inside the container network. It is usually useful to the host or peer containers, but not automatically useful to other LAN devices.

Lab A: Host-Only Service

Run this from any directory. It starts a tiny web server that only listens on your current machine.

python3 -m http.server 8080 --bind 127.0.0.1

In another terminal, prove it works locally:

curl -v http://127.0.0.1:8080/

Now ask the diagnostic question: if another laptop or hardware device tries http://YOUR_MAC_LAN_IP:8080, should it work? No. The process bound to loopback only.

Find your LAN IP
# Common macOS Wi-Fi interface
ipconfig getifaddr en0

# Common Linux command
hostname -I

Lab B: Container Port Publishing

If Docker is installed, this command runs Nginx in a container and publishes container port 80 to host port 8080, but only on host loopback:

docker run --rm -p 127.0.0.1:8080:80 nginx:alpine

Local test:

curl -I http://127.0.0.1:8080/

To deliberately allow LAN clients, widen the host bind address:

docker run --rm -p 8080:80 nginx:alpine
Docker publishes to all host interfaces by default when you omit the host IP. Use that intentionally. For experiments, start with 127.0.0.1.

Hardware Translation

On a Raspberry Pi or similar Linux box, the same chain applies. The difference is that the host is now the device.

  1. Find the device: ping raspberrypi.local, your router device list, or sudo nmap -sn 192.168.1.0/24 after adjusting the subnet.
  2. SSH into it: ssh USER@raspberrypi.local or ssh USER@DEVICE_IP.
  3. Start a service on the device. For a LAN-visible test: python3 -m http.server 8080 --bind 0.0.0.0.
  4. From your laptop, try curl -v http://DEVICE_IP:8080/.
  5. If the service is in a container on the device, publish the port on the device host: docker run --rm -p 8080:80 nginx:alpine.

That is the same pattern: process -> bind address -> sandbox boundary -> host interface -> client route.

Scenario Quiz

Pick the most likely broken link. You get immediate feedback.

Scenario 1

You run python3 -m http.server 8080 --bind 127.0.0.1 on your Mac. Your browser can open http://127.0.0.1:8080. Your phone on the same Wi-Fi cannot open http://MAC_LAN_IP:8080.

Scenario 2

You run Nginx in Docker with docker run --rm nginx:alpine. Nginx starts successfully, but curl http://127.0.0.1:80 from the host fails.

Scenario 3

You SSH into a Raspberry Pi and run python3 -m http.server 8080 --bind 0.0.0.0. From the Pi, curl http://127.0.0.1:8080 works. From your laptop, curl http://192.168.1.42:8080 fails.

Exit Ticket

Before moving on, you should be able to answer this without looking:

A service works at http://127.0.0.1:8080 on the host but not from another device on the LAN. Name the two most likely reasons.

Good answer: it may be bound to loopback only, or the host/network/firewall path to the LAN IP may be blocked. If the service is inside a sandbox, missing port publishing is also high on the list.

References

Docker: Port publishing and mapping

Official reference for mapping container ports to host addresses.

Docker: Publishing and exposing ports

Beginner explanation of why isolated containers need published ports.

Linux: network_namespaces(7)

Kernel-level explanation of isolated network devices, stacks, routes, firewalls, and ports.

Raspberry Pi: Remote access

Official guide for finding device IP addresses and connecting with SSH.

Ask follow-up questions in the agent when a step feels unclear. The next good lesson is filesystem boundaries: how source code, build artifacts, and device files cross into a sandbox.