Localhost Development: ip, ports & co.

Context

This is a back to basics about developing local servers.

It's mainly a reference for my future self.

Network Interfaces

Your computer has multiple network interfaces. Each interface is assigned with a specific IP address. One such virtual interface is called loopback.

On a Mac, you can run ifconfig to list your network interfaces.

Here is a summary of the kind of interface you might see:

Name Description
lo0 Loopback
gif0 Generic IP tunnel (VPN)
stf0 IPv4 to IPv6 tunnel, obsolete
anpiX Apple Network Processor Interface, virtual usb-c interfaces
enX Ethernet interface (wifi, wired, dock, etc.)
ap0 Access Point interface, for when laptop is a Wifi hotspot
awdl0 Apple Wireless Direct Link for Airdrop and Airplay
bridge0 Network bridge (usually for enX) to share traffic between interfaces
llw0 Low Latency Wireless for Homekit/IoT
utunX Tunnel interfaces (VPN)

Loopback

The loopback interface is special in that any server running on it is accessible to the current device only.

By definition, it has address ::1 (or 127.0.0.1)

Localhost

.localhost is one of the 4 reserved gTLD to help with development, along with .example, .invalid and .test.

x.localhost is guarranteed to resolve to the loopback address on the loopback interface.

0.0.0.0?

:: or 0.0.0.0 are special: listening on those IPs means listening on all interface of this device.

This is only useful if you want to access your local server on the same network, like if you run your server on your laptop, but want to access it from your phone.

For this usecase, I'd recommend mDNS, though.

Ports

Port ranges are standardized:

Range Description
0-1023 System Ports/Well Known Ports, required escalated priviledges
1024-49151 User Port/Registered Ports, usables
49152-65535 Dynamic Ports, never assigned, for clients

Port 0 is special: binding to it will result in the OS assigning a randomly available free port.

Realistically, only the User Ports should be used, and it's common to bind to port 8080 for http traffic, or nearby.

Static Recommendations

For running a server locally, listen to localhost and a free port like 8080. Ensure the port is changeable via a configuration to allow running more than 1 service at a time.

To avoid remembering the ports of each service, and to help with TLS, you may want to have a reverse proxy listening on localhost:80, and let it handle the conversion with sub dns, like api.localhost being routed to localhost:8080, and db.localhost is routed to localhost:8083, etc.

This is what Traeffic partially automates in with labels in docker-compose, but you can do this locally with Caddy:

Caddyfile Example

api.localhost {
	reverse_proxy localhost:8080
}

db.localhost {
	reverse_proxy localhost:8083
}

Kubernetes Recommendations

If your container listens on localhost in kubernetes, only other containers in that pod will be able to access your server.

Kubernetes will make the traffic reach your container through a different network interface.

Since you usually do not know in advance which IP will be given to you, it is recommended to expose your container server on all network interfaces (aka :: or 0.0.0.0).

Dynamic Recommendations

If you have a registry, like in a service mesh, it makes sense to bind to localhost and port 0 and then publish this to your registry.