Warming up the neural circuits...
By the end of this chapter you will:
DNS is the phonebook of the internet. SSL/TLS is the envelope that keeps your letter private. Together, they're the foundation of trust on the web — and when they break, your entire product is invisible or branded "Not Secure" by every browser.
You want to send a confidential letter to a friend in another city. You need three things:
Their address (DNS): You look up "Raj Patel, Mumbai" in a directory. The directory says: Building 42, Tech Park, Andheri East, Mumbai 400093. Without this lookup, the post office has no idea where to send your letter.
A trusted courier (SSL/TLS): You don't write your credit card number on a postcard that every postal worker can read. You seal it in a tamper-evident envelope. If anyone opens it in transit, you'll know. TLS is that envelope — it encrypts your data and detects tampering.
Identity verification (Certificate Authorities): Before you seal the envelope, you verify you're sending to the real Raj Patel, not an imposter. You call a mutual friend who vouches: "Yes, Raj lives at that address. Here's his public key to seal the envelope." Certificate Authorities (Let's Encrypt, DigiCert) are that mutual friend — they verify domain ownership before issuing certificates.
Now imagine every website visit is a letter. Billions of letters per day. The DNS system handles the addressing for all of them. The TLS system handles the encryption. When either fails — wrong DNS record, expired certificate — the letter never arrives or arrives with "WARNING: NOT SECURE" stamped on it in red.
This chapter is about making sure your letters always arrive, always encrypted, and always trusted.
DNS (Domain Name System) translates human-readable names (api.yourapp.com) into machine-readable IP addresses (142.250.80.46). It's the largest distributed database on Earth, and understanding its record types is non-negotiable for backend engineers.
# The DNS resolution chain for api.yourapp.com
# 1. Your local machine checks its DNS cache
# 2. If not cached, it asks the recursive resolver (usually your ISP or 8.8.8.8)
# 3. The resolver asks a ROOT nameserver: "Who handles .com?"
# 4. Root responds: "Ask the .com TLD nameserver at [IP]"
# 5. The resolver asks the .com TLD: "Who handles yourapp.com?"
# 6. TLD responds: "Ask ns1.digitalocean.com at [IP]" (your authoritative nameserver)
# 7. The resolver asks ns1.digitalocean.com: "What's the IP for api.yourapp.com?"
# 8. Your nameserver responds: "142.250.80.46" (the A record)
| Record | Purpose | Example | When to use |
|---|---|---|---|
| A | Maps domain → IPv4 address | api.yourapp.com → 142.250.80.46 | Pointing your domain at a VPS with a static IPv4 |
| AAAA | Maps domain → IPv6 address | api.yourapp.com → 2607:f8b0:: | IPv6 support (increasingly required for mobile networks) |
| CNAME | Maps domain → another domain (alias) | www.yourapp.com → yourapp.com | Pointing a subdomain at a or endpoint |
| MX | Mail server for the domain | yourapp.com → mail.google.com (priority 10) | Setting up email (Gmail, Outlook, custom mail server) |
| TXT | Arbitrary text data | v=spf1 include:_spf.google.com ~all | SPF/DKIM/DMARC (email auth), domain verification, ACME challenges |
| NS | Authoritative nameservers | yourapp.com → ns1.digitalocean.com | Delegating DNS management to a provider |
| SRV | Service location (host + port) | _sip._tcp.yourapp.com → sipserver:5060 | Non-HTTP services (SIP, LDAP, XMPP) |
| CAA | Which CAs can issue certs | yourapp.com → 0 issue "letsencrypt.org" | Restricting certificate issuance (critical security record) |
You CANNOT set a CNAME record at the apex (root) of your domain (yourapp.com). RFC 1034 forbids it because a CNAME cannot coexist with other records (like MX or NS records, which the apex must have). If your provider says "point your domain at our load balancer," they must give you an IP for an A record, or use an ALIAS/ANAME record (provider-specific, non-standard but widely supported). This trips up every developer the first time they try to point a root domain at a CDN.
TTL (Time To Live) tells resolvers how long to a DNS record. Lower TTL means faster propagation of changes. Higher TTL means less DNS traffic and faster resolution (cache hit).
# Check current TTL for a record
$ dig +short api.yourapp.com
# 142.250.80.46
$ dig api.yourapp.com | grep -E "^\s+[0-9]+"
# api.yourapp.com. 300 IN A 142.250.80.46
# ^^^ TTL = 300 seconds (5 minutes)
# Strategy for migration:
# 1. Lower TTL to 60s at least 1 TTL before migration
# 2. Migrate the record
Before any DNS migration, drop the TTL to 30-60 seconds at least as long as the current TTL before the switch. If your TTL is 3600s (1 hour), you need to lower it at least 1 hour before migration. Otherwise, resolvers that cached the old value won't check for the new one until their cache expires — and some users will hit the old IP for up to an hour after you switch.
TLS (Transport Layer Security) is what puts the "S" in HTTPS. Understanding the handshake matters because it's the primary source of perceived latency for first-time visitors.
Client Server
| |
|--- ClientHello ------------->| "I support TLS 1.3, these ciphers, here's a random number"
| |
|<--- ServerHello -------------| "Let's use TLS 1.3 + AES-256-GCM. Here's my certificate + random number"
| |
|--- Certificate verification | Client verifies: cert signed by trusted CA? Not expired? Domain matches?
| |
|--- Key exchange ------------->| (TLS 1.3: 0-RTT — data starts flowing immediately)
|<--- Finished -----------------|
| |
|===Encrypted Application Data==| All subsequent data encrypted with symmetric session keys
TLS 1.2: 2 round trips (ClientHello → ServerHello → ClientKeyExchange → Finished) = ~100-300ms
TLS 1.3: 1 round trip (ClientHello → ServerHello+Finished) = ~50-100ms
TLS 1.3 + 0-RTT (session resumption): 0 round trips = ~5msLet's Encrypt is a Certificate Authority that issues free, automated TLS certificates. Certbot is the client that requests and installs them.
# Install certbot (Ubuntu/Debian)
sudo apt update && sudo apt install certbot python3-certbot-nginx -y
# Issue and install certificate automatically (modifies Nginx config)
sudo certbot --nginx -d api.yourapp.com -d www.yourapp.com
# Certificate files installed at:
# /etc/letsencrypt/live/yourapp.com/fullchain.pem (cert + chain)
# /etc/letsencrypt/live/yourapp.com/privkey.pem (private key — NEVER share)
#
Wildcard certs (*.yourapp.com) cover all subdomains with a single certificate. They require DNS-01 challenge (proving you control DNS, not just the web server):
# Wildcard certs require DNS challenge (HTTP challenge doesn't support wildcards)
sudo certbot certonly \
--manual \
--preferred-challenges dns \
-d '*.yourapp.com' \
-d yourapp.com
# Certbot will prompt you to create a TXT record:
# _acme-challenge.yourapp.com → "abc123def456..."
# Add this TXT record at your DNS provider, wait for propagation, press Enter
# For automated renewal with DNS plugins:
#
A wildcard cert for *.yourapp.com covers api.yourapp.com, cdn.yourapp.com, but NOT internal.api.yourapp.com. Wildcards match exactly one . For deep subdomains, you need either additional specific certs or a cert for *.api.yourapp.com.
HTTP Strict Transport Security tells browsers: "Never connect to this domain over HTTP. Always use HTTPS."
# In your Nginx server block:
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# max-age=63072000: 2 years in seconds
# includeSubDomains: applies to all subdomains too
# preload: submit to Google's HSTS preload list (browsers ship with this list)
# Danger: Once HSTS is set with a long max-age, browsers will REFUSE to connect
# over HTTP. If your TLS breaks (expired cert), your site is completely unreachable
# for the duration of the max-age. Start with max-age=300 (5 min) for testing.server {
listen 80;
server_name api.yourapp.com;
# Permanent redirect (301) — tells search engines and browsers to remember
return 301 https://$server_name$request_uri;
}
# If you have many domains, use a catch-all:
server {
listen 80 default_server;
server_name _;
return 301 https://$host$
Let's Encrypt certs expire in 90 days. Auto-renewal is NOT optional:
# Check renewal timer
sudo systemctl status certbot.timer
# If not active, enable it:
sudo systemctl enable --now certbot.timer
# Test renewal works
sudo certbot renew --dry-run
# Add a post-renewal hook to reload Nginx
# /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh:
#!/bin/bash
systemctl reload
An expired certificate is a hard outage. Browsers show a full-page warning with "Your connection is not private" and a "Back to safety" . Users can technically click through ("Advanced → Proceed anyway"), but most don't. Your site is effectively down. The cause: certbot timer wasn't enabled after server reboot, firewall blocked outbound port 80 (needed for HTTP-01 challenge), or DNS records changed. Always monitor cert expiration with external monitoring (UptimeRobot, Better Uptime, or a cron job: openssl s_client -connect api.yourapp.com:443 2>/dev/null | openssl x509 -noout -enddate).
yourapp.com → Marketing site (Netlify/Vercel)
api.yourapp.com → Backend API (VPS with Nginx)
cdn.yourapp.com → Static assets (S3 + CloudFront)
admin.yourapp.com → Admin panel (separate deploy)
ws.yourapp.com → WebSocket server (special Nginx config)
*.yourapp.com → Wildcard for dev/staging environmentsEach subdomain can have different TLS configurations, different backend servers, and different security postures. The subdomain is your unit of deployment isolation at the DNS level.
Stripe processes payments for millions of businesses. Their SSL/TLS infrastructure handles billions of requests daily with near-zero latency overhead:
Certificate transparency: Every certificate Stripe uses is logged to Certificate Transparency (CT) logs. This means any mis-issued certificate is publicly visible and detectable. Stripe monitors CT logs for their domains — if a certificate appears that they didn't request, it's an immediate security incident.
CAA records are mandatory: Stripe uses CAA DNS records to restrict which Certificate Authorities can issue certificates for stripe.com. This prevents a compromised or rogue CA from issuing a valid certificate for their domain. Every production domain at Stripe has a CAA record.
TLS version enforcement: Stripe's only accepts TLS 1.2 and above. Attempts to connect with TLS 1.0 or 1.1 are rejected. This is enforced at their load balancer level — the application never sees insecure connections.
The lesson: SSL/DNS configuration isn't a one-time setup task. It's an ongoing security posture that requires monitoring (certificate expiry), verification (CT logs), and restriction (CAA records). Treat your TLS configuration with the same rigor as your application code.
| Mistake | Why it's wrong | What to do instead |
|---|---|---|
| Forgetting to enable certbot auto-renewal | Certificate expires after 90 days. Your site shows "Not Secure" errors. Users bounce | sudo systemctl enable --now certbot.timer. Verify with sudo systemctl status certbot.timer |
| Using CNAME at the apex domain | RFC violation. Breaks MX records. Some providers silently convert it, others reject it outright | Use an A record (if static IP) or ALIAS/ANAME (if your DNS provider supports it) for the apex |
Setting max-age=63072000 for HSTS without testing first | If TLS breaks, browsers refuse HTTP connections for 2 years. Your site is unreachable | Start with max-age=300 (5 min) for testing. Increase to 2 years only after verifying TLS is stable |
| Using HTTP-01 challenge when port 80 is blocked by firewall | Certbot can't complete the challenge. Certificate issuance fails silently until the old cert expires | Use DNS-01 challenge (works with blocked ports) or ensure port 80 is open from the internet during renewal |
| Copy-pasting SSL config without understanding ciphers | Old ciphers (RC4, 3DES, CBC-mode) are vulnerable. Misconfigured ciphers mean TLS that's "on" but insecure | Use Mozilla's SSL Configuration Generator. Choose "Modern" for TLS 1.3 only or "Intermediate" for TLS 1.2+ compatibility |
| Pointing MX records at a web server IP | Email sent to your domain bounces. Your web server isn't configured to receive email | MX records must point at a mail server (Gmail, Outlook, or self-hosted). Use dig MX yourdomain.com to verify |
| Not monitoring certificate expiry externally | Your monitoring runs from the same server as your app. If the server is down, you don't get alerted about the cert either | Use external monitoring services (UptimeRobot, Better Uptime, SSL Labs API) to check cert expiry from outside your infrastructure |
0 issue "letsencrypt.org"). This prevents certificate mis-issuance — a leading cause of phishing attacks. If you change CAs later, update the CAA record first, then request the new certificate.tar -czf ssl-backup.tar.gz /etc/letsencrypt/ && gpg --encrypt --recipient admin@yourapp.com ssl-backup.tar.gz.ssl_early_data on; in Nginx. The tradeoff: 0-RTT data is replayable (an attacker can capture and resend 0-RTT data). Never put mutating operations (POST, PUT, DELETE) in 0-RTT data.ssl_stapling on;), Nginx fetches the OCSP response periodically and includes it in the TLS handshake, eliminating the browser's separate OCSP request.systemd-resolved or dnsmasq as a local DNS cache. Every outbound connection from your backend (database, Redis, external APIs) involves a DNS lookup. Caching reduces these lookups from 50ms to <1ms and reduces load on your DNS provider.privkey.pem file is the crown jewel of your TLS setup. Anyone with this file can impersonate your domain. Use chmod 600 on private key files. Use environment-specific keys (dev gets a self-signed cert or a separate Let's Encrypt subdomain cert), never copy production keys to development.api.yourapp.com issued by a CA you don't use is a security incident — someone may have compromised domain .Set up DNS records for a test domain: Purchase a cheap domain ($1-5 on Namecheap or Porkbun) or use a free subdomain service. Configure: an A record pointing @ to your VPS IP, a CNAME record for www pointing to @, and an MX record pointing to a mail provider. Verify all records with dig and nslookup. Document the TTL values and explain why you chose them.
Issue your first Let's Encrypt certificate: On a VPS with Nginx running, use certbot to issue and install a certificate. Verify HTTPS works in a browser. Check the certificate details (issuer, expiry, subject) using browser dev tools. Run certbot certificates to see your installed certificates and their expiry dates.
Set up a wildcard certificate with DNS challenge: Using certbot with a DNS plugin (Cloudflare, DigitalOcean, or Route53), issue a wildcard certificate for *.yourdomain.com. Configure Nginx to use it for three subdomains (api, admin, cdn). Verify all three work over HTTPS. Write a script that tests renewal automatically and alerts if renewal fails.
Configure HSTS and security headers: Add HSTS (max-age=63072000; includeSubDomains; preload) to your Nginx config AFTER testing with max-age=300. Add X-Frame-Options, X-Content-Type-Options, and Referrer-Policy headers. Use curl -I https://yourdomain.com to verify all headers are present. Test with SSL Labs Server Test and achieve an A+ rating.
Implement certificate monitoring and alerting: Write a monitoring script (Python or Bash) that: checks certificate expiry for all your domains (using openssl s_client), alerts via email/Slack at 30, 14, and 7 days before expiry, checks CT logs via crt.sh API for unexpected certificates, and verifies CAA records are present and correct. Deploy this on a $5 VPS separate from your main infrastructure.
Design a multi-region DNS failover strategy: Your application serves users globally from two regions (us-east-1 and eu-west-1). Design a DNS configuration using latency-based or geo-based routing (Route53 or Cloudflare) that routes users to the nearest healthy region. Handle: normal operation (geo-routing), regional outage (automatic failover), and DNS TTL strategy during failover. Document how long failover takes and how much traffic is lost during the TTL window.
Q: What's the difference between an A record and a CNAME record?
A: An A record maps a domain directly to an IPv4 address (e.g., api.yourapp.com → 142.250.80.46). A CNAME maps a domain to another domain name (e.g., www.yourapp.com → yourapp.com). The key practical difference: CNAMEs can't exist at the apex (root) of a domain because a CNAME can't coexist with other required records like MX or NS. A records work everywhere. CNAMEs are useful for aliases — point www at the root, point cdn at your CloudFront distribution URL, etc.
Q: How does Let's Encrypt verify domain ownership before issuing a certificate?
A: Let's Encrypt uses the ACME protocol with challenges. HTTP-01 challenge: the CA provides a token, you place it at http://yourdomain.com/.well-known/acme-challenge/<token>, the CA verifies it can fetch that token. DNS-01 challenge: you create a TXT record at _acme-challenge.yourdomain.com with the token value, the CA verifies via DNS lookup. HTTP-01 proves you control the web server. DNS-01 proves you control the DNS. DNS-01 is required for wildcard certificates.
Q: What happens when a TLS certificate expires? A: Browsers refuse to establish a secure connection. The user sees a full-page warning: "Your connection is not private" (Chrome) or "Warning: Potential Security Risk Ahead" (Firefox). They can technically bypass it ("Advanced → Proceed anyway"), but the experience is hostile and most users leave. On the server side, API clients that validate certificates (most HTTP libraries do by default) will reject the connection. Your application is effectively offline until the certificate is renewed.
Q: Explain the TLS 1.3 handshake and why it's faster than TLS 1.2. A: TLS 1.3 reduces the handshake from 2 round trips to 1 round trip. In TLS 1.2: ClientHello → ServerHello+Certificate → ClientKeyExchange+ChangeCipherSpec → ServerFinished. That's 2 RTTs (~100-300ms). In TLS 1.3: ClientHello (with key share) → ServerHello+Certificate+Finished (encrypted). That's 1 RTT (~50-100ms). With 0-RTT resumption (sending encrypted application data in the ClientHello), it's effectively 0 RTTs (~5ms). TLS 1.3 also removes obsolete cryptographic primitives (RSA key exchange, CBC-mode ciphers, SHA-1 hashes, RC4, 3DES) and makes forward secrecy mandatory — every connection uses ephemeral Diffie-Hellman key exchange, so compromising the server's long-term private key doesn't decrypt past sessions.
Q: How would you handle a situation where your TLS certificate expires in 2 hours and certbot renewal is failing?
A: First, triage: is it a Let's Encrypt outage, a firewall issue, or a DNS problem? Check certbot logs (/var/log/letsencrypt/letsencrypt.log) for the specific error. Common fixes: (1) Port 80 is blocked — temporarily open it for HTTP-01 challenge, or switch to DNS-01 challenge if your DNS provider has an API. (2) Rate limit — Let's Encrypt limits duplicate certificate issuances to 5 per week per domain. If you've hit the limit, use the staging environment to debug, then request a production cert after the rate limit resets (check crt.sh for exact timing). (3) DNS record missing/wrong — the _acme-challenge TXT record might have been removed. Re-add it. (4) As a last resort, manually request a certificate from a different CA (ZeroSSL offers free certs too) and install it manually — this buys time to fix Let's Encrypt. (5) Post-incident: set up monitoring to alert at 30 days, not 2 hours.
Q: Design a DNS architecture that supports canary deployments — routing 5% of traffic to a new version of your API.
A: DNS alone can't do percentage-based routing (it can do geo-routing and failover, but not weighted splits). The architecture needs a traffic management layer: (1) Use a cloud load balancer (AWS ALB, Cloudflare Load Balancer) that supports weighted routing. Configure two target groups: api-v1 (95%) and api-v2 (5%). (2) For a DNS-only approach: create two A records, pointing at the v2 servers, and use application-level logic (feature flag, cookie, or random sampling) to send 5% of users to the canary endpoint. (3) For a more sophisticated approach: use a service mesh (Istio, Linkerd) with traffic splitting rules at the envoy/sidecar level. The core principle: DNS is for service discovery ("where is this service?"), not traffic management ("how much traffic goes where?"). Separate these concerns. Use DNS to point at a load balancer or API gateway, and use the gateway for weighted routing.
DNS is the internet's distributed phonebook — A records for IPs, CNAMEs for aliases, MX for email, TXT for verification and security policies. TTL controls how fast changes propagate; lower it before migrations. TLS is what makes HTTPS secure — TLS 1.3 handshakes are twice as fast as TLS 1.2. Let's Encrypt provides free automated certificates via certbot; DNS-01 challenge unlocks wildcard certs. Auto-renewal is non-negotiable — an expired cert is a hard outage. HSTS forces HTTPS and prevents downgrade attacks, but demands careful rollout. Subdomains are deployment isolation units; each can have independent TLS, backends, and security policies. CAA records restrict which CAs can issue certs for your domain. Certificate Transparency monitoring catches mis-issuance. The bottom of the — DNS and TLS — is boring until it breaks, at which point it becomes the only thing that matters.
sudo certbot --nginx -d domain.com issues and installs. certbot renew --dry-run tests renewal.sudo systemctl enable --now certbot.timer is NOT optional. Expired cert = site offline.*.domain.com) require DNS-01 challenge. HTTP-01 doesn't support wildcards.max-age=300 for testing, then max-age=63072000 for production.openssl s_client -connect domain:443 | openssl x509 -noout -enddate checks cert expiry.Which DNS record type maps a domain to an IPv4 address? A) A record B) CNAME record C) MX record D) TXT record
Why can't you set a CNAME at the apex (root) of a domain? A) It's too expensive B) A CNAME cannot coexist with other required records like MX and NS at the apex C) CNAMEs only work with HTTPS D) ISPs block apex CNAMEs
What happens if certbot's auto-renewal timer isn't enabled? A) The certificate auto-extends B) The certificate expires after 90 days — your site shows "Not Secure" errors C) Let's Encrypt sends a reminder email D) Nginx automatically self-signs a replacement
How many round trips does a TLS 1.3 handshake take (vs TLS 1.2's 2 round trips)? A) 3 round trips B) 1 round trip C) 0 round trips D) Same as TLS 1.2
What challenge type does a wildcard certificate (*.domain.com) require?
A) HTTP-01 B) DNS-01 C) TLS-ALPN-01 D) Email verification
What does HSTS with max-age=63072000 enforce?
A) The certificate is valid for 2 years B) Browsers must use HTTPS for this domain for 2 years — HTTP connections are refused C) DNS records are cached for 2 years D) Passwords must be at least 8 characters
You see an unexpected certificate for your domain on crt.sh. What should you do? A) Ignore it — crt.sh shows test certificates too B) Investigate immediately — it could indicate domain validation compromise or unauthorized certificate issuance C) Delete the crt.sh entry D) Renew your own certificate
api-canary.yourapp.com