调试 DNS 解析、网络连接和 HTTP 问题。涵盖 dig/nslookup、端口测试、防火墙规则、curl 诊断、/etc/hosts、代理配置和证书故障排除。
适用场景
- DNS 名称无法解析或解析到错误 IP
- 连接被拒绝/连接超时错误
- 诊断防火墙或安全组规则
- HTTP 请求因不明原因失败
- 代理配置问题
- SSL/TLS 证书错误
- 测试服务间连通性
DNS 调试
查询 DNS 记录
# A 记录(IP 地址)
dig example.com
dig +short example.com# 特定记录类型
dig example.com MX # 邮件服务器
dig example.com CNAME # 别名
dig example.com TXT # 文本记录(SPF、DKIM 等)
dig example.com NS # 名称服务器
dig example.com AAAA # IPv6 地址
dig example.com SOA # 起始授权
# 查询特定 DNS 服务器
dig @8.8.8.8 example.com
dig @1.1.1.1 example.com
# 追踪完整解析路径
dig +trace example.com
# 反向查找(IP → 主机名)
dig -x 93.184.216.34
# nslookup(更简单,全平台可用)
nslookup example.com
nslookup example.com 8.8.8.8 # 查询特定服务器
nslookup -type=MX example.com
# host(最简单)
host example.com
host -t MX example.com
检查 DNS 传播
# 查询多个公共 DNS 服务器
for dns in 8.8.8.8 1.1.1.1 9.9.9.9 208.67.222.222; do
echo -n "$dns: "
dig +short @"$dns" example.com
done# 检查 TTL(生存时间)
dig example.com | grep -E '^\S+\s+\d+\s+IN\s+A'
# 数字是 TTL 秒数
本地 DNS 问题
# 检查 /etc/resolv.conf(系统使用的 DNS 服务器)
cat /etc/resolv.conf# 检查 /etc/hosts(本地覆盖)
cat /etc/hosts
# 刷新 DNS 缓存
# macOS:
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
# Linux (systemd-resolved):
sudo systemd-resolve --flush-caches
# Windows:
ipconfig /flushdns
# 检查 systemd-resolved 是否运行(Linux)
resolvectl status
/etc/hosts 模式
# /etc/hosts — 本地 DNS 覆盖(无 TTL,即时生效)# 将域名指向 localhost(用于开发)
127.0.0.1 myapp.local
127.0.0.1 api.myapp.local
# 屏蔽域名
0.0.0.0 ads.example.com
# 测试迁移(DNS 修改前将域名指向新服务器)
203.0.113.50 example.com
203.0.113.50 www.example.com
# 一个 IP 对应多个名称
192.168.1.100 db.local redis.local cache.local
端口和连通性测试
测试端口是否开放
# nc (netcat) — 最可靠
nc -zv example.com 443
nc -zv -w 5 example.com 80 # 5 秒超时# 测试多个端口
for port in 22 80 443 5432 6379; do
nc -zv -w 2 example.com $port 2>&1
done
# /dev/tcp(bash 内置,无需额外工具)
timeout 3 bash -c 'echo > /dev/tcp/example.com/443' && echo "开放" || echo "关闭"
# curl(同时测试 HTTP)
curl -sI -o /dev/null -w "%{http_code}" https://example.com
# 从 Docker 容器内部测试
docker exec my-container nc -zv db 5432
网络路径诊断
# traceroute(显示网络跳数)
traceroute example.com# mtr(持续 traceroute 带统计——最适合发现丢包)
mtr example.com
mtr -r -c 20 example.com # 报告模式,20 个包
# ping
ping -c 5 example.com
# 显示本地网络接口
ip addr show # Linux
ifconfig # macOS / 旧版 Linux
# 显示路由表
ip route show # Linux
netstat -rn # macOS
route -n # Linux(旧版)
检查监听端口
# 哪个进程在哪个端口监听(Linux)
ss -tlnp
ss -tlnp | grep :8080# macOS
lsof -i -P -n | grep LISTEN
lsof -i :8080
# 旧版 Linux
netstat -tlnp
netstat -tlnp | grep :8080
# 哪个进程在使用端口
lsof -i :3000
fuser 3000/tcp # Linux
curl 诊断
详细请求检查
# 完整详细输出(请求头、TLS 握手、时间)
curl -v https://api.example.com/endpoint# 显示时间分解
curl -o /dev/null -s -w "
DNS: %{time_namelookup}s
连接: %{time_connect}s
TLS: %{time_appconnect}s
TTFB: %{time_starttransfer}s
总计: %{time_total}s
状态码: %{http_code}
大小: %{size_download} bytes
" https://api.example.com/endpoint
# 仅显示响应头
curl -sI https://api.example.com/endpoint
# 跟随重定向并显示每一步
curl -sIL https://example.com
# 将域名解析到特定 IP(绕过 DNS)
curl --resolve example.com:443:203.0.113.50 https://example.com
# 使用特定网络接口
curl --interface eth1 https://example.com
调试常见 HTTP 问题
# 测试不同 HTTP 版本
curl --http1.1 https://example.com
curl --http2 https://example.com# 测试特定 TLS 版本
curl --tlsv1.2 https://example.com
curl --tlsv1.3 https://example.com
# 忽略证书错误(仅调试用)
curl -k https://self-signed.example.com
# 发送自定义 Host 头(虚拟主机)
curl -H "Host: example.com" https://203.0.113.50/
# 测试 CORS 预检
curl -X OPTIONS -H "Origin: http://localhost:3000" \
-H "Access-Control-Request-Method: POST" \
-v https://api.example.com/endpoint
防火墙基础
iptables(Linux)
# 列出所有规则
sudo iptables -L -n -v# 允许 80 端口入站
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# 允许特定 IP 入站
sudo iptables -A INPUT -s 203.0.113.0/24 -p tcp --dport 22 -j ACCEPT
# 阻止端口入站
sudo iptables -A INPUT -p tcp --dport 3306 -j DROP
# 保存规则(重启后持久化)
sudo iptables-save > /etc/iptables/rules.v4
ufw(更简单,Ubuntu/Debian)
# 启用
sudo ufw enable# 允许/拒绝
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 203.0.113.0/24 to any port 22
sudo ufw deny 3306
# 查看状态
sudo ufw status verbose
# 重置所有规则
sudo ufw reset
macOS 防火墙
# 查看状态
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate# 启用
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on
# 允许应用
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --add /usr/local/bin/myapp
代理配置
环境变量
# 为大多数 CLI 工具设置代理
export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080
export NO_PROXY=localhost,127.0.0.1,.internal.example.com# 专门为 curl 设置
export http_proxy=http://proxy.example.com:8080 # 小写也有效
# 带认证
export HTTPS_PROXY=http://user:password@proxy.example.com:8080
通过代理测试
# curl 显式指定代理
curl -x http://proxy.example.com:8080 https://httpbin.org/ip# SOCKS 代理
curl --socks5 localhost:1080 https://httpbin.org/ip
# 通过代理验证外部 IP
curl -x http://proxy:8080 https://httpbin.org/ip
curl https://httpbin.org/ip # 与直连对比
# 测试代理连通性
curl -v -x http://proxy:8080 https://example.com 2>&1 | grep -i "proxy\|connect"
常见代理问题
# Node.js fetch/undici 不遵循 HTTP_PROXY
# 使用 undici ProxyAgent 或带 http-proxy-agent 的 node-fetch# Git 通过代理
git config --global http.proxy http://proxy:8080
git config --global https.proxy http://proxy:8080
# 移除:
git config --global --unset http.proxy
# npm 通过代理
npm config set proxy http://proxy:8080
npm config set https-proxy http://proxy:8080
# pip 通过代理
pip install --proxy http://proxy:8080 package-name
证书故障排除
# 从服务器检查证书
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
openssl x509 -noout -subject -issuer -dates# 检查过期时间
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -enddate
# 下载证书链
openssl s_client -showcerts -connect example.com:443 < /dev/null 2>/dev/null | \
awk '/BEGIN CERT/,/END CERT/' > chain.pem
# 对照 CA 证书包验证证书
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt server.pem
# 检查特定主机名的证书(SNI)
openssl s_client -connect cdn.example.com:443 -servername cdn.example.com
# 常见错误:"certificate has expired"
# 检查服务器上的日期:
date
# 如果系统时钟不正确,证书会显示无效
快速诊断脚本
#!/bin/bash
# net-check.sh — 快速网络诊断
TARGET="${1:?用法: net-check.sh <主机名> [端口]}"
PORT="${2:-443}"echo "=== 网络检查: $TARGET:$PORT ==="
echo -n "DNS 解析: "
IP=$(dig +short "$TARGET" | head -1)
[[ -n "$IP" ]] && echo "$IP" || echo "失败"
echo -n "Ping: "
ping -c 1 -W 3 "$TARGET" > /dev/null 2>&1 && echo "正常" || echo "失败(可能被阻止)"
echo -n "端口 $PORT: "
nc -zv -w 5 "$TARGET" "$PORT" 2>&1 | grep -q "succeeded\|open" && echo "开放" || echo "关闭/被过滤"
if [[ "$PORT" == "443" || "$PORT" == "8443" ]]; then
echo -n "TLS: "
echo | openssl s_client -connect "$TARGET:$PORT" -servername "$TARGET" 2>/dev/null | \
grep -q "Verify return code: 0" && echo "有效" || echo "无效/错误"
echo -n "证书过期时间: "
echo | openssl s_client -connect "$TARGET:$PORT" 2>/dev/null | \
openssl x509 -noout -enddate 2>/dev/null | sed 's/notAfter=//'
fi
echo "=== 完成 ==="
技巧
dig +short 是命令行检查 DNS 最快的方式。使用 @8.8.8.8 绕过本地缓存。
nc -zv 是最简单的端口连通性测试。如果 nc 不可用,使用 bash 的 /dev/tcp。
- curl 的
-w 格式字符串配合时间变量是诊断慢 HTTP 请求最快的方式:DNS、连接、TLS 和 TTFB 都可见。
- DNS 变更根据 TTL 传播。在期望 DNS 变更生效前,先用
dig 检查当前 TTL。
/etc/hosts 修改立即生效(无 TTL,无传播延迟)。用于在修改 DNS 前测试域名迁移。
- 调试"连接被拒绝"时:先用
nc 验证端口是否开放,再用 ss -tlnp 或 lsof -i 检查服务是否在监听。
mtr 比 traceroute 更适合诊断丢包——它持续运行并显示每跳的丢包百分比。
- Node.js、Python
requests 和许多库不会自动使用 HTTP_PROXY 环境变量。检查每个工具的代理文档。
Debug DNS resolution, network connectivity, and HTTP issues. Covers dig/nslookup, port testing, firewall rules, curl diagnostics, /etc/hosts, proxy configuration, and certificate troubleshooting.
When to Use
- DNS name not resolving or resolving to wrong IP
- Connection refused / connection timed out errors
- Diagnosing firewall or security group rules
- HTTP requests failing for unclear reasons
- Proxy configuration issues
- SSL/TLS certificate errors
- Testing connectivity between services
DNS Debugging
Query DNS records
# A record (IP address)
dig example.com
dig +short example.com# Specific record types
dig example.com MX # Mail servers
dig example.com CNAME # Aliases
dig example.com TXT # Text records (SPF, DKIM, etc.)
dig example.com NS # Name servers
dig example.com AAAA # IPv6 address
dig example.com SOA # Start of Authority
# Query a specific DNS server
dig @8.8.8.8 example.com
dig @1.1.1.1 example.com
# Trace the full resolution path
dig +trace example.com
# Reverse lookup (IP → hostname)
dig -x 93.184.216.34
# nslookup (simpler, works everywhere)
nslookup example.com
nslookup example.com 8.8.8.8 # Query specific server
nslookup -type=MX example.com
# host (simplest)
host example.com
host -t MX example.com
Check DNS propagation
# Query multiple public DNS servers
for dns in 8.8.8.8 1.1.1.1 9.9.9.9 208.67.222.222; do
echo -n "$dns: "
dig +short @"$dns" example.com
done# Check TTL (time to live)
dig example.com | grep -E '^\S+\s+\d+\s+IN\s+A'
# The number is TTL in seconds
Local DNS issues
# Check /etc/resolv.conf (which DNS server the system uses)
cat /etc/resolv.conf# Check /etc/hosts (local overrides)
cat /etc/hosts
# Flush DNS cache
# macOS:
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
# Linux (systemd-resolved):
sudo systemd-resolve --flush-caches
# Windows:
ipconfig /flushdns
# Check if systemd-resolved is running (Linux)
resolvectl status
/etc/hosts patterns
# /etc/hosts — local DNS overrides (no TTL, instant)# Point a domain to localhost (for development)
127.0.0.1 myapp.local
127.0.0.1 api.myapp.local
# Block a domain
0.0.0.0 ads.example.com
# Test a migration (point domain to new server before DNS change)
203.0.113.50 example.com
203.0.113.50 www.example.com
# Multiple names for one IP
192.168.1.100 db.local redis.local cache.local
Port and Connectivity Testing
Test if a port is open
# nc (netcat) — most reliable
nc -zv example.com 443
nc -zv -w 5 example.com 80 # 5 second timeout# Test multiple ports
for port in 22 80 443 5432 6379; do
nc -zv -w 2 example.com $port 2>&1
done
# /dev/tcp (bash built-in, no extra tools needed)
timeout 3 bash -c 'echo > /dev/tcp/example.com/443' && echo "Open" || echo "Closed"
# curl (also tests HTTP)
curl -sI -o /dev/null -w "%{http_code}" https://example.com
# Test from inside a Docker container
docker exec my-container nc -zv db 5432
Network path diagnostics
# traceroute (show network hops)
traceroute example.com# mtr (continuous traceroute with stats — best for finding packet loss)
mtr example.com
mtr -r -c 20 example.com # Report mode, 20 packets
# ping
ping -c 5 example.com
# Show local network interfaces
ip addr show # Linux
ifconfig # macOS / older Linux
# Show routing table
ip route show # Linux
netstat -rn # macOS
route -n # Linux (older)
Check listening ports
# What's listening on which port (Linux)
ss -tlnp
ss -tlnp | grep :8080# macOS
lsof -i -P -n | grep LISTEN
lsof -i :8080
# Older Linux
netstat -tlnp
netstat -tlnp | grep :8080
# Which process is using a port
lsof -i :3000
fuser 3000/tcp # Linux
curl Diagnostics
Verbose request inspection
# Full verbose output (headers, TLS handshake, timing)
curl -v https://api.example.com/endpoint# Show timing breakdown
curl -o /dev/null -s -w "
DNS: %{time_namelookup}s
Connect: %{time_connect}s
TLS: %{time_appconnect}s
TTFB: %{time_starttransfer}s
Total: %{time_total}s
Status: %{http_code}
Size: %{size_download} bytes
" https://api.example.com/endpoint
# Show response headers only
curl -sI https://api.example.com/endpoint
# Follow redirects and show each hop
curl -sIL https://example.com
# Resolve a domain to a specific IP (bypass DNS)
curl --resolve example.com:443:203.0.113.50 https://example.com
# Use a specific network interface
curl --interface eth1 https://example.com
Debug common HTTP issues
# Test with different HTTP versions
curl --http1.1 https://example.com
curl --http2 https://example.com# Test with specific TLS version
curl --tlsv1.2 https://example.com
curl --tlsv1.3 https://example.com
# Ignore certificate errors (debugging only)
curl -k https://self-signed.example.com
# Send request with custom Host header (virtual hosts)
curl -H "Host: example.com" https://203.0.113.50/
# Test CORS preflight
curl -X OPTIONS -H "Origin: http://localhost:3000" \
-H "Access-Control-Request-Method: POST" \
-v https://api.example.com/endpoint
Firewall Basics
iptables (Linux)
# List all rules
sudo iptables -L -n -v# Allow incoming on port 80
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# Allow incoming from specific IP
sudo iptables -A INPUT -s 203.0.113.0/24 -p tcp --dport 22 -j ACCEPT
# Block incoming on a port
sudo iptables -A INPUT -p tcp --dport 3306 -j DROP
# Save rules (persist across reboot)
sudo iptables-save > /etc/iptables/rules.v4
ufw (simpler, Ubuntu/Debian)
# Enable
sudo ufw enable# Allow/deny
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 203.0.113.0/24 to any port 22
sudo ufw deny 3306
# Check status
sudo ufw status verbose
# Reset all rules
sudo ufw reset
macOS firewall
# Check status
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate# Enable
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on
# Allow an application
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --add /usr/local/bin/myapp
Proxy Configuration
Environment variables
# Set proxy for most CLI tools
export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080
export NO_PROXY=localhost,127.0.0.1,.internal.example.com# For curl specifically
export http_proxy=http://proxy.example.com:8080 # lowercase also works
# With authentication
export HTTPS_PROXY=http://user:password@proxy.example.com:8080
Test through proxy
# curl with explicit proxy
curl -x http://proxy.example.com:8080 https://httpbin.org/ip# SOCKS proxy
curl --socks5 localhost:1080 https://httpbin.org/ip
# Verify your external IP through proxy
curl -x http://proxy:8080 https://httpbin.org/ip
curl https://httpbin.org/ip # Compare with direct
# Test proxy connectivity
curl -v -x http://proxy:8080 https://example.com 2>&1 | grep -i "proxy\|connect"
Common proxy issues
# Node.js fetch/undici does NOT respect HTTP_PROXY
# Use undici ProxyAgent or node-fetch with http-proxy-agent# Git through proxy
git config --global http.proxy http://proxy:8080
git config --global https.proxy http://proxy:8080
# Remove:
git config --global --unset http.proxy
# npm through proxy
npm config set proxy http://proxy:8080
npm config set https-proxy http://proxy:8080
# pip through proxy
pip install --proxy http://proxy:8080 package-name
Certificate Troubleshooting
# Check certificate from a server
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
openssl x509 -noout -subject -issuer -dates# Check expiry
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -enddate
# Download certificate chain
openssl s_client -showcerts -connect example.com:443 < /dev/null 2>/dev/null | \
awk '/BEGIN CERT/,/END CERT/' > chain.pem
# Verify a certificate against CA bundle
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt server.pem
# Check certificate for a specific hostname (SNI)
openssl s_client -connect cdn.example.com:443 -servername cdn.example.com
# Common error: "certificate has expired"
# Check the date on the server:
date
# If the system clock is wrong, certs will appear invalid
Quick Diagnostics Script
#!/bin/bash
# net-check.sh — Quick network diagnostics
TARGET="${1:?Usage: net-check.sh [port]}"
PORT="${2:-443}"echo "=== Network Check: $TARGET:$PORT ==="
echo -n "DNS resolution: "
IP=$(dig +short "$TARGET" | head -1)
[[ -n "$IP" ]] && echo "$IP" || echo "FAILED"
echo -n "Ping: "
ping -c 1 -W 3 "$TARGET" > /dev/null 2>&1 && echo "OK" || echo "FAILED (may be blocked)"
echo -n "Port $PORT: "
nc -zv -w 5 "$TARGET" "$PORT" 2>&1 | grep -q "succeeded\|open" && echo "OPEN" || echo "CLOSED/FILTERED"
if [[ "$PORT" == "443" || "$PORT" == "8443" ]]; then
echo -n "TLS: "
echo | openssl s_client -connect "$TARGET:$PORT" -servername "$TARGET" 2>/dev/null | \
grep -q "Verify return code: 0" && echo "VALID" || echo "INVALID/ERROR"
echo -n "Certificate expiry: "
echo | openssl s_client -connect "$TARGET:$PORT" 2>/dev/null | \
openssl x509 -noout -enddate 2>/dev/null | sed 's/notAfter=//'
fi
echo "=== Done ==="
Tips
dig +short is the fastest way to check DNS from the command line. Use @8.8.8.8 to bypass local caching.
nc -zv is the simplest port connectivity test. If nc isn't available, use bash's /dev/tcp.
- curl's
-w format string with timing variables is the fastest way to diagnose slow HTTP requests: DNS, connect, TLS, and TTFB are all visible.
- DNS changes propagate based on TTL. Check the current TTL with
dig before expecting a DNS change to take effect.
/etc/hosts changes take effect immediately (no TTL, no propagation delay). Use it to test domain migrations before changing DNS.
- When debugging "connection refused": first verify the port is open with
nc, then check the service is actually listening with ss -tlnp or lsof -i.
mtr is better than traceroute for diagnosing packet loss — it runs continuously and shows per-hop loss percentages.
- Node.js, Python
requests, and many libraries do NOT automatically use HTTP_PROXY environment variables. Check each tool's proxy documentation.