Interfaces and ip
The iproute2 suite — ip addr, ip link, ss — replaced legacy ifconfig/netstat. Predictable interface names (ens3, enp2s0) survive reboots; loopback (lo) is always present. ss -tlnp shows what is listening and which process owns it.
You SSH into a new VM and the first thing you need to know is: does this machine have a working network interface, what IP does it have, and what ports are open? The old tools — ifconfig, netstat — are gone from minimal Debian images; they come from the net-tools package that most distros no longer install by default. The modern replacements are ip (from iproute2) and ss (socket statistics). These are not just drop-in replacements — they expose more information in a cleaner format and are the tools that kernel developers actually maintain. If you still reach for ifconfig, you are debugging with a tool that does not know about network namespaces, MPLS, or VRFs. The gap matters in containers and cloud VMs.
After this lesson you can list all interfaces and their addresses with ip addr, bring an interface up or down with ip link set, assign a temporary address with ip addr add, read predictable interface names and understand why they exist, and use ss -tlnp to see what is listening on which port and which process owns it.
ip addr show — the primary tool for seeing interface addresses.
Every network interface has a name, flags (UP, LOWER_UP, LOOPBACK), an index, and one or more addresses. The loopback interface (lo) is always present; inet 127.0.0.1/8 is its address.
ip addr show
# 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
# link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# inet 127.0.0.1/8 scope host lo
# inet6 ::1/128 scope host
# 2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP
# link/ether 52:54:00:ab:cd:ef brd ff:ff:ff:ff:ff:ff
# inet 10.0.0.10/24 brd 10.0.0.255 scope global dynamic ens3
# Short form: ip addr (same output)
# Per-interface: ip addr show ens3The inet line is the IPv4 address in CIDR notation. scope global means it is reachable from other hosts; scope host (loopback) means only the local host. dynamic means it was assigned by DHCP.
ip link show — interface state without addresses.
When you need to check whether an interface is up or see its MAC address without the address noise:
ip link show
# 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 ...
# 2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
# link/ether 52:54:00:ab:cd:ef brd ff:ff:ff:ff:ff:ff
# Bring an interface down and back up (needs root):
sudo ip link set ens3 down
sudo ip link set ens3 up
# Check: the UP flag disappears from the angle-bracket flags when down
ip link show ens3
# 2: ens3: <BROADCAST,MULTICAST> mtu 1500 ... ← no UP flagip link set ... down is non-destructive: it does not remove the interface or its configuration. DHCP clients (dhclient, systemd-networkd) will notice the carrier change and may act — but the address stays in the kernel’s address table until cleared.
Predictable interface names: why ens3 and not eth0.
Linux kernels before udev used eth0, eth1 in probe order — race-prone on multiport machines, meaningless after a reboot with different hardware. Systemd’s udev renamed interfaces using a stable algorithm based on firmware slot, PCI bus address, or MAC address:
# Name scheme prefixes:
# en = Ethernet
# wl = Wireless LAN
# ww = Wireless WAN (WWAN/LTE)
#
# Suffix encoding:
# o<index> = on-board (e.g. eno1)
# s<slot> = PCI slot (e.g. ens3)
# p<bus>s<slot> = PCI path (e.g. enp2s0)
# x<MAC> = named by MAC (fallback)
#
# Examples you will see on cloud VMs:
# ens3 → PCI slot 3 Ethernet
# enp0s3 → PCI bus 0, slot 3
# ens192 → VMware virtual NIC slot 192
# The old name eth0 is still used when udev cannot determine a stable path,
# or in containers where the kernel exposes a veth pair.The practical outcome: the same interface name survives reboots, hardware swaps in the same slot, and kernel upgrades. On cloud VMs you can rely on ens3 staying ens3.
Assigning a temporary address with ip addr add.
DHCP-assigned addresses are managed by a network daemon. Manual assignment is useful for testing, adding a second address, or bringing up a link before the daemon runs:
# Add a temporary address (lost on reboot unless persisted in /etc/network/interfaces or netplan):
sudo ip addr add 192.0.2.50/24 dev ens3
# Verify:
ip addr show ens3
# inet 10.0.0.10/24 ...
# inet 192.0.2.50/24 scope global ens3 ← second address visible
# Remove it:
sudo ip addr del 192.0.2.50/24 dev ens3A single interface can hold multiple addresses (multihoming). The kernel sends traffic from whichever address is selected by the routing table. To persist addresses across reboots, use /etc/network/interfaces (Debian ifupdown), netplan (Ubuntu), or systemd-networkd.
ss -tlnp — what is listening and which process.
ss is the modern replacement for netstat. The flags used most in practice:
ss -tlnp
# -t TCP sockets only
# -l listening sockets only (servers waiting for connections)
# -n numeric ports (do not resolve /etc/services names)
# -p show process (PID and name) that owns the socket
# Example output:
# State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
# LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1234,fd=3))
# LISTEN 0 4096 127.0.0.1:5432 0.0.0.0:* users:(("postgres",pid=5678,fd=7))
# LISTEN 0 128 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=9012,fd=6))
# All TCP (established + listen):
ss -tnp
# UDP sockets:
ss -ulnp
# All sockets, numeric, with process:
ss -anpLocal Address:Port of 0.0.0.0:22 means sshd listens on all interfaces; 127.0.0.1:5432 means postgres only accepts connections from localhost — a security boundary visible right here.
First-login network triage on a new VM.
You SSH into host-a (10.0.0.10/24). The app is not reachable. In 60 seconds:
# 1. Do we have a live interface?
ip addr show
# → ens3 UP, inet 10.0.0.10/24 — good
# 2. Is the app actually listening?
ss -tlnp | grep ':8080'
# → nothing — the app never started or crashed
# 3. Start the app (example: systemd unit)
sudo systemctl start myapp
ss -tlnp | grep ':8080'
# LISTEN 0 511 0.0.0.0:8080 0.0.0.0:* users:(("myapp",pid=4321,fd=10))
# 4. Is it listening on all interfaces or only localhost?
# 0.0.0.0:8080 → all interfaces, reachable from 10.0.0.x
# 127.0.0.1:8080 → only localhost — a firewall or bind-address config issue
# 5. Double-check from the outside (from host-b):
# ssh host-b 'curl -s http://10.0.0.10:8080/health'Reading ss -tlnp before checking firewall rules or DNS saves minutes at 3am.
▸Common mistake
ifconfig is not just deprecated — it is absent. On a fresh Debian 12 or Ubuntu 24.04 minimal install, ifconfig is not installed. Running it gives “command not found.” Muscle memory that reaches for ifconfig eth0 will mislead you. The iproute2 mapping: ifconfig → ip addr show; ifconfig eth0 up → ip link set eth0 up; netstat -tlnp → ss -tlnp. Install net-tools if you need the old commands temporarily, but do not script against them — they are not maintained and do not understand network namespaces.
▸Why this works
On macOS, ifconfig is the primary tool and is actively maintained (BSD heritage). ip is not available unless you install iproute2mac via Homebrew — and even then it is a partial shim. For socket inspection macOS uses netstat -an or lsof -i. The concepts are identical (interfaces, addresses, listening sockets) but the tooling surface is entirely different. If your dev machine is macOS and your production is Linux, keep both vocabularies: ifconfig/netstat for your laptop, ip/ss for everything else.
You run ss -tlnp and see: LISTEN 0 128 127.0.0.1:5432 0.0.0.0:* users:((postgres,pid=5678,fd=7)). What does this tell you about postgres reachability from another host?
ip addr show lists all interfaces and their IPv4/IPv6 addresses in CIDR notation; scope global means externally reachable, scope host is loopback-only. ip link set <iface> up/down controls interface state without removing addresses. Predictable interface names (ens3, enp2s0) are assigned by udev based on PCI topology — stable across reboots, unlike the legacy eth0 race. ip addr add/del assigns temporary addresses; persistence requires netplan, systemd-networkd, or /etc/network/interfaces. ss -tlnp shows TCP listening sockets with the owning process — bind address 0.0.0.0 means all interfaces, 127.0.0.1 means localhost-only. These five operations cover 90% of first-login network triage.
Practice
Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.
Something unclear?
Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.