Skip to content

Network Fundamentals Every Software Developer Should Know

A practical glossary of essential networking concepts for developers - from protocols and DNS to debugging tools and security basics.

Ayhan Sipahi Ayhan Sipahi

Mysterious timeouts, slow APIs, and TLS errors in distributed systems are almost always network problems disguised as application problems. When developers lack a working model of TCP, DNS, and HTTP, diagnosis stalls at the wrong layer and fixes are guesswork.

The concepts below are the ones that surface most often in backend development and production troubleshooting: protocols, the connection lifecycle, debugging tools, and security basics. Each entry names what the concept is, when it matters, and which command answers the question.

Where Network Knowledge Pays Off#

Perfect application code still fails when data movement between client and server is not understood. Developers struggle with:

  • Debugging mysterious timeouts - Is it DNS? TCP handshake? SSL negotiation? Application logic?
  • Performance optimization - Why does your API feel slow? Is it latency, bandwidth, or connection overhead?
  • Security decisions - Understanding TLS, certificates, and network security helps you make informed choices
  • Infrastructure design - Load balancing, CDN configuration, and service communication patterns
  • Production incidents - Network issues often manifest as application problems

Network Layers & Models#

OSI Model#

The OSI (Open Systems Interconnection) model divides networking into seven layers. While you don’t need to memorize all layers, understanding the concept helps troubleshooting:

Layer 7: Application  (HTTP, FTP, SMTP)
Layer 6: Presentation (SSL/TLS, encryption)
Layer 5: Session  (connection management)
Layer 4: Transport  (TCP, UDP)
Layer 3: Network  (IP, routing)
Layer 2: Data Link  (Ethernet, MAC addresses)
Layer 1: Physical  (cables, signals)

Knowing which layer a problem occurs at saves debugging time: DNS issues are Layer 7, routing problems are Layer 3, and physical connectivity is Layer 1.

TCP/IP Model#

The practical model we actually use collapses OSI into four layers:

Application Layer  (HTTP, DNS, SSH)
Transport Layer  (TCP, UDP)
Internet Layer  (IP, ICMP)
Link Layer  (Ethernet, Wi-Fi)

Most developer troubleshooting happens at the Application and Transport layers. Understanding IP helps with routing issues, and Link layer problems usually require network admin intervention.

Core Protocols#

HTTP/HTTPS#

HTTP (Hypertext Transfer Protocol) is the foundation of web communication. It’s a request-response protocol where clients send requests and servers return responses.

Key characteristics:

  • Stateless (each request is independent)
  • Text-based protocol
  • Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD
  • Status codes: 2xx (success), 3xx (redirect), 4xx (client error), 5xx (server error)

HTTPS adds SSL/TLS encryption on top of HTTP. The ‘S’ means your data is encrypted in transit.

HTTPS actually provides three guarantees at once: encryption keeps the payload private, authentication proves you’re talking to the right server, and integrity proves the data wasn’t modified in transit.

A basic HTTP request looks like this:

# Simple GET request
curl -v https://api.example.com/users

# POST with JSON body
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"name": "John", "email": "john@example.com"}'

# See response headers
curl -I https://api.example.com/health

APIs, web applications, and RESTful services are the default use case; HTTPS should be the default for anything that crosses the internet.

HTTP/2 and HTTP/3#

HTTP/2 improves on HTTP/1.1 with:

  • Multiplexing (multiple requests over single connection)
  • Header compression
  • Server push
  • Binary protocol (not text-based)

HTTP/3 uses QUIC instead of TCP:

  • Faster connection establishment
  • Better handling of packet loss
  • Built on UDP with reliability added

HTTP/2 significantly reduces latency for websites with many resources, and HTTP/3 shines on mobile networks with packet loss. HTTP/2 also requires HTTPS; browsers won’t negotiate it over plain HTTP.

TCP vs UDP#

TCP (Transmission Control Protocol):

  • Connection-oriented (handshake before data transfer)
  • Reliable (guarantees delivery and order)
  • Flow control and congestion control

UDP (User Datagram Protocol):

  • Connectionless (fire and forget)
  • Unreliable (no delivery guarantee)
  • No ordering guarantee

HTTP/HTTPS traffic, database connections, and file transfers all need TCP because delivery has to be guaranteed. UDP shows up wherever a lost packet costs less than the overhead of guaranteeing it arrives: video streaming (a dropped frame goes unnoticed), gaming (speed over perfect accuracy), DNS queries (a client can just retry), real-time metrics (losing one data point doesn’t matter).

Here’s what the three-way handshake looks like on the wire:

ServerClientServerClientTCP Three-Way HandshakeConnection EstablishedConnection TerminationSYN (sequence=1000)SYN-ACK (sequence=5000, ack=1001)ACK (sequence=1001, ack=5001)Data TransferACKFINACKFINACK

Seeing TCP retransmissions? Check network congestion, packet loss, or firewall issues.

WebSocket#

WebSocket provides full-duplex communication over a single TCP connection. Unlike HTTP’s request-response model, it starts as an HTTP upgrade request, then keeps a persistent, low-overhead channel open for real-time, two-way messages, which is why chat applications, live notifications, real-time dashboards, collaborative editing, and gaming reach for it. Either side can push data without waiting for a request.

Server and client in Node.js:

import WebSocket from 'ws';

// Server
const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', (ws) => {
  console.log('Client connected');

  ws.on('message', (message) => {
    console.log('Received:', message);
    // Broadcast to all clients
    wss.clients.forEach((client) => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(message);
      }
    });
  });

  ws.on('close', () => {
    console.log('Client disconnected');
  });
});

// Client
const ws = new WebSocket('ws://localhost:8080');

ws.on('open', () => {
  ws.send('Hello Server!');
});

ws.on('message', (data) => {
  console.log('Received:', data);
});

Proxies and load balancers often close WebSocket connections after an idle timeout, so a heartbeat/ping-pong exchange is what keeps the connection alive.

gRPC#

gRPC is a modern RPC framework using HTTP/2 and Protocol Buffers, particularly popular for microservices communication. It’s a binary protocol for efficiency, strongly typed through Protocol Buffers, supports streaming in all three directions (client, server, bi-directional), generates code from .proto files, and includes load balancing and retries out of the box, which also makes it a natural choice for high-performance APIs, polyglot environments with many language bindings, and streaming data.

A minimal .proto definition:

syntax = "proto3";

service UserService {
  rpc GetUser (GetUserRequest) returns (User);
  rpc ListUsers (ListUsersRequest) returns (stream User);
}

message GetUserRequest {
  string user_id = 1;
}

message User {
  string id = 1;
  string name = 2;
  string email = 3;
}

Where gRPC struggles: browser clients (limited support), public-facing APIs (REST is more universal), teams unfamiliar with Protocol Buffers.

DNS & Name Resolution#

How DNS Works#

DNS (Domain Name System) translates human-readable domain names to IP addresses. It’s a distributed, hierarchical system.

DNS query flow:

Authoritative DNSTLD DNS (.com)Root DNSResolver (Local DNS)ApplicationAuthoritative DNSTLD DNS (.com)Root DNSResolver (Local DNS)Applicationalt[Cached][Not Cached]Query: api.example.comReturn cached IPQuery: api.example.comRefer to .com TLDQuery: api.example.comRefer to example.com NSQuery: api.example.comReturn IP: 192.0.2.1Return IP: 192.0.2.1

DNS record types:

  • A: Maps domain to IPv4 address
  • AAAA: Maps domain to IPv6 address
  • CNAME: Alias to another domain
  • MX: Mail server records
  • TXT: Text records (often used for verification, SPF, DKIM)
  • NS: Nameserver records
  • SOA: Start of Authority (zone information)

Common dig invocations for troubleshooting:

# Basic DNS lookup
dig example.com

# Query specific record type
dig example.com AAAA

# Use specific DNS server
dig @8.8.8.8 example.com

# Trace DNS resolution path
dig +trace example.com

# Reverse DNS lookup (IP to domain)
dig -x 192.0.2.1

# Short answer only
dig +short example.com

Where DNS goes wrong:

  • DNS caching: Changed DNS but old IP still resolving? Check TTL (Time To Live)
  • DNS propagation: Changes can take 24-48 hours to propagate globally
  • Local cache: Application might cache DNS results (check your DNS client settings)
  • Split-horizon DNS: Internal vs external DNS returning different results

DNS failures are often silent: an application might keep using a stale cached value while DNS is broken, masking the problem until the cache expires.

DNS TTL#

TTL (Time To Live) tells resolvers how long to cache a DNS record. Measured in seconds.

Strategy:

  • Long TTL (hours/days): Stable infrastructure, reduce DNS load
  • Short TTL (minutes): Before planned changes for faster cutover
  • Balance: 300-3600 seconds (5 minutes to 1 hour) works for most cases

Pre-migration pattern:

# 1 week before migration: Lower TTL to 300 seconds
# Migration day: Change DNS records
# 1 week after migration: Raise TTL back to 3600+ seconds

IP Addressing & Routing#

IPv4 Addressing#

IPv4 address: 32-bit number written as four octets (0-255) separated by dots.

Example: 192.168.1.100

Special ranges:

  • Private addresses (not routable on internet):
    • 10.0.0.0/8 (10.0.0.0 - 10.255.255.255)
    • 172.16.0.0/12 (172.16.0.0 - 172.31.255.255)
    • 192.168.0.0/16 (192.168.0.0 - 192.168.255.255)
  • Loopback: 127.0.0.0/8 (localhost)
  • Link-local: 169.254.0.0/16 (auto-configuration when DHCP fails)

CIDR notation: 192.168.1.0/24 means first 24 bits are network, last 8 bits are host.

  • /24 = 256 addresses (254 usable, 2 reserved)
  • /16 = 65,536 addresses
  • /8 = 16,777,216 addresses

Checking your own IP address:

# Public IP
curl ifconfig.me

# Local IP (Linux/Mac)
ifconfig | grep "inet " | grep -v 127.0.0.1

# Local IP (Linux)
ip addr show

IPv6 Addressing#

IPv6 address: 128-bit number written as eight groups of four hexadecimal digits.

Example: 2001:0db8:85a3:0000:0000:8a2e:0370:7334

Shortened: 2001:db8:85a3::8a2e:370:7334 (consecutive zeros can be replaced with ::)

IPv4 addresses are exhausted, which is why cloud providers increasingly use IPv6; modern applications should support both.

Many tools default to IPv4, so IPv6 connectivity needs an explicit test.

NAT (Network Address Translation)#

NAT allows multiple devices on a private network to share a single public IP address. Your home router does this.

Where it shows up:

  • Understanding private vs public IPs
  • Debugging connection issues (NAT traversal)
  • Security implications (NAT provides basic firewalling)
  • Cloud environments (VPC networking, NAT gateways)

AWS example: Private subnet instances use NAT Gateway to access internet while remaining unreachable from internet.

Ports & Common Services#

Port Numbers#

Ports identify specific services on a host. Range: 0-65535

Port ranges:

  • Well-known ports (0-1023): Reserved for common services, require root/admin
  • Registered ports (1024-49151): Used by applications
  • Dynamic/Private ports (49152-65535): Temporary ports for client connections

Ports worth knowing:

PortProtocolService
20/21FTPFile Transfer (data/control)
22SSHSecure Shell
25SMTPEmail sending
53DNSDomain Name System
80HTTPWeb traffic
443HTTPSSecure web traffic
465/587SMTPSecure email (SSL/TLS)
3000-Common dev server (Node.js)
3306MySQLDatabase
5432PostgreSQLDatabase
6379RedisCache/database
8080HTTPAlternative HTTP (dev/proxy)
8443HTTPSAlternative HTTPS
27017MongoDBDatabase

Commands for checking what’s using a port:

# Check if port is listening (Linux)
netstat -tuln | grep :443

# See what's using a port
lsof -i :3000

# Test if port is open
nc -zv example.com 443

# Test connection with timeout
timeout 5 bash -c 'cat < /dev/null > /dev/tcp/example.com/443' && echo "Open" || echo "Closed"

Port already in use: find and kill the process:

# Find process using port 3000
lsof -ti:3000

# Kill process using port 3000
kill $(lsof -ti:3000)

# Forcefully kill if needed
kill -9 $(lsof -ti:3000)

Firewalls & Port Security#

Firewalls control which ports are accessible. Security groups in AWS/Azure are essentially firewalls.

Best practices:

  • Only open necessary ports
  • Use specific source IPs when possible (not 0.0.0.0/0)
  • Different rules for internal vs external traffic
  • Document why each port is open

When an API suddenly becomes unreachable, check firewall rules before diving into application code; many hours can be lost debugging “broken” code when it is simply a security group rule blocking traffic.

Load Balancing & Distribution#

Load Balancer Types#

Load balancers distribute traffic across multiple servers for reliability and scalability.

Layer 4 (Transport Layer) Load Balancing:

  • Routes based on IP address and port
  • Fast (no application layer inspection)
  • Protocol-agnostic (works with any TCP/UDP traffic)
  • Good match for high-throughput requirements, non-HTTP protocols, simple round-robin distribution, and WebSocket traffic where sticky sessions are handled elsewhere
  • Examples: AWS Network Load Balancer, HAProxy in TCP mode

Layer 7 (Application Layer) Load Balancing:

  • Routes based on HTTP headers, URL path, cookies
  • Content-based routing
  • SSL termination
  • Good match for path-based routing (/api/* to one service, /admin/* to another), host-based routing across multiple domains on one load balancer, and request or header modification
  • Examples: AWS Application Load Balancer, NGINX, HAProxy in HTTP mode

Load Balancing Algorithms#

Round Robin: Distribute requests equally in sequence. Simple but doesn’t account for server load.

Least Connections: Send to server with fewest active connections. Good for long-lived connections.

IP Hash: Route based on client IP. Same client always goes to same server (session affinity without sticky sessions).

Weighted: Assign weights to servers (for different capacity). Useful during migrations or canary deployments.

Blue/Green deployment:

Load Balancer Config:
- Blue environment: weight 100
- Green environment: weight 0

Deploy to Green, test, then:
- Blue: 90, Green: 10 (canary)
- Blue: 50, Green: 50 (gradual shift)
- Blue: 0, Green: 100 (complete cutover)

Health Checks#

Health checks verify server availability. Load balancer removes unhealthy servers from rotation.

Health check strategies:

  • TCP check: Can connect to port? (minimal check)
  • HTTP check: Returns 200 OK? (application-aware)
  • Deep health check: Query database, check dependencies

Implementation example:

// Simple health check endpoint
app.get('/health', (req, res) => {
  res.status(200).json({ status: 'ok' });
});

// Deep health check
app.get('/health/deep', async (req, res) => {
  try {
    // Check database
    await db.query('SELECT 1');

    // Check Redis
    await redis.ping();

    // Check critical dependencies
    const apiReachable = await checkExternalAPI();

    if (apiReachable) {
      res.status(200).json({
        status: 'healthy',
        dependencies: {
          database: 'ok',
          cache: 'ok',
          externalAPI: 'ok'
        }
      });
    } else {
      throw new Error('External API unreachable');
    }
  } catch (error) {
    res.status(503).json({
      status: 'unhealthy',
      error: error.message
    });
  }
});

Health check failures cause cascading issues: an overly aggressive check marks healthy servers unhealthy, while an overly lenient one leaves unhealthy servers in rotation.

Content Delivery Networks (CDN)#

CDN Basics#

CDN distributes content across geographically distributed edge servers. Clients connect to nearest edge location for faster delivery.

Key concepts:

  • Origin: Your original server
  • Edge location: CDN’s distributed servers
  • Cache: Content stored at edge locations
  • TTL: How long content stays cached
  • Cache invalidation: Removing stale content

What to cache:

  • Static assets (images, CSS, JavaScript)
  • Infrequently changing content
  • Publicly accessible resources

What not to cache:

  • Dynamic, user-specific content
  • Authenticated API responses
  • Real-time data

Cache Control Headers#

Control caching behavior with HTTP headers:

// Cache for 1 year (immutable assets with fingerprints)
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');

// Cache for 1 hour
res.setHeader('Cache-Control', 'public, max-age=3600');

// Don't cache
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate');

// Cache but revalidate
res.setHeader('Cache-Control', 'public, max-age=0, must-revalidate');

Cache-Control directives:

  • public: Can be cached by any cache
  • private: Only client browser can cache (not CDN)
  • no-cache: Revalidate with origin before using cached version
  • no-store: Don’t cache at all
  • max-age: Cache lifetime in seconds
  • immutable: Content will never change (aggressive caching)

Asset fingerprinting:

app-abc123.js  # Hash in filename, cache forever
app.js  # No hash, short cache or no-cache

CDN Gotchas#

Problem: Deployed new version but users see old cached content.

Solutions:

  • Use versioned filenames (app.v2.js or app.abc123.js)
  • Invalidate CDN cache (can cost money, takes time)
  • Lower TTL before deployment

Problem: CDN caching authenticated content.

Solution: Use Cache-Control: private for user-specific content, or include Vary: Authorization header.

SSL/TLS & Certificates#

How SSL/TLS Works#

SSL/TLS provides encryption, authentication, and integrity for network communication.

TLS handshake process (simplified):

  1. Client sends supported cipher suites and TLS version
  2. Server responds with chosen cipher and its certificate
  3. Client verifies certificate (signed by trusted CA)
  4. Client and server exchange keys and establish encrypted connection
  5. Application data flows over encrypted channel

Certificate components:

  • Public key: Used to encrypt data sent to server
  • Private key: Used by server to decrypt data (kept secret)
  • Certificate Authority (CA): Trusted entity that signs certificates
  • Certificate chain: Your cert → Intermediate CA → Root CA

Certificate Types#

Domain Validation (DV): Proves you control the domain. Automated, fast, free (Let’s Encrypt).

Organization Validation (OV): Includes organization verification. More trust, more expensive.

Extended Validation (EV): Highest level of validation. Shows organization name in browser. Most expensive.

Wildcard: Covers all subdomains (*.example.com). Convenient but higher security risk if compromised.

Multi-domain (SAN): Covers multiple specific domains in one certificate.

Practical Certificate Management#

Let’s Encrypt example - Free automated certificates:

# Install certbot
sudo apt-get install certbot

# Get certificate (automated)
sudo certbot certonly --standalone -d example.com -d www.example.com

# Auto-renewal (add to cron)
0 0 * * * certbot renew --quiet

Certificate troubleshooting:

Expired certificate:

# Check certificate expiration
echo | openssl s_client -connect example.com:443 2>/dev/null | \
  openssl x509 -noout -dates

Certificate chain issues:

# Verify certificate chain
openssl s_client -connect example.com:443 -showcerts

# Test with specific CA bundle
curl --cacert /path/to/ca-bundle.crt https://example.com

Wrong domain on certificate:

# Check certificate subject
echo | openssl s_client -connect example.com:443 2>/dev/null | \
  openssl x509 -noout -subject -ext subjectAltName

Self-signed certificates: Fine for development, never for production. Browsers will show warnings.

TLS Best Practices#

  • Use TLS 1.2 or 1.3 (TLS 1.0/1.1 are deprecated)
  • Strong cipher suites (avoid weak ciphers like RC4, DES)
  • Certificate pinning for mobile apps (optional, adds security)
  • Automated renewal (certificates expire, usually 90 days for Let’s Encrypt)
  • HSTS header tells browsers to only use HTTPS
// Enable HSTS
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');

Network Security Basics#

Firewalls#

Firewall filters network traffic based on rules. Can operate at different layers.

Types:

  • Packet filtering: Layer 3/4 (IP, port, protocol)
  • Stateful inspection: Tracks connection state
  • Application firewall: Layer 7 (inspects HTTP, etc.)
  • WAF (Web Application Firewall): Protects against web attacks (SQL injection, XSS)

Cloud firewall equivalents:

  • AWS: Security Groups, Network ACLs, AWS WAF
  • Azure: Network Security Groups, Application Gateway WAF
  • GCP: VPC Firewall Rules, Cloud Armor

Best practice: Defense in depth. Multiple layers of security.

VPN (Virtual Private Network)#

VPN creates encrypted tunnel over public network, making it appear you’re on a private network.

Use cases:

  • Secure remote access to corporate network
  • Accessing geographically restricted services
  • Encrypting traffic on untrusted networks (coffee shop Wi-Fi)

Types:

  • Site-to-Site VPN: Connect two networks (e.g., office to AWS VPC)
  • Remote Access VPN: Individual users connect to network
  • SSL VPN: Browser-based, no client needed
  • IPsec VPN: Traditional, requires client software

Developer perspective: If you’re accessing production systems remotely, you’re likely using VPN. Understand connection requirements and troubleshooting.

Common Attack Vectors#

DDoS (Distributed Denial of Service): Overwhelming a server with traffic; CDN, rate limiting, and auto-scaling absorb it.

Man-in-the-Middle: Intercepting communication; TLS/SSL and certificate validation close that gap.

DNS Hijacking: Redirecting DNS to malicious servers. Mitigation: DNSSEC, trusted DNS providers.

Port Scanning: Discovering open ports. Mitigation: Close unnecessary ports, use firewall.

SQL Injection: Malicious SQL in inputs; parameterized queries and input validation stop it.

XSS (Cross-Site Scripting): Injecting malicious scripts. Mitigation: Output encoding, CSP headers.

Essential Networking Tools#

ping#

Purpose: Test connectivity and measure latency.

# Basic ping
ping example.com

# Limit to 5 packets
ping -c 5 example.com

# Flood ping (testing, requires root)
sudo ping -f example.com

What it tells you:

  • Can you reach the host?
  • What’s the latency?
  • Is there packet loss?

Sample output:

64 bytes from example.com (93.184.216.34): icmp_seq=1 ttl=56 time=15.2 ms
  • time=15.2 ms: Round-trip latency
  • ttl=56: Time to live (hops remaining)

Gotcha: Some servers block ICMP (ping). No response doesn’t always mean server is down.

traceroute / tracepath#

Purpose: Show path packets take to destination.

# Trace route to destination
traceroute example.com

# Alternative (doesn't require root)
tracepath example.com

# Trace with ICMP instead of UDP
traceroute -I example.com

What it tells you:

  • Network path to destination
  • Where latency is introduced
  • Where packets are being dropped

Interpreting results:

 1  192.168.1.1 (192.168.1.1)  1.234 ms
 2  10.0.0.1 (10.0.0.1)  5.678 ms
 3  * * *
 4  example.com (93.184.216.34)  15.2 ms
  • Each line is a hop (router)
  • * * * means hop didn’t respond (often firewalled)
  • Large jump in latency shows bottleneck

curl#

curl transfers data over various protocols and is essential for API testing.

# GET request
curl https://api.example.com/users

# POST with JSON
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"name": "John"}'

# Follow redirects
curl -L https://example.com

# Show response headers
curl -i https://example.com

# Show request/response headers
curl -v https://example.com

# Save response to file
curl -o output.html https://example.com

# Download with progress bar
curl -# -O https://example.com/file.zip

# Test with specific IP (bypass DNS)
curl --resolve example.com:443:93.184.216.34 https://example.com

# Custom headers
curl -H "Authorization: Bearer token123" https://api.example.com

# Measure time breakdown
curl -w "@curl-format.txt" -o /dev/null -s https://example.com

curl timing format file (curl-format.txt):

time_namelookup:  %{time_namelookup}s\n
time_connect:  %{time_connect}s\n
time_appconnect:  %{time_appconnect}s\n
time_pretransfer: %{time_pretransfer}s\n
time_redirect:  %{time_redirect}s\n
time_starttransfer: %{time_starttransfer}s\n
time_total:  %{time_total}s\n

netstat / ss#

Purpose: Network statistics - active connections, listening ports, routing tables.

# Show all listening TCP ports
netstat -tuln

# Show all connections with process info
sudo netstat -tulnp

# Show routing table
netstat -r

# Modern alternative (faster)
ss -tuln

# Show specific port
ss -tuln | grep :443

# Show connections by state
ss -t state established

States you’ll see:

  • LISTEN: Waiting for connections
  • ESTABLISHED: Active connection
  • TIME_WAIT: Connection closed, waiting to ensure closure
  • CLOSE_WAIT: Remote end closed, local end hasn’t yet

Debugging scenario: Too many TIME_WAIT connections? Might need to adjust TCP settings or connection pooling.

nslookup / dig#

Purpose: DNS queries and troubleshooting.

# Basic lookup
nslookup example.com

# Query specific DNS server
nslookup example.com 8.8.8.8

# Dig (more detailed)
dig example.com

# Query specific record type
dig example.com AAAA

# Short answer
dig +short example.com

# Trace DNS resolution
dig +trace example.com

# Reverse lookup
dig -x 93.184.216.34

tcpdump / wireshark#

Purpose: Packet capture and analysis. The ultimate debugging tool for network issues.

# Capture on interface (requires root)
sudo tcpdump -i eth0

# Capture specific port
sudo tcpdump -i eth0 port 443

# Capture and save to file
sudo tcpdump -i eth0 -w capture.pcap

# Read from file
tcpdump -r capture.pcap

# Capture specific host
sudo tcpdump -i eth0 host example.com

# HTTP traffic only
sudo tcpdump -i eth0 -A port 80

tcpdump is the last resort when nothing else helps. You’ll see every packet, which is overwhelming but sometimes necessary.

Wireshark: GUI version of tcpdump with powerful filtering and analysis. Use for deep inspection of saved packet captures.

nc (netcat)#

nc is the Swiss army knife of TCP/UDP connections.

# Test if port is open
nc -zv example.com 443

# Listen on port (simple server)
nc -l 8080

# Connect and send data
echo "Hello" | nc example.com 80

# Chat between two machines
# Machine 1: nc -l 8080
# Machine 2: nc machine1-ip 8080

# Simple HTTP request
printf "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n" | nc example.com 80

telnet#

telnet tests TCP connections without encryption, useful for debugging protocols directly.

# Test SMTP
telnet mail.example.com 25

# Test HTTP
telnet example.com 80
# Then type: GET / HTTP/1.1 [Enter]
#  Host: example.com [Enter]
#  [Enter]

# Test if port is open
telnet example.com 443

Note: Most systems don’t include telnet by default anymore. Use nc instead.

Practical Debugging Scenarios#

Scenario 1: API Timeout#

Problem: API calls timing out randomly.

Debugging approach:

# 1. Check if server is reachable
ping api.example.com

# 2. Check DNS resolution time
time dig api.example.com

# 3. Test connection
curl -w "@curl-format.txt" -o /dev/null https://api.example.com

# 4. Check from different location
# Is it network path issue or server issue?

# 5. Monitor active connections
watch -n 1 'ss -s'

# 6. Check for packet loss
ping -c 100 api.example.com | tail -n 3

Key insight: The timing breakdown from step 3 tells you which layer to inspect next. A slow time_namelookup points at DNS, a slow time_appconnect at TLS, and a slow time_starttransfer back at the application.

Scenario 2: SSL Certificate Error#

Problem: HTTPS connection failing with certificate error.

Debugging approach:

# 1. Check certificate details
echo | openssl s_client -connect example.com:443 -servername example.com

# 2. Check expiration
echo | openssl s_client -connect example.com:443 2>/dev/null | \
  openssl x509 -noout -dates

# 3. Verify certificate chain
curl -v https://example.com

# 4. Check certificate matches domain
echo | openssl s_client -connect example.com:443 2>/dev/null | \
  openssl x509 -noout -text | grep DNS:

# 5. Test with custom CA bundle (if using private CA)
curl --cacert /path/to/ca.crt https://example.com

Scenario 3: DNS Resolution Issues#

Problem: Domain resolving to wrong IP or not resolving at all.

Debugging approach:

# 1. Check what your system resolves to
dig example.com

# 2. Check with different DNS servers
dig @8.8.8.8 example.com  # Google DNS
dig @1.1.1.1 example.com  # Cloudflare DNS
dig @8.8.4.4 example.com  # Google DNS backup

# 3. Clear local DNS cache (Mac)
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder

# 4. Clear local DNS cache (Linux)
sudo systemd-resolve --flush-caches

# 5. Check if it's DNS propagation issue
# Use online tools: whatsmydns.net

# 6. Verify DNS records at authoritative server
dig +trace example.com

DNS issues often appear as intermittent failures because of caching at multiple levels: application, OS, resolver, TTL.

Scenario 4: Port Already in Use#

Problem: Can’t start server - port already in use.

Debugging approach:

# 1. Find what's using the port
lsof -i :3000

# 2. Kill the process
kill $(lsof -ti:3000)

# 3. If kill doesn't work
kill -9 $(lsof -ti:3000)

# 4. Check if port is actually free now
netstat -tuln | grep :3000

# 5. Alternative - use different port or configure port reuse
# In Node.js:
# server.listen(3000, { reuseAddr: true })

Scenario 5: High Latency#

Problem: Application feels slow, debugging where latency comes from.

Measuring with curl:

# Create curl timing format
cat > curl-format.txt << 'EOF'
\n
    time_namelookup:  %{time_namelookup}s\n
       time_connect:  %{time_connect}s\n
    time_appconnect:  %{time_appconnect}s\n
   time_pretransfer:  %{time_pretransfer}s\n
      time_redirect:  %{time_redirect}s\n
 time_starttransfer:  %{time_starttransfer}s\n
                    ----------\n
         time_total:  %{time_total}s\n
\n
EOF

# Measure request timing
curl -w "@curl-format.txt" -o /dev/null -s https://api.example.com

Interpreting results:

  • High time_namelookup: DNS slow
  • High time_connect: Network latency or server not responding
  • High time_appconnect: SSL handshake slow
  • High time_starttransfer: Server processing slow
  • High time_total with low other times: Large response body

A Default Debugging Order#

Work top down: reach the host, resolve the name, complete the TCP handshake, complete the TLS handshake, then read the HTTP response and its timing. curl -w, dig, and ss cover all five checks in seconds, without root access or a capture file. Ruling them out first matters because a failure at any of those layers looks identical from inside your service, showing up as a timeout.

Two situations justify skipping ahead to tcpdump. The first is when the fast tools come back clean and the symptom persists, which usually means something between the endpoints is rewriting or dropping traffic. The second is when the failure is intermittent enough that you need a capture already running when it recurs. Packet capture produces far more data than you want to read.

The habit that pays off outside incidents is writing down which ports are open, why they are open, and which firewall rule allows them.

References#

Related posts