Networking Ssl Mastery

Category: DevOps & Infrastructure | Read: 12 min | v1.0.0

Networking & SSL/TLS Mastery

1. DNS Deep-Dive

DNS Resolution Flow

Browser requests ──→ Local cache ──→ OS cache ──→ Router cache ──→ ISP DNS
                                                              │
                                                         Recursive query
                                                              │
                                              ┌───────────────┼───────────────┐
                                              ↓               ↓               ↓
                                         Root NS        TLD NS (.com)   Authoritative NS
                                              │               │               │
                                         Referral        Referral        ANSWER (A/AAAA/CNAME)

DNS Record Types Quick Reference

| Type | Purpose | Example | |------|---------|---------| | A | IPv4 address | @ IN A 1.2.3.4 | | AAAA | IPv6 address | @ IN AAAA 2001:db8::1 | | CNAME | Alias | www IN CNAME example.com | | MX | Mail server | @ IN MX 10 mail.example.com | | TXT | Text/spf/dkim | @ IN TXT "v=spf1 include:_spf.google.com ~all" | | SRV | Service record | _sip._tcp IN SRV 10 60 5060 sip.example.com | | NS | Name server | @ IN NS ns1.example.com | | CAA | Certificate auth | @ IN CAA 0 issue "letsencrypt.org" |

DNS Troubleshooting

# Query specific DNS server
dig @8.8.8.8 example.com A +short
dig @8.8.8.8 example.com MX +short
dig @8.8.8.8 example.com CNAME +short

Trace resolution path

dig +trace example.com

Reverse DNS lookup

dig -x 1.2.3.4

Check DNS propagation

dnsviz.net # Online tool

Or use multiple resolvers

for dns in 8.8.8.8 1.1.1.1 9.9.9.9; do echo "=== $dns ===" && dig @$dns example.com A +short done

Flush local DNS cache

systemd-resolve --flush-caches # systemd-resolved rndc flush # BIND

2. Reverse Proxy Patterns

Decision Tree

Need a reverse proxy? ─┬─ HTTP routing + SSL ──→ Nginx (most common)
                          ├─ API gateway + rate limiting ──→ Kong / Traefik
                          ├─ TCP/UDP load balancing ──→ HAProxy
                          └─ Service mesh (microservices) ──→ Envoy + Istio

Nginx Reverse Proxy (Production)

# /etc/nginx/sites-available/api.myapp.com
upstream api_backend {
    least_conn;
    server 10.0.1.1:8080 max_fails=3 fail_timeout=30s;
    server 10.0.1.2:8080 max_fails=3 fail_timeout=30s;
    server 10.0.1.3:8080 backup;
    keepalive 32;
}

Rate limiting zone

limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s; limit_req_zone $binary_remote_addr zone=auth:10m rate=5r/m;

Security headers

add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self'" always;

server {
listen 443 ssl http2;
server_name api.myapp.com;

# SSL Configuration
ssl_certificate /etc/letsencrypt/live/api.myapp.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.myapp.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/api.myapp.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;

# HSTS (31536000s = 1 year)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# Logging
access_log /var/log/nginx/api_access.log json_combined;
error_log /var/log/nginx/api_error.log warn;

location / {
limit_req zone=api burst=200 nodelay;
proxy_pass http://api_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
proxy_send_timeout 30s;
}

location /auth/ {
limit_req zone=auth burst=10 nodelay;
proxy_pass http://api_backend;
# ... same proxy headers
}

# Health check
location /health {
proxy_pass http://api_backend/health;
access_log off;
}
}

HTTP → HTTPS redirect

server { listen 80; server_name api.myapp.com; return 301 https://$host$request_uri; }

HAProxy TCP Proxy (Database)

frontend mysql_front
    bind *:3306
    default_backend mysql_back

backend mysql_back
balance leastconn
option mysql-check user haproxy_check
server mysql1 10.0.1.1:3306 check inter 5s rise 3 fall 2
server mysql2 10.0.1.2:3306 check inter 5s rise 3 fall 2 backup

3. TLS Termination & Certificate Management

TLS 1.3 Handshake Flow

Client                                          Server
  │─── ClientHello (supported versions,    ──→│
  │    cipher suites, key_share)              │
  │                                            │
  │←── ServerHello (chosen cipher,             │
  │     key_share, certificate)             ────│
  │                                            │
  │─── Finished (encrypted) ──────────────────→│
  │←── Finished (encrypted) ──────────────────│
  │                                            │
  │════════ Encrypted Application Data ════════│

Let's Encrypt with certbot

# Install certbot
apt install certbot python3-certbot-nginx

Get certificate (standalone)

certbot certonly --standalone -d api.myapp.com --non-interactive --agree-tos -m admin@myapp.com

Get certificate (dns challenge for wildcard)

certbot certonly --dns-cloudflare \ --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \ -d '*.myapp.com' -d 'myapp.com'

Auto-renewal (already set up by certbot timer)

certbot renew --dry-run # Test renewal

Check certificate info

openssl x509 -in /etc/letsencrypt/live/api.myapp.com/fullchain.pem -noout -text | grep -E 'Subject:|Not Before|Not After'

Wildcard Certificate with DNS Challenge

# /etc/letsencrypt/cloudflare.ini
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN

Issue wildcard cert

certbot certonly \ --dns-cloudflare \ --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \ -d '*.hkuk2.s4s.host' -d 'hkuk2.s4s.host' \ --non-interactive --agree-tos -m admin@s4s.host

Self-Signed Certificate (Internal Services)

# Create private key + certificate
openssl req -x509 -newkey rsa:4096 \
  -keyout internal.key -out internal.crt \
  -days 365 -nodes \
  -subj "/CN=internal.myapp.com/O=MyApp/C=US" \
  -addext "subjectAltName=DNS:internal.myapp.com,DNS:*.internal.myapp.com"

Create CA and sign certificate (for internal PKI)

1. Create CA

openssl genrsa -out ca.key 4096 openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \ -subj "/CN=MyApp Internal CA/O=MyApp/C=US"

2. Create CSR

openssl genrsa -out service.key 2048 openssl req -new -key service.key -out service.csr \ -subj "/CN=api.internal.myapp.com/O=MyApp/C=US"

3. Sign with CA

openssl x509 -req -days 365 -in service.csr -CA ca.crt -CAkey ca.key \ -CAcreateserial -out service.crt \ -extfile <(echo "subjectAltName=DNS:api.internal.myapp.com")

4. Cloudflare CDN & Edge

Cloudflare Configuration

# Cloudflare API: Set SSL mode to "Full (Strict)"
curl -X PATCH "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/settings/ssl" \
  -H "Authorization: Bearer ${CF_TOKEN}" \
  -H "Content-Type: application/json" \
  --data '{"value":"strict"}'

Cache rules for API

curl -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/pagerules" \ -H "Authorization: Bearer ${CF_TOKEN}" \ --data '{ "targets": [{"target":"url","constraint":{"operator":"matches","value":"api.myapp.com/v1/*"}}], "actions": [{"id":"cache_level","value":"bypass"}], "priority": 1 }'

Purge cache

curl -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/purge_cache" \ -H "Authorization: Bearer ${CF_TOKEN}" \ --data '{"purge_everything":true}'

Cloudflare Nginx Origin Config

# Real IP restoration behind Cloudflare
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
real_ip_header CF-Connecting-IP;

5. Firewall & Network Security

UFW (Ubuntu)

# Default policies
ufw default deny incoming
ufw default allow outgoing

Allow SSH (from specific IPs only)

ufw allow from 10.0.1.0/24 to any port 22 proto tcp ufw allow from 203.0.113.50 to any port 22 proto tcp # Office IP

Allow web

ufw allow 80/tcp ufw allow 443/tcp

Allow specific services

ufw allow from 10.0.1.0/24 to any port 3306 proto tcp # MySQL from app servers ufw allow from 10.0.1.0/24 to any port 5432 proto tcp # PostgreSQL from app servers ufw allow from 10.0.1.0/24 to any port 6379 proto tcp # Redis from app servers

Rate limit SSH

ufw limit 22/tcp

Enable

ufw enable ufw status verbose

iptables (Advanced)

# Block common attacks
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 --rttl --name SSH -j DROP

SYN flood protection

iptables -A INPUT -p tcp --syn -m limit --limit 1/s --limit-burst 3 -j ACCEPT iptables -A INPUT -p tcp --syn -j DROP

Block known bad IPs

iptables -A INPUT -s 1.2.3.4 -j DROP

Save rules

iptables-save > /etc/iptables/rules.v4

6. Flowcharts & Decision Diagrams

SSL/TLS Problem Decision Tree

SSL problem? ─┬─ Certificate expired ──→ Auto-renew with certbot, check cron timer
                ├─ Certificate not trusted ──→ Install full chain (cert + intermediate)
                ├─ Mixed content ──→ Replace all http:// with https:// in HTML/JS
                ├─ HSTS issues ──→ Check preload status, clear browser HSTS cache
                ├─ SNI not configured ──→ Add server_name in nginx, check ssl_preread
                ├─ Weak ciphers ──→ Update ssl_ciphers to Mozilla Modern profile
                └─ OCSP error ──→ Enable ssl_stapling, check resolver in nginx

DNS Problem Decision Tree

DNS not resolving? ─┬─ NXDOMAIN ──→ Check DNS records exist at authoritative NS
                       ├─ SERVFAIL ──→ Check DNSSEC, nameserver connectivity
                       ├─ Timeout ──→ Check firewall allows UDP/TCP 53
                       ├─ Wrong answer ──→ Check TTL expired, flush caches
                       └─ Works from some locations ──→ Propagation delay (wait for TTL)

Network Troubleshooting Flowchart

Can't connect? ─┬─ ping fails ──→ Firewall, routing, host down
                   ├─ ping works, port fails ──→ Service not listening, firewall
                   ├─ Connection refused ──→ Service not running or wrong port
                   ├─ Connection timeout ──→ Firewall DROP, routing issue
                   ├─ Connection reset ──→ Service crashed, IDS/IPS blocking
                   └─ Works from localhost ──→ Firewall/iptables rule blocking external

7. Testing Strategy

SSL/TLS Testing

# Test SSL configuration (Qualys SSL Labs alternative)

Using testssl.sh

git clone https://github.com/drwetter/testssl.sh.git cd testssl.sh ./testssl.sh -E https://api.myapp.com

Quick SSL check with openssl

openssl s_client -connect api.myapp.com:443 -servername api.myapp.com /dev/null | openssl x509 -noout -dates -subject -issuer

Check specific TLS version

openssl s_client -connect api.myapp.com:443 -tls1_3 /dev/null | grep "Protocol"

DNS resolution test across providers

for resolver in 8.8.8.8 1.1.1.1 9.9.9.9; do echo "=== $resolver ===" && dig @$resolver api.myapp.com A +short done

Network Performance Testing

# Bandwidth test with iperf3
iperf3 -s          # On server
iperf3 -c server-ip -t 30 -P 4   # On client (4 parallel streams, 30s)

Latency test

ping -c 100 api.myapp.com | tail -1

MTR (combined traceroute + ping)

mtr --report api.myapp.com

TCP connection stats

ss -s # Summary ss -tlp # Listening TCP sockets ss -s | grep -E 'estab|timewait'

8. Performance Optimization

Nginx Tuning

# /etc/nginx/nginx.conf
worker_processes auto;
worker_rslimit_nofile 100000;

events {
worker_connections 4096;
use epoll;
multi_accept on;
}

http {
# Keep-alive
keepalive_timeout 65;
keepalive_requests 100000;

# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 4;
gzip_min_length 256;
gzip_types text/plain text/css application/json application/javascript text/xml;

# Buffer sizes
client_body_buffer_size 16K;
client_header_buffer_size 1k;
client_max_body_size 64m;
large_client_header_buffers 4 8k;

# File cache
open_file_cache max=10000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;

# Upstream keepalive
upstream api_backend {
server 10.0.1.1:8080;
keepalive 32;
}
}

DNS Performance Optimization

# Use local DNS cache (systemd-resolved)

/etc/systemd/resolved.conf

[Resolve] DNS=8.8.8.8 1.1.1.1 FallbackDNS=9.9.9.9 Cache=yes CacheFromLocal=yes DNSOverTLS=opportunistic

Security & Encryption

TLS Certificate Chain Validation

# Verify full trust chain
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt \
  -untrusted /etc/letsencrypt/live/api.myapp.com/chain.pem \
  /etc/letsencrypt/live/api.myapp.com/cert.pem

Check certificate SANs (critical for multi-domain certs)

openssl x509 -in cert.pem -noout -text | grep -A1 "Subject Alternative Name"

Generate DH params (for DHE cipher suites — use ECDHE instead when possible)

openssl dhparam -out /etc/nginx/dhparam.pem 2048

Automated Certificate Monitoring

#!/bin/bash

/usr/local/bin/check-certs.sh — alert 30 days before expiry

ALERT_DAYS=30

for cert in /etc/letsencrypt/live/*/fullchain.pem; do
domain=$(basename $(dirname $cert))
expiry=$(openssl x509 -in "$cert" -noout -enddate | cut -d= -f2)
days_left=$(( ( $(date -d "$expiry" +%s) - $(date +%s) ) / 86400 ))

if [ "$days_left" -lt "$ALERT_DAYS" ]; then
echo "⚠️ Certificate for $domain expires in $days_left days!" | \
mail -s "CERT EXPIRY: $domain" admin@myapp.com
fi
done

Deployment Strategies

Nginx Blue-Green Switch

#!/bin/bash

/usr/local/bin/blue-green-switch.sh

ENV=$1 # "blue" or "green"

Health check target first

curl -sf http://10.0.1.$([ "$ENV" = "blue" ] && echo "1" || echo "2"):8080/health || { echo "❌ $ENV environment health check failed!"; exit 1 }

Update upstream in nginx

sed -i "s/server 10.0.1.[12]/server 10.0.1.$([ "$ENV" = "blue" ] && echo "1" || echo "2")/" \ /etc/nginx/conf.d/upstream.conf

nginx -t && nginx -s reload
echo "✅ Switched to $ENV environment"

Automated SSL Renewal + Deploy

#!/bin/bash

/etc/letsencrypt/renewal-hooks/deploy/reload-services.sh

set -e

Reload nginx to pick up new certs

systemctl reload nginx

Reload any other services using certs

systemctl reload postfix 2>/dev/null || true systemctl reload dovecot 2>/null || true

Send notification

curl -s -X POST "$SLACK_WEBHOOK" \ -H 'Content-Type: application/json' \ -d '{"text":"✅ SSL certificate renewed and services reloaded"}'

Zero-Downtime Database Migration

# pt-online-schema-change handles this for MySQL

For PostgreSQL: use CREATE + INSERT + RENAME pattern

Step 1: Create new table alongside old

psql -c "CREATE TABLE orders_v2 (LIKE orders INCLUDING ALL);"

Step 2: Add new columns to v2

psql -c "ALTER TABLE orders_v2 ADD COLUMN priority INTEGER DEFAULT 0;"

Step 3: Backfill in batches (avoid locking)

for offset in $(seq 0 10000 $(psql -t -c "SELECT COUNT(*) FROM orders")); do psql -c "INSERT INTO orders_v2 SELECT *, 0 FROM orders ORDER BY id OFFSET $offset LIMIT 10000 ON CONFLICT DO NOTHING;" sleep 1 # Let replication catch up done

Step 4: Swap tables in a transaction

psql -c "BEGIN; ALTER TABLE orders RENAME TO orders_old; ALTER TABLE orders_v2 RENAME TO orders; COMMIT;"

Step 5: Drop old table after verification

psql -c "DROP TABLE orders_old;"

Performance Optimization — Protocol & Caching

  • TLS 1.3 0-RTT — reduce handshake latency by 100ms+ on repeat connections
  • OCSP Stapling — eliminate CA roundtrip during TLS handshake
  • HTTP/2 Multiplexing — single connection, multiple streams, no head-of-line blocking
  • DNS Prefetch
  • TCP Fast Opennet.ipv4.tcp_fastopen=3 on both client and server
  • Best Practices

  • Always use Full (Strict) SSL mode with Cloudflare — origin cert + Cloudflare cert
  • Enable HTTP/2 everywhere — single connection multiplexing
  • Set HSTS with preload — max-age=31536000, includeSubDomains
  • Use OCSP stapling — reduces TLS handshake latency by 100-300ms
  • Rate-limit auth endpoints at edge — 5-10 req/min for login, 100 req/s for API
  • Monitor certificate expiry — alert 30 days before renewal
  • Use DNS challenge for wildcard certs — easier than HTTP challenge for internal domains
  • Separate internal and external DNS — split-horizon DNS for security
  • Real IP restoration — always configure set_real_ip_from behind CDN/proxy
  • Test SSL configuration regularly — testssl.sh monthly, update cipher suite annually
  • 10. Common Pitfalls

    | # | Pitfall | Impact | Fix |
    |---|---------|--------|-----|
    | 1 | Missing intermediate cert | Browser shows untrusted | Use fullchain.pem, not cert.pem |
    | 2 | Not restoring real IP | All traffic appears from proxy | Set real_ip_header CF-Connecting-IP |
    | 3 | HTTP→HTTPS redirect loop | Cloudflare "too many redirects" | Set SSL mode to Full (Strict) |
    | 4 | DNS TTL too high | Can't failover quickly | Set TTL to 300-300s for critical records |
    | 5 | Not rate-limiting SSH | Brute force attacks | ufw limit 22/tcp or fail2ban |
    | 6 | Mixed content warnings | Browser blocks resources | Replace all http:// in HTML with https:// |
    | 7 | Weak DH parameters | Logjam attack | Use 2048-bit+ DH params or ECDHE only |
    | 8 | Not monitoring cert expiry | Service goes down | certbot renew --dry-run + monitoring |
    | 9 | DNS cache poisoning | Wrong IP responses | Enable DNSSEC, use trusted resolvers |
    | 10 | Proxy buffers too small | 502 errors on large responses | Increase proxy_buffer_size to 16k |

    11. Quick Reference

    # Check SSL cert details
    openssl x509 -in /etc/letsencrypt/live/domain/fullchain.pem -noout -dates -issuer
    

    Test TLS version and ciphers

    openssl s_client -connect domain:443 -tls1_3 /dev/null | grep "Cipher"

    Nginx config test and reload

    nginx -t && nginx -s reload

    Firewall: check rules

    ufw status numbered iptables -L -n -v --line-numbers

    DNS: check propagation

    dig domain A +short @8.8.8.8

    Cloudflare: purge cache

    curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE/purge_cache" \ -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ -d '{"purge_everything":true}'

    Network: check connections

    ss -tlnp | grep nginx # Listening ports ss -s # Connection summary