# Networking — The Foundation of Everything This is the most important concept to master. Every other technology in this homelab is built on networking fundamentals. CCNA will teach this deeply — this is the overview. --- ## IP Addresses Every device on a network has an IP address — a unique identifier. **IPv4:** Four numbers 0–255 separated by dots: `192.168.1.205` **Private ranges** (not routable on the internet, only on local networks): - `192.168.x.x` — home networks (your router assigns these) - `172.16.x.x – 172.31.x.x` — Docker bridge networks use this range - `10.x.x.x` — corporate networks often use this **Public IPs:** Routable on the internet. Your home has one (assigned by ISP). kscloud1 has one (assigned by Hetzner). **Tailscale IPs:** `100.x.x.x` — a special private range used by Tailscale for its overlay network. --- ## Subnets and CIDR Notation A subnet is a range of IP addresses. CIDR notation describes the range: - `192.168.1.0/24` — all addresses from `192.168.1.0` to `192.168.1.255` (256 addresses) - `172.16.0.0/12` — a large range covering all Docker bridge networks - `/32` — a single IP address The number after `/` is the prefix length — how many bits are fixed. The remaining bits define the host range. In this homelab: `ufw allow from 172.16.0.0/12` allows traffic from any Docker container to the host. That `/12` covers all possible Docker bridge subnet addresses. --- ## Ports A port is a number (0–65535) that identifies a specific service on a host. Think of the IP address as the building, and the port as the apartment number. **Well-known ports:** - 22 — SSH - 80 — HTTP - 443 — HTTPS - 3306 — MySQL/MariaDB - 5432 — PostgreSQL - 6379 — Redis **Your homelab ports** (just examples — you know yours): - Each service binds to a port inside the container - Docker maps host ports to container ports: `3006:3000` When a service "listens on a port," it's waiting for TCP/UDP connections on that port. When cloudflared connects to `http://grafana:3000`, it's connecting to IP of the `grafana` container on port 3000. --- ## DNS — How Names Become IPs DNS (Domain Name System) translates human-readable names to IP addresses. ``` www.kitestacks.com → DNS lookup → Cloudflare's IP address grafana → Docker DNS → 172.x.x.x (container IP) 100.123.x.x → Tailscale DNS → kscloud1 ``` **Cloudflare DNS:** You configured NS records to point `kitestacks.com` to Cloudflare's nameservers. Cloudflare then controls all DNS for that domain. The A record for `www.kitestacks.com` points to Cloudflare's anycast IP, not your home IP. **Docker DNS:** Inside the `kitestacks` Docker network, Docker runs an internal DNS server at `127.0.0.11`. When cloudflared looks up `homepage`, Docker DNS returns the container's IP on the bridge network. **How to check DNS:** ```bash dig www.kitestacks.com # what does the public DNS say? nslookup grafana # from inside a container ``` --- ## HTTP vs HTTPS **HTTP (HyperText Transfer Protocol):** Data is sent in plain text. Anyone who can see the network traffic can read it. **HTTPS:** HTTP + TLS encryption. Data is encrypted in transit. **TLS (Transport Layer Security):** A cryptographic protocol. Requires a certificate proving the server is who it claims to be. In this homelab: - All internal Docker network traffic is HTTP — it never leaves the host, so encryption isn't needed - All public traffic goes through Cloudflare, which handles TLS — Cloudflare terminates HTTPS at the edge - Between Cloudflare and cloudflared (the tunnel itself), traffic is encrypted by the tunnel protocol **Certificates:** Cloudflare manages TLS certificates for `*.kitestacks.com` automatically — you don't need to configure Let's Encrypt or buy a certificate. --- ## Reverse Proxy A reverse proxy sits in front of services and routes requests to them. ``` Client → Reverse Proxy → Service A ↘ Service B ↘ Service C ``` In this homelab, Cloudflare + cloudflared acts as the reverse proxy: - Receives all inbound HTTPS traffic - Decrypts TLS - Reads the `Host` header (`www.kitestacks.com`, `grafana.kitestacks.com`, etc.) - Routes to the correct container based on the hostname rules you configured nginx (the portal container) is also a reverse proxy — it forwards `/api/*` requests to the metrics API running on the host. --- ## Cloudflare Tunnel — Deep Dive The tunnel replaces the need for port forwarding. Here's exactly what happens: **Setup (happens once when you start cloudflared):** 1. cloudflared reads the TUNNEL_TOKEN 2. It makes an outbound HTTPS connection to Cloudflare's edge servers (`region1.argotunnel.com`) 3. It authenticates and registers as a connector 4. Cloudflare keeps this connection open (persistent, long-lived) **When a request comes in:** 1. User's browser connects to Cloudflare's edge (the public IP in DNS) 2. Cloudflare sees the Host header: `grafana.kitestacks.com` 3. Cloudflare looks up the tunnel configuration — `grafana.kitestacks.com` → `http://grafana:3000` 4. Cloudflare sends the request over the existing tunnel connection to cloudflared 5. cloudflared resolves `grafana` via Docker DNS → gets container IP 6. cloudflared forwards the request to the grafana container 7. Response goes back through the tunnel to Cloudflare → to the user **The key insight:** All of this happens over a single outbound connection from cloudflared. No inbound ports. Your home router doesn't know any of this is happening. --- ## Tailscale — Overlay Network Tailscale creates a WireGuard mesh between devices. Each device gets a `100.x.x.x` IP that works regardless of physical location or network. **Under the hood:** - WireGuard: a modern VPN protocol, UDP-based, very fast, cryptographically simple - Tailscale coordinates key exchange via their servers, but actual traffic is peer-to-peer - Works behind NAT via UDP hole-punching (most of the time) - Falls back to relay servers (DERP) if direct connection isn't possible **Why this matters for the homelab:** - kscloud1's Postgres and Redis bind to `100.123.x.x` (Tailscale IP), not `0.0.0.0` - Even though kscloud1 has a public IP, the database is unreachable from the internet - Only devices on the tailnet can connect to it - Monk's Authentik connects to `100.123.x.x:5432` — traffic goes through the encrypted Tailscale tunnel --- ## Firewall Basics (ufw) ufw (Uncomplicated Firewall) manages Linux's netfilter/iptables rules. ```bash ufw default deny incoming # block all inbound by default ufw allow ssh # allow SSH (port 22) ufw allow from 172.16.0.0/12 to any port 8000 # Docker containers → metrics API ``` On kscloud1: ufw blocks everything by default. The exception for `172.16.0.0/12` allows containers (which use 172.x.x.x addresses) to reach port 8000 on the host (where the metrics API runs in host network mode). Without that rule: the homepage container calls `host.docker.internal:8000` → kernel sees source `172.x.x.x` → ufw blocks it → System Status widget shows "Offline." --- ## What to Know Cold for CCNA - **Subnetting:** Practice calculating subnets. `/24`, `/25`, `/26`, `/27` etc. — know the host ranges by heart. - **OSI Model:** 7 layers. Know what each layer does and what protocols live there. - **TCP vs UDP:** TCP is reliable (handshake, acknowledgements). UDP is fast (no handshake, fire and forget). HTTP uses TCP. DNS uses UDP (mostly). - **The TCP 3-way handshake:** SYN → SYN-ACK → ACK. This is how every TCP connection starts. - **ARP:** How a device finds the MAC address for an IP on the same subnet. - **Default gateway:** The router. Packets destined for outside the local subnet go to the default gateway. - **NAT:** Network Address Translation. How your home router lets multiple devices share one public IP. Crucial to understand — it's why cloudflared uses outbound connections. --- ## What to Say About Networking > *"The homelab uses Cloudflare Tunnel for all inbound traffic, which means no ports are open on the home router. All nine public subdomains have DNS pointing to Cloudflare, and a cloudflared connector on each host maintains a persistent outbound tunnel. Internally, services communicate over a Docker bridge network using container DNS. A Tailscale overlay network connects monk and kscloud1 for private database access — the shared Authentik Postgres is bound only to the Tailscale interface so it's never exposed to the public internet."*