Every Linux server you manage needs networking. Whether you're deploying a web application, connecting to a database, or troubleshooting why users can't reach your service, understanding Linux networking is essential. This lesson covers network interfaces, port checking, firewall management with ufw, DNS resolution, and connectivity troubleshooting — the tools and commands every DevOps engineer uses daily.

1. Learning Objectives

By the end of this lesson, you will be able to:

  • View and configure network interfaces using ip and nmcli
  • Check open ports and active connections with ss and netstat
  • Set up firewall rules with ufw to allow or block traffic
  • Test connectivity with ping, curl, and traceroute
  • Troubleshoot DNS resolution with dig and nslookup
  • Inspect and modify network routing tables
  • Diagnose common network issues methodically

2. Why This Matters

Real-world scenario: You've deployed a Flask web application on a cloud server. It's running on port 5000, but nobody can access it from the browser. Your first instinct is to check if the process is running (it is). Then you check if the firewall is blocking the port (it is). Finally, you check if the application is binding to the right IP address (it's binding to 127.0.0.1 instead of 0.0.0.0 — only localhost can reach it).

These three checks — process status, firewall rules, and interface binding — are the fundamentals of Linux networking troubleshooting. Every DevOps engineer runs them dozens of times a week. This lesson gives you the commands and the mental model to diagnose and fix network issues confidently.

3. Core Concepts

Network Interface — A virtual or physical device that connects your system to a network. Common interfaces: eth0 (wired Ethernet), wlan0 (WiFi), lo (loopback/localhost). Cloud servers often use ens3 or eth0.

IP Address — A unique identifier for your machine on a network. IPv4 examples: 192.168.1.10 (private), 203.0.113.5 (public). The special address 127.0.0.1 refers to the local machine (localhost).

Port — A numbered endpoint for network communication. Common ports: 22 (SSH), 80 (HTTP), 443 (HTTPS), 3306 (MySQL), 5432 (PostgreSQL), 8080 (alternative HTTP), 3000 (Node.js dev server).

Firewall — A ruleset that filters incoming and outgoing traffic. ufw (Uncomplicated Firewall) is the most common frontend on Ubuntu. firewalld is common on RHEL/CentOS. Underneath, both use iptables or nftables.

DNS (Domain Name System) — Translates domain names like example.com into IP addresses. Your server uses DNS to reach external services like package repositories and APIs.

Routing Table — A set of rules that determines where network packets go based on their destination IP. The default route sends packets to the internet gateway.

4. Hands-On Practice

4.1 Inspecting Network Interfaces

Start by viewing your system's network interfaces:

# List all network interfaces
ip link show

# Show IP addresses assigned to each interface
ip addr show
# Short form
ip a

# Show only active interfaces
ip link show up

# Check interface statistics (packets, errors, drops)
ip -s link show eth0
Inspecting network interfaces with ip
kubectl get pods -w
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.5/24 brd 10.0.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe12:3456/64 scope link
valid_lft forever preferred_lft forever
Output of ip a showing loopback and Ethernet interfaces

Key things to read from the output: The interface name (eth0), its state (UP), the assigned IP (10.0.0.5/24), and the MAC address (52:54:00:12:34:56). The /24 means the subnet mask is 255.255.255.0.

4.2 Checking Open Ports and Connections

ss (socket statistics) is the modern replacement for netstat. It shows open ports, active connections, and listening services:

# Show all listening TCP ports and their processes
ss -tlnp

# Show all listening UDP ports
ss -ulnp

# Show all active connections (established)
ss -tunp

# Show listening sockets (both TCP and UDP) with process info
ss -tulnp

# Legacy: equivalent netstat commands
netstat -tulnp
netstat -anp | grep LISTEN
Checking open ports and connections with ss
kubectl get pods -w
$ ss -tulnp
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=456,fd=12))
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=789,fd=3))
tcp LISTEN 0 128 127.0.0.1:3306 0.0.0.0:* users:(("mysqld",pid=901,fd=24))
tcp LISTEN 0 128 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1001,fd=8))
tcp LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=789,fd=4))
ss output showing SSH (22), MySQL (3306), and Nginx (80) listening

Interpretation: 0.0.0.0:22 means SSH is listening on all interfaces. 127.0.0.1:3306 means MySQL is listening on localhost only (not accessible from other machines). This is a common security pattern for databases.

4.3 Firewall Management with ufw

ufw (Uncomplicated Firewall) is the easiest way to manage firewall rules on Ubuntu/Debian:

# Check firewall status
sudo ufw status
sudo ufw status verbose

# Enable/disable the firewall
sudo ufw enable
sudo ufw disable

# Allow traffic on specific ports
sudo ufw allow 22/tcp        # SSH
sudo ufw allow 80/tcp        # HTTP
sudo ufw allow 443/tcp       # HTTPS
sudo ufw allow 3000/tcp      # Custom app port

# Allow by service name (uses /etc/services)
sudo ufw allow ssh
sudo ufw allow http

# Deny a specific port
sudo ufw deny 3306         # Block MySQL from external access

# Allow from specific IP
sudo ufw allow from 192.168.1.100 to any port 22

# Allow a subnet
sudo ufw allow from 10.0.0.0/24 to any port 5432

# Delete a rule (by number or by specification)
sudo ufw status numbered
sudo ufw delete 3
sudo ufw delete allow 3000/tcp

# Reset to defaults
sudo ufw default deny incoming
sudo ufw default allow outgoing

# View logged denied packets
sudo journalctl -u ufw

# Reload after changes
sudo ufw reload
Complete ufw firewall management commands
kubectl get pods -w
$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
3000/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN Anywhere (v6)
80/tcp (v6) ALLOW IN Anywhere (v6)
443/tcp (v6) ALLOW IN Anywhere (v6)
3000/tcp (v6) ALLOW IN Anywhere (v6)
ufw status showing active firewall rules

4.4 Testing Connectivity

Once you've configured interfaces, ports, and firewall rules, test connectivity end-to-end:

# 1. Check if a remote host is reachable
ping -c 4 google.com

# 2. Test a specific port is open (TCP)
curl -v http://localhost:80
curl -v http://10.0.0.5:3000

# 3. Test TCP connection at the socket level
timeout 3 bash -c 'echo >/dev/tcp/google.com/80' && echo "Port 80 is open"

# 4. Trace the route packets take
traceroute google.com
# Modern alternative
tracepath google.com

# 5. Test HTTP headers
curl -I https://example.com

# 6. Check bandwidth (requires iperf3 on both ends)
iperf3 -c 10.0.0.5

# 7. Port scan (install nmap first)
nmap -p 22,80,443 10.0.0.5
Connectivity testing commands

4.5 DNS Troubleshooting

DNS issues are among the most common network problems. Here's how to diagnose them:

# Check system DNS configuration
cat /etc/resolv.conf

# Query DNS resolution for a domain
dig example.com

# Short form: just the answer
dig +short example.com

# Query a specific DNS server
dig @8.8.8.8 example.com

# Reverse DNS lookup (IP to hostname)
dig -x 142.250.80.14

# Simpler alternative to dig
nslookup example.com
nslookup example.com 8.8.8.8

# Check which DNS server resolved the name
host example.com

# Test DNS resolution and connection together
curl -v https://example.com

# Flush DNS cache (systemd-resolved)
sudo resolvectl flush-caches

# Check DNS cache statistics
resolvectl statistics
DNS troubleshooting commands

4.6 Routing and Gateway

The routing table tells your system where to send packets. The default route is the gateway for all internet traffic:

# View routing table
ip route show
# Short form
ip r

# Add a static route
sudo ip route add 10.0.1.0/24 via 10.0.0.1 dev eth0

# Delete a route
sudo ip route del 10.0.1.0/24

# Add a default gateway
sudo ip route add default via 10.0.0.1

# Show ARP table (IP to MAC mappings)
ip neigh show

# Check route to a specific destination
ip route get 8.8.8.8

# Trace path (shows where packets are being forwarded)
# First install: apt install mtr
traceroute -n 8.8.8.8
Routing table management
kubectl get pods -w
$ ip route show
default via 10.0.0.1 dev eth0 proto static
10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.5

$ ip route get 8.8.8.8
8.8.8.8 via 10.0.0.1 dev eth0 src 10.0.0.5 uid 1000
Routing table output showing default gateway and path to 8.8.8.8

The default via 10.0.0.1 line means: send all outbound traffic (not matching any other route) to the gateway at 10.0.0.1. The 10.0.0.0/24 dev eth0 line means: traffic to the local subnet goes directly through the eth0 interface.

5. Common Errors & Solutions

  1. Error: Connection refused — The port is closed or no service is listening. Run ss -tulnp | grep :PORT to see if anything is listening. Start the service if it isn't running.
  2. Error: Connection timed out — A firewall is dropping your packets. Check sudo ufw status on the server, and verify cloud security groups (AWS security groups, GCP firewall rules) allow the port.
  3. Error: Temporary failure in name resolution — DNS is broken. Run dig google.com and cat /etc/resolv.conf. The DNS server IP in /etc/resolv.conf may be unreachable.
  4. Error: Address already in use — Another process is already using that port. Run ss -tulnp | grep :PORT to find the PID, then kill or stop the conflicting process.
  5. Error: Permission denied when binding to port — Ports below 1024 require root. Use sudo to start the service, or bind to a port above 1024 and use a reverse proxy (Nginx) to forward from port 80.
  6. Error: Network is unreachable — The route to the destination doesn't exist. Run ip route show to check your routing table. You may have lost your default gateway.

6. Summary Checklist

  • I can inspect network interfaces with ip a and understand the output
  • I can check what ports are listening with ss -tulnp
  • I can configure ufw to allow/deny specific ports and IPs
  • I can test TCP connectivity with curl and socket checks
  • I can resolve DNS issues using dig and nslookup
  • I can view and modify the routing table with ip route
  • I can diagnose connection refused vs. timeout vs. unreachable errors

7. Practice Exercise

Scenario: You've just deployed a Node.js API server on a fresh Ubuntu server. It's listening on port 3000. Users report they can't reach your API from their browsers.

Tasks:

  1. Check if the Node.js process is listening on port 3000 (ss -tulnp | grep 3000)
  2. Check if the firewall is blocking port 3000 (sudo ufw status). If it isn't allowed, add a rule.
  3. Test locally: curl -v http://localhost:3000 should return a response
  4. Find the server's IP: ip a | grep inet
  5. Test from another machine: curl -v http://SERVER_IP:3000
  6. If still failing, check if the app is binding to 0.0.0.0 or 127.0.0.1. If it's on localhost-only, restart the app with the correct bind address.

Bonus: Check DNS resolution and verify the routing table to understand how traffic flows from the user to your server.

8. Next Steps

Now that you can configure Linux networking, the next lesson in the Linux series will cover Linux Package Management: apt, snap, and dpkg. You'll learn to install, update, and remove software packages, manage repositories, and troubleshoot package conflicts — essential skills for provisioning and maintaining servers.

After that, the series will move into Bash Scripting - Conditionals, Loops, and Functions to automate everything you've learned.

Gataya Med

DevOps Engineer & Backend Developer. Sharing insights on cloud, automation, and scalable systems.

Comments (0)

Sarah Chen July 20, 2026

This is exactly what I needed! The initContainer approach solved our migration issues completely. Thanks for the detailed guide!

Reply

Leave a Comment