The database server's firewall allowlisted the app box by IP, and the IP came from hostname -I run on the app box — first field, copied into the rule, ticket closed. The first field on that machine was 172.17.0.1, the Docker bridge. The rule matched nothing. Nobody noticed for six weeks because the app was still reaching the database through an older, broader rule, and the day that rule was cleaned up as "redundant" was the day the app went down at 6 pm on a Friday. The wrong IP in a firewall rule does not error; it waits. The same goes for a backup destination: rsync to a mistyped address on a host that happens to exist is a backup that lands somewhere you do not control.
There is no single "my IP address" on a Linux box. There is the address on each interface, the one the default route uses, the public address the world sees after NAT, the gateway, the DNS servers, and the MAC. Which one you need depends on where the rule you are writing lives. The script below prints all of them on one screen so the value you paste came from a report, not from a guess.
Addresses and ports are the same audit
A firewall rule is an address and a port, and half the mistakes are on the port side: a service bound to 0.0.0.0 when it should be on 127.0.0.1, or a listener on an interface you forgot existed. The guide covers reading ss output, telling a bound socket from an exposed one, and closing what should not be open: Find and Close Open Ports on Linux. Run this report and the open ports script together before writing any rule.
The Script
What does the report look like?
This is the script run on the laptop this page was written on — a Kali box on Wi-Fi with Docker running. Every address that identifies this machine or its network — the public IPv4 and IPv6, the MAC, the ISP's DNS servers and Docker's link-local addresses — is swapped for a documentation-range placeholder (RFC 5737, RFC 3849, RFC 7042). The private LAN addresses and the layout are verbatim.
Read the second block and the six-week firewall mistake explains itself. Five interfaces carry an address. Only wlan1 reaches anything beyond the box, and the script picked it without being told because it followed the default route. hostname -I on this same machine prints 172.17.0.1 172.18.0.1 192.168.0.233 ... — two bridge addresses before the real one.
Pass an interface name and the report switches to it. A name that does not exist stops with exit 1 rather than reporting an empty row you might paste anyway:
Which address is "my IP address"?
ip -brief addr is the command that answers it, and the -brief flag is what makes the output readable: name, state, addresses, one line each. The first thing to do with that list is throw most of it away. lo is the loopback; 127.0.0.1 never leaves the box. docker0, br-*, and veth* are container plumbing. fe80:: prefixes are IPv6 link-local — every interface has one, none of them route anywhere. What is left is the interface with a real address, and on a laptop with an idle Ethernet port and two Wi-Fi radios, that can still be three candidates.
The tiebreaker is the routing table. Whatever interface carries the default route is the one the rest of the network talks to you through, and its address is the one that belongs in another machine's firewall rule, in a known_hosts entry, or as the target of an rsync remote backup.
How do I find the default gateway and the interface it uses?
One line, and it carries three of the report's rows: the gateway after via, the interface after dev, and the source address after src. The script parses dev by position-independent field search rather than $5, because the field order changes when proto or metric are absent. If this command prints nothing, the box has no route out at all — the LAN may work, the internet will not, and no amount of DNS debugging will help until a default route exists.
For a specific destination, ip route get 1.1.1.1 shows the kernel's actual decision including the source address it will stamp on the packet. On a multi-homed server that is the only reliable way to know which of your addresses a remote service will see.
Why does /etc/resolv.conf point to 127.0.0.53?
Because on any distribution running systemd-resolved, /etc/resolv.conf is a symlink to a generated file whose only nameserver is the local stub. This box shows exactly that:
The stub forwards to those four upstream servers, and resolvectl status adds which one answered most recently. Copy 127.0.0.53 into a container's DNS config or a dig @ command and it fails, because the stub only listens on the host. The script asks resolvectl first and falls back to reading resolv.conf when the command is missing — which is the Alpine, older-Debian, and minimal-cloud-image case, where the file lists the real servers.
How do I find my public IP from the command line?
You cannot find it on the box, because the box does not have it. The public address exists only in the NAT table of the router or cloud gateway in front of you. The honest method is to ask something on the other side:
The -4 and -6 flags matter. Without them curl picks whichever family it connects with first, and on a dual-stack box that is usually IPv6 — so a script that expected a dotted-quad gets a colon-separated string and puts it in a rule that wanted the other one. The --max-time is the difference between a report that says "lookup failed" in five seconds and one that hangs a cron job forever on a network where outbound HTTPS is blocked. The script wraps both calls in || true and prints a ✗ row, because an unreachable lookup service is information, not a reason to abort the rest of the report.
Where is the MAC address?
ip -brief link prints it as the third column, and /sys/class/net/<iface>/address holds the same value as a plain file — the script reads the file because it needs no parsing. The MAC belongs in DHCP reservations, Wake-on-LAN, and MAC-filter allowlists. It is not a security control: any interface's MAC can be changed with one ip link set command, and the idle wlan0 radio on this box already reports a randomized, locally-administered one (4e:c4:5d:... — the second hex digit's 2-bit is the giveaway).
If you want this alongside CPU, memory, disk, and uptime in one paste, the quick system info report covers the rest of the box; this script is the network half.
Frequently Asked Questions
How do I find my IP address in the Linux terminal?
Run ip -brief addr. Each line is one interface: its name, its state, and every address on it. The one you usually want is on the interface that ip route show default names as dev. Ignore lo, docker0, br-*, and anything starting with fe80::. hostname -I prints only the addresses with no interface names, which is why it is risky on a box running Docker — the bridge address often comes first.
What is the difference between a local IP and a public IP?
The local IP is assigned to your interface and is reachable only inside your network — 192.168.x.x, 10.x.x.x, or 172.16–31.x.x. The public IP is the address your router or cloud NAT presents to the internet; every device behind it shares it, and the box itself has no record of it. A firewall rule on another machine in your LAN needs the local IP. An allowlist on a remote service needs the public one. Either in the other's place produces a rule that matches nothing and fails silently.
Why does /etc/resolv.conf show nameserver 127.0.0.53 instead of my DNS server?
Because systemd-resolved runs a caching stub on 127.0.0.53 and /etc/resolv.conf is a symlink to its generated file. Applications ask the stub, which forwards to the upstream servers it learned from DHCP or your config. resolvectl dns shows those per interface; resolvectl status adds which one answered last. Boxes without resolved list the real servers in resolv.conf directly, which is why the script tries resolvectl first and falls back to the file.
How do I find my default gateway on Linux?
ip route show default prints default via <gateway> dev <interface>. The address after via is your router and the interface after dev carries traffic to it. If it prints nothing, the box has no route to the outside world. ip route get 1.1.1.1 shows the same decision for one destination, including the source address the kernel will use, which is what you need on a box with several interfaces.
Is ifconfig gone, and what replaced it?
ifconfig is part of net-tools, which Ubuntu, Debian, Fedora, and RHEL all stopped installing by default. It still works if you install it, but it does not understand multiple addresses per interface or network namespaces. The replacement is ip from iproute2: ip addr for addresses, ip link for interfaces and MACs, ip route for routing. The -brief flag gives one clean line per interface, which is far easier to read and grep.
Part of the bash snippets collection