[{"content":" What is the OSI Model? # The OSI (Open Systems Interconnection) model is a conceptual framework that describes how data moves across a network in 7 layers. Each layer has a specific job and communicates with the layers directly above and below it.\nYou don\u0026rsquo;t need to memorize every detail, but understanding which layer a problem lives at makes troubleshooting dramatically faster.\nThe 7 Layers at a Glance # Layer Name Data Unit Key Function 7 Application Data User-facing protocols (HTTP, DNS, SSH) 6 Presentation Data Encoding, encryption, compression 5 Session Data Connection management, sessions 4 Transport Segment/Datagram End-to-end delivery (TCP, UDP) 3 Network Packet Routing and IP addressing 2 Data Link Frame Local network delivery (MAC addresses) 1 Physical Bits Electrical signals, cables, radio A common mnemonic: Please Do Not Throw Sausage Pizza Away (layers 1–7).\nLayer 1 — Physical # The physical medium that carries signals between devices.\nWhat lives here:\nEthernet cables (Cat5e, Cat6) Fiber optic Wi-Fi radio signals Network interface cards (NICs) Hubs and repeaters Troubleshooting at Layer 1:\n# Check if the network interface is up ip link show # Check cable connection status ethtool eth0 | grep \u0026#34;Link detected\u0026#34; # Wi-Fi signal strength iwconfig wlan0 Common problems: Unplugged cables, damaged connectors, interference on wireless, faulty NICs.\nLayer 2 — Data Link # Handles communication between devices on the same local network using MAC addresses. Splits into two sub-layers:\nLLC (Logical Link Control) — flow control and error detection MAC (Media Access Control) — hardware addressing What lives here:\nSwitches MAC addresses ARP (Address Resolution Protocol) Ethernet frames VLANs Troubleshooting at Layer 2:\n# View MAC address of your interfaces ip link show # View the ARP table (IP → MAC mappings) ip neigh show # Check for ARP resolution arping -I eth0 192.168.1.1 # View VLAN configuration cat /proc/net/vlan/config Common problems: MAC address conflicts, ARP table issues, switch port misconfiguration, VLAN mismatches.\nLayer 3 — Network # Handles routing packets between different networks using IP addresses. This is where data can cross network boundaries.\nWhat lives here:\nIP addresses (IPv4, IPv6) Routers ICMP (ping, traceroute) Subnets and CIDR Routing tables NAT Troubleshooting at Layer 3:\n# Check IP address configuration ip addr show # View routing table ip route show # Test connectivity to a host ping -c 4 8.8.8.8 # Trace the path packets take traceroute 8.8.8.8 # or mtr 8.8.8.8 # Check if a specific route exists ip route get 10.0.0.1 Common problems: Wrong IP/subnet, missing routes, firewall blocking ICMP, NAT misconfiguration.\nLayer 4 — Transport # Provides end-to-end communication between applications on different hosts. Handles reliability and flow control.\nTwo main protocols:\nProtocol Type Use Case TCP Connection-oriented, reliable HTTP, SSH, email, file transfer UDP Connectionless, fast DNS, video streaming, gaming, VoIP TCP connection flow (three-way handshake):\nClient → SYN → Server Client ← SYN-ACK ← Server Client → ACK → Server (connection established) Troubleshooting at Layer 4:\n# Check if a port is open and listening ss -tlnp ss -ulnp # Test TCP connectivity to a specific port nc -zv example.com 443 # View active connections ss -tunap # Check for dropped packets or connection issues netstat -s | grep -i error # Capture TCP handshake sudo tcpdump -i eth0 \u0026#39;tcp[tcpflags] \u0026amp; (tcp-syn|tcp-ack) != 0\u0026#39; -c 20 Common problems: Port not listening, firewall rules, connection timeouts, TCP retransmissions, port exhaustion.\nLayer 5 — Session # Manages sessions between applications — establishing, maintaining, and terminating connections.\nWhat lives here:\nSession establishment and teardown Authentication handshakes TLS/SSL session resumption RPC sessions NetBIOS In practice, this layer is often merged with Layers 6 and 7 in modern networking (TCP/IP model combines them).\nTroubleshooting at Layer 5:\n# Check TLS session details openssl s_client -connect example.com:443 -sess_out /tmp/session.pem # View established sessions ss -o state established Common problems: Session timeouts, authentication failures, TLS handshake errors.\nLayer 6 — Presentation # Handles data formatting so that applications can understand each other. Deals with encoding, encryption, and compression.\nWhat lives here:\nTLS/SSL encryption Character encoding (UTF-8, ASCII) Data serialization (JSON, XML, protobuf) Compression (gzip, brotli) Image formats (JPEG, PNG) Troubleshooting at Layer 6:\n# Check TLS certificate and protocol version openssl s_client -connect example.com:443 \u0026lt;/dev/null 2\u0026gt;/dev/null | openssl x509 -noout -dates -subject # Test TLS with a specific version openssl s_client -connect example.com:443 -tls1_3 # Check what compression/encoding a server supports curl -sI -H \u0026#34;Accept-Encoding: gzip, br\u0026#34; https://example.com | grep -i content-encoding Common problems: Certificate errors, unsupported TLS versions, encoding mismatches, expired certs.\nLayer 7 — Application # The layer closest to the user. Provides network services directly to applications.\nWhat lives here:\nHTTP/HTTPS DNS SSH FTP/SFTP SMTP, IMAP, POP3 DHCP SNMP Troubleshooting at Layer 7:\n# Test HTTP response curl -I https://example.com # Check DNS resolution dig example.com +short # Test SSH connectivity ssh -v user@host # Test SMTP nc -zv mail.example.com 25 # Inspect HTTP headers and timing curl -w \u0026#34;\\nDNS: %{time_namelookup}s\\nConnect: %{time_connect}s\\nTLS: %{time_appconnect}s\\nTotal: %{time_total}s\\n\u0026#34; -o /dev/null -s https://example.com Common problems: Misconfigured services, DNS failures, authentication issues, application bugs, 4xx/5xx HTTP errors.\nEncapsulation: How Data Flows Down the Stack # When you send data, each layer wraps it with its own header:\nApplication: [Data] Transport: [TCP Header][Data] Network: [IP Header][TCP Header][Data] Data Link: [Frame Header][IP Header][TCP Header][Data][Frame Trailer] Physical: 01101001011010... On the receiving end, each layer strips its header and passes the payload up.\nOSI vs TCP/IP Model # The TCP/IP model is what\u0026rsquo;s actually implemented. It simplifies OSI into 4 layers:\nTCP/IP Layer OSI Layers Protocols Application 5, 6, 7 HTTP, DNS, SSH, TLS Transport 4 TCP, UDP Internet 3 IP, ICMP Network Access 1, 2 Ethernet, Wi-Fi, ARP The OSI model is useful for understanding concepts; the TCP/IP model reflects how things actually work.\nTroubleshooting Strategy: Bottom Up # When diagnosing network issues, start at Layer 1 and work up:\n# Layer 1: Is the interface up? ip link show eth0 # Layer 2: Can we reach the gateway\u0026#39;s MAC? arping -c 2 192.168.1.1 # Layer 3: Can we route to the destination? ping -c 4 8.8.8.8 # Layer 4: Is the port reachable? nc -zv example.com 443 # Layer 7: Does the application respond? curl -I https://example.com If ping works but curl doesn\u0026rsquo;t, the problem is above Layer 3. If the link is up but ping fails, focus on Layer 2/3. This approach eliminates variables systematically.\nBest Practices # Troubleshoot bottom-up — confirm each layer before moving to the next Use tcpdump or Wireshark when you need to see exactly what\u0026rsquo;s on the wire Learn the difference between TCP and UDP issues — TCP problems show retransmissions, UDP problems show packet loss silently Remember that most real-world issues live at Layers 3, 4, and 7 Document your network topology — knowing the path packets take saves hours of debugging ","date":"2 June 2026","externalUrl":null,"permalink":"/posts/osi-model-explained/","section":"Posts","summary":"A practical breakdown of the 7 OSI layers, what happens at each one, the protocols involved, and how to troubleshoot at each level.","title":"The OSI Model: Fundamentals","type":"posts"},{"content":" Beyond the Basics # The basics post covered what each OSI layer does. This post covers how they interact in practice — the things that break in production and the tools to diagnose them.\nPacket Captures with tcpdump # tcpdump lets you observe traffic at Layers 2–7 in real time. It\u0026rsquo;s the fastest way to confirm what\u0026rsquo;s actually happening on the wire.\nCapture all traffic on an interface # sudo tcpdump -i eth0 -n Filter by host and port # sudo tcpdump -i eth0 host 10.0.0.5 and port 443 -n Capture to a file for Wireshark analysis # sudo tcpdump -i eth0 -w /tmp/capture.pcap -c 1000 Watch a TCP handshake # sudo tcpdump -i eth0 \u0026#39;tcp[tcpflags] \u0026amp; (tcp-syn) != 0\u0026#39; -n Read specific fields # # Show packet sizes sudo tcpdump -i eth0 -n -l | awk \u0026#39;{print $NF}\u0026#39; # Show only RST packets (connection resets) sudo tcpdump -i eth0 \u0026#39;tcp[tcpflags] \u0026amp; (tcp-rst) != 0\u0026#39; -n What to look for:\nSymptom Likely Layer Cause SYN sent, no SYN-ACK 3/4 Firewall drop, host down, wrong route SYN-ACK received, then RST 4/7 Port closed, application crashed Retransmissions 3/4 Packet loss, congestion, MTU issues Connection established, no data 7 Application-level bug, TLS failure MTU and Fragmentation # MTU (Maximum Transmission Unit) is the largest packet size a link can carry. Standard Ethernet MTU is 1500 bytes.\nWhy MTU matters # When a packet exceeds the link\u0026rsquo;s MTU:\nIf the Don\u0026rsquo;t Fragment (DF) bit is set → packet is dropped, ICMP \u0026ldquo;fragmentation needed\u0026rdquo; is sent back If DF is not set → packet is fragmented into smaller pieces Detecting MTU issues # Path MTU discovery failures are a common cause of mysterious connectivity problems — connections establish (small packets) but hang when transferring data (large packets).\n# Find the path MTU to a host ping -c 4 -M do -s 1472 example.com # If this fails, reduce size until it works ping -c 4 -M do -s 1400 example.com # Check interface MTU ip link show eth0 | grep mtu # Trace path MTU tracepath example.com Common MTU scenarios # Scenario Effective MTU Why Standard Ethernet 1500 Default VPN tunnel (WireGuard) ~1420 Tunnel headers consume space PPPoE (some ISPs) 1492 PPPoE header is 8 bytes Docker overlay network ~1450 VXLAN encapsulation overhead Jumbo frames (datacenter) 9000 Must be configured end-to-end Fixing MTU problems # # Set interface MTU sudo ip link set eth0 mtu 1400 # Persistent (NetworkManager) nmcli connection modify \u0026#34;Wired\u0026#34; 802-3-ethernet.mtu 1400 # Clamp TCP MSS in iptables (fixes MTU issues for TCP without changing MTU) sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu TCP Deep Dive # Connection states # A TCP connection transitions through states. Understanding these helps diagnose stuck connections:\nLISTEN → SYN_RECEIVED → ESTABLISHED → FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED → CLOSE_WAIT → LAST_ACK → CLOSED # Count connections by state ss -ant | awk \u0026#39;{print $1}\u0026#39; | sort | uniq -c | sort -rn TIME_WAIT accumulation # After closing a connection, TCP enters TIME_WAIT for 2×MSL (usually 60 seconds). High-traffic servers can accumulate thousands:\n# Count TIME_WAIT connections ss -ant state time-wait | wc -l # Check system limits cat /proc/sys/net/ipv4/tcp_max_tw_buckets If TIME_WAIT is exhausting ports:\n# Enable socket reuse (safe for clients) sudo sysctl -w net.ipv4.tcp_tw_reuse=1 # Make persistent echo \u0026#34;net.ipv4.tcp_tw_reuse = 1\u0026#34; | sudo tee -a /etc/sysctl.d/99-tcp.conf TCP window size and throughput # TCP window size limits how much data can be in-flight before an acknowledgment. On high-latency links, small windows throttle throughput:\n# Check current TCP buffer sizes sysctl net.ipv4.tcp_rmem sysctl net.ipv4.tcp_wmem # Increase for high-bandwidth links sudo sysctl -w net.ipv4.tcp_rmem=\u0026#34;4096 87380 16777216\u0026#34; sudo sysctl -w net.ipv4.tcp_wmem=\u0026#34;4096 65536 16777216\u0026#34; Retransmissions # Retransmissions indicate packet loss. High retransmission rates degrade performance:\n# Check retransmission stats netstat -s | grep -i retrans # Watch in real time watch -n 1 \u0026#39;netstat -s | grep retrans\u0026#39; # Per-connection retransmissions ss -ti | grep -A1 retrans NAT (Network Address Translation) # NAT rewrites packet headers at Layer 3, allowing multiple devices to share a single public IP.\nTypes of NAT # Type Description Use Case SNAT Rewrites source IP Outbound traffic from private network DNAT Rewrites destination IP Port forwarding, load balancing Masquerade SNAT with dynamic source IP Home routers, VPNs NAT with nftables # # Masquerade outbound traffic sudo nft add table nat sudo nft add chain nat postrouting { type nat hook postrouting priority 100 \\; } sudo nft add rule nat postrouting oifname \u0026#34;eth0\u0026#34; masquerade # Port forward 8080 → internal server:80 sudo nft add chain nat prerouting { type nat hook prerouting priority -100 \\; } sudo nft add rule nat prerouting iifname \u0026#34;eth0\u0026#34; tcp dport 8080 dnat to 192.168.1.10:80 Diagnosing NAT issues # # View active NAT connections sudo conntrack -L # Count NAT table entries sudo conntrack -C # Check if NAT table is full cat /proc/sys/net/netfilter/nf_conntrack_max cat /proc/sys/net/netfilter/nf_conntrack_count # Symptoms of NAT table exhaustion: new connections randomly fail # Fix: increase the limit sudo sysctl -w net.netfilter.nf_conntrack_max=262144 Firewalls Mapped to OSI Layers # Linux firewalls (iptables/nftables) operate across multiple layers:\nChain/Hook OSI Layer What it filters Raw/prerouting 3 Before connection tracking Mangle 3/4 Packet modification (TTL, TOS, MSS) NAT 3/4 Address/port rewriting Filter (input/forward/output) 3/4 Accept/drop decisions nftables examples at different layers # # Layer 3: Block an IP sudo nft add rule inet filter input ip saddr 10.0.0.50 drop # Layer 4: Allow only specific ports sudo nft add rule inet filter input tcp dport { 22, 80, 443 } accept sudo nft add rule inet filter input drop # Layer 4: Rate limit connections sudo nft add rule inet filter input tcp dport 22 ct state new limit rate 3/minute accept # Stateful filtering (Layer 4/5) sudo nft add rule inet filter input ct state established,related accept sudo nft add rule inet filter input ct state invalid drop Diagnosing firewall drops # # Log dropped packets sudo nft add rule inet filter input log prefix \u0026#34;DROPPED: \u0026#34; drop # Watch the log sudo journalctl -f | grep DROPPED # Count drops per chain sudo nft list ruleset | grep -c drop VLAN Trunking (Layer 2/3 Boundary) # VLANs segment a physical network into logical broadcast domains at Layer 2.\nCreating a VLAN interface # # Add VLAN 100 on eth0 sudo ip link add link eth0 name eth0.100 type vlan id 100 sudo ip addr add 10.100.0.1/24 dev eth0.100 sudo ip link set eth0.100 up Inter-VLAN routing # Devices on different VLANs can\u0026rsquo;t communicate at Layer 2. They need a Layer 3 router:\n# Enable IP forwarding (acts as router between VLANs) sudo sysctl -w net.ipv4.ip_forward=1 # Device on VLAN 100 (10.100.0.0/24) can now reach VLAN 200 (10.200.0.0/24) # if this host has interfaces on both VLANs Diagnosing VLAN issues # # Verify VLAN is configured cat /proc/net/vlan/config # Check tagged traffic is arriving sudo tcpdump -i eth0 -e vlan -n # Common problem: switch port not set to trunk mode # You\u0026#39;ll see no traffic on the VLAN interface L4 vs L7 Load Balancing # Load balancers operate at different OSI layers with different tradeoffs:\nLayer 4 (Transport) # Routes based on IP and port. Doesn\u0026rsquo;t inspect content.\nClient → [L4 LB] → Backend ↓ Decision: IP hash, round-robin, least connections Sees: Source/dest IP, source/dest port Doesn\u0026#39;t see: HTTP headers, URLs, cookies Pros: Fast, low overhead, protocol-agnostic Cons: Can\u0026rsquo;t route based on content, no SSL termination\nExample: Linux IPVS\n# Install sudo dnf install ipvsadm # Add virtual service sudo ipvsadm -A -t 10.0.0.1:80 -s rr # Add backends sudo ipvsadm -a -t 10.0.0.1:80 -r 10.0.0.10:80 -m sudo ipvsadm -a -t 10.0.0.1:80 -r 10.0.0.11:80 -m # Check status sudo ipvsadm -L -n Layer 7 (Application) # Inspects application content to make routing decisions.\nClient → [L7 LB] → Backend ↓ Decision: URL path, Host header, cookie, method Sees: Full HTTP request Can: Terminate TLS, rewrite headers, cache Pros: Content-based routing, SSL termination, header manipulation Cons: Higher latency, more resource intensive, protocol-specific\nExample: nginx as L7 load balancer\nupstream api_servers { server 10.0.0.10:8080; server 10.0.0.11:8080; } upstream static_servers { server 10.0.0.20:80; server 10.0.0.21:80; } server { listen 443 ssl; location /api/ { proxy_pass http://api_servers; } location /static/ { proxy_pass http://static_servers; } } When to use which # Requirement Use Simple TCP/UDP distribution L4 Route by URL or header L7 Non-HTTP protocols (database, MQTT) L4 SSL termination L7 Maximum performance L4 A/B testing, canary deploys L7 Best Practices # Capture packets before guessing — tcpdump eliminates speculation Test MTU end-to-end when setting up VPNs or overlay networks Monitor TIME_WAIT and conntrack table size on high-traffic systems Log firewall drops — silent drops are the hardest to troubleshoot Choose load balancer layer based on whether you need content awareness When debugging, correlate layers — a Layer 7 timeout might be caused by Layer 3 packet loss ","date":"2 June 2026","externalUrl":null,"permalink":"/posts/osi-model-intermediate/","section":"Posts","summary":"Deeper networking concepts mapped to OSI layers — packet captures, TCP internals, MTU issues, NAT, firewalls, and L4 vs L7 load balancing.","title":"The OSI Model: Intermediate Concepts","type":"posts"},{"content":" From Understanding to Operating # The fundamentals covered what each layer does. The intermediate post covered how to diagnose issues. This post covers how production systems are architected across the network stack.\nBGP — How the Internet Routes # BGP (Border Gateway Protocol) operates at Layer 3 and is how autonomous systems (ASes) — ISPs, cloud providers, large organizations — exchange routing information.\nWhy it matters # Every time you connect to a website, BGP determines the path your packets take across multiple networks. BGP misconfigurations or hijacks can take down large portions of the internet.\nKey concepts # Term Meaning AS (Autonomous System) A network under single administrative control (e.g., your ISP) AS Number (ASN) Unique identifier for an AS (e.g., AS13335 is Cloudflare) Prefix An IP range advertised via BGP (e.g., 104.16.0.0/12) Peering Direct connection between two ASes Transit Paying another AS to carry your traffic Viewing BGP routes # # Check which AS announces an IP whois -h whois.radb.net 1.1.1.1 # View BGP path to a prefix traceroute -A 1.1.1.1 # Query a route server for BGP info dig +short TXT 1.1.1.1.origin.asn.cymru.com # Returns: \u0026#34;13335 | 1.1.1.0/24 | US | arin | 2014-03-28\u0026#34; BGP on Linux (bird) # For environments where you run your own BGP (datacenters, Kubernetes with MetalLB/Calico):\n# Check BGP session status sudo birdc show protocols # View received routes sudo birdc show route # Check specific prefix sudo birdc show route for 10.0.0.0/24 BGP security concerns # Route hijacking — malicious AS advertises someone else\u0026rsquo;s prefix Route leaks — accidental propagation of routes to unintended networks Mitigation — RPKI (Resource Public Key Infrastructure) validates route origins # Check RPKI validation status of a prefix curl -s https://stat.ripe.net/data/rpki-validation/data.json?resource=AS13335\u0026amp;prefix=1.1.1.0/24 Anycast — One IP, Many Locations # Anycast assigns the same IP address to multiple servers in different geographic locations. The network routes users to the nearest instance.\nHow it works # User in Tokyo → routes to Tokyo server (same IP: 1.1.1.1) User in London → routes to London server (same IP: 1.1.1.1) User in New York → routes to New York server (same IP: 1.1.1.1) BGP makes this possible — each location advertises the same prefix, and routing naturally selects the closest path.\nUse cases # Service Why Anycast DNS (root servers, Cloudflare, Google) Low-latency name resolution worldwide CDNs Serve static content from nearest edge DDoS mitigation Distribute attack traffic across many locations Anycast vs Unicast vs Multicast # Type Description Example Unicast One-to-one, single destination Regular web server Anycast One-to-nearest, same IP at many locations CDN, DNS Multicast One-to-many, group delivery Video streaming, IPTV Broadcast One-to-all on a segment ARP, DHCP discover Verifying anycast behavior # # Same IP resolves to different servers depending on your location dig +short whoami.cloudflare.com @1.1.1.1 # Trace to see which PoP you hit traceroute 1.1.1.1 mtr --report 1.1.1.1 Container Networking — Network Namespaces in Practice # Containers use Linux network namespaces to create isolated network stacks. Understanding this demystifies Docker and Kubernetes networking.\nNetwork namespaces # Each namespace gets its own interfaces, routes, and iptables rules:\n# Create a network namespace sudo ip netns add app1 # List namespaces ip netns list # Run a command inside the namespace sudo ip netns exec app1 ip addr show # Only sees loopback — fully isolated # Create a veth pair (virtual cable between namespaces) sudo ip link add veth-host type veth peer name veth-app1 # Move one end into the namespace sudo ip link set veth-app1 netns app1 # Assign IPs sudo ip addr add 10.0.0.1/24 dev veth-host sudo ip netns exec app1 ip addr add 10.0.0.2/24 dev veth-app1 # Bring interfaces up sudo ip link set veth-host up sudo ip netns exec app1 ip link set veth-app1 up # Test connectivity ping -c 2 10.0.0.2 Docker networking # Docker uses this same mechanism with a bridge:\n# View Docker\u0026#39;s bridge network docker network inspect bridge # See veth pairs connecting containers to the bridge bridge link show # View NAT rules Docker creates sudo iptables -t nat -L -n | grep DOCKER # Debug container DNS docker exec mycontainer cat /etc/resolv.conf Kubernetes networking model # Kubernetes requires:\nEvery Pod gets its own IP Pods can communicate without NAT Nodes can communicate with Pods without NAT CNI plugins (Calico, Cilium, Flannel) implement this differently:\nCNI Plugin Approach Layer Flannel VXLAN overlay L2 over L3 Calico BGP routing L3 Cilium eBPF datapath L3/L4 # View Pod IPs and node assignments kubectl get pods -o wide # Check CNI configuration ls /etc/cni/net.d/ # View routes on a node (Calico) ip route | grep cali # Debug connectivity between pods kubectl exec pod-a -- ping \u0026lt;pod-b-ip\u0026gt; kubectl exec pod-a -- traceroute \u0026lt;pod-b-ip\u0026gt; mTLS — Mutual TLS for Zero Trust # Standard TLS (HTTPS) only verifies the server\u0026rsquo;s identity. mTLS requires both client and server to present certificates — enabling zero-trust service-to-service authentication.\nHow mTLS works # Client Server │ │ ├── ClientHello ───────────────→│ │←── ServerHello + ServerCert ──┤ │←── CertificateRequest ────────┤ (server asks for client cert) ├── ClientCert + Verify ───────→│ (client proves identity) │ │ │←── Encrypted connection ─────→│ (both sides verified) Testing mTLS with curl # # Generate CA openssl req -x509 -newkey rsa:4096 -keyout ca-key.pem -out ca-cert.pem -days 365 -nodes -subj \u0026#34;/CN=MyCA\u0026#34; # Generate server cert openssl req -newkey rsa:4096 -keyout server-key.pem -out server-csr.pem -nodes -subj \u0026#34;/CN=server.local\u0026#34; openssl x509 -req -in server-csr.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -days 365 # Generate client cert openssl req -newkey rsa:4096 -keyout client-key.pem -out client-csr.pem -nodes -subj \u0026#34;/CN=client-app\u0026#34; openssl x509 -req -in client-csr.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -days 365 # Connect with mTLS curl --cacert ca-cert.pem --cert client-cert.pem --key client-key.pem https://server.local:8443/ Where mTLS is used # Service meshes (Istio, Linkerd) — automatic mTLS between all services Kubernetes API server — kubelet ↔ API server communication Database connections — PostgreSQL, MongoDB client certificate auth Zero-trust networks — replace VPN with per-service identity eBPF and XDP — Programmable Packet Processing # eBPF (extended Berkeley Packet Filter) lets you run sandboxed programs in the Linux kernel. XDP (eXpress Data Path) hooks into the network driver for line-rate packet processing.\nWhere eBPF operates in the stack # Packet arrives at NIC → XDP (before kernel networking stack) ← fastest, can drop/redirect → tc (traffic control, after sk_buff allocation) → Netfilter/iptables → Socket layer → Application Practical eBPF networking tools # # Install bcc tools (eBPF toolkit) sudo dnf install bcc-tools # Trace TCP connections in real time sudo tcptracer-bpfcc # Monitor TCP retransmissions sudo tcpretrans-bpfcc # Track TCP connection latency sudo tcpconnlat-bpfcc # Snoop DNS queries without tcpdump sudo gethostlatency-bpfcc Cilium — eBPF-based Kubernetes networking # Cilium replaces iptables with eBPF programs for faster, more observable networking:\n# Check Cilium status cilium status # View eBPF-enforced network policies cilium endpoint list # Monitor packet drops with reason cilium monitor --type drop # Trace a specific flow cilium monitor --from-ip 10.0.0.5 --to-ip 10.0.0.10 Why eBPF matters # Traditional eBPF iptables with thousands of rules → slow O(1) lookup via BPF maps tcpdump captures everything → disk pressure Targeted in-kernel filtering Sidecar proxy per pod → overhead Kernel-level enforcement Service Mesh — L4/L7 Networking Abstraction # A service mesh adds a network proxy alongside each service, handling concerns like routing, observability, and security transparently.\nArchitecture # Service A → [Envoy Sidecar] → network → [Envoy Sidecar] → Service B ↕ ↕ Control Plane (Istio/Linkerd) What the mesh handles by layer # OSI Layer Mesh Feature 7 HTTP routing, retries, header-based traffic splitting 6 mTLS encryption between services 5 Connection pooling, circuit breaking 4 TCP health checks, load balancing Istio traffic management # # Route 90% of traffic to v1, 10% to v2 (canary) apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: my-service spec: hosts: - my-service http: - route: - destination: host: my-service subset: v1 weight: 90 - destination: host: my-service subset: v2 weight: 10 Debugging mesh networking # # Check sidecar proxy status istioctl proxy-status # View Envoy configuration for a pod istioctl proxy-config routes deploy/my-service # Check if mTLS is active between services istioctl authn tls-check my-service.default Network Observability # At production scale, you need visibility across all layers simultaneously.\nDistributed tracing # Traces follow a request across network hops and services:\n# View traces (requires Jaeger/Zipkin) # Each span shows: # - DNS resolution time (L7) # - TCP connection time (L4) # - TLS handshake time (L6) # - Application processing time (L7) Key metrics by layer # Layer What to Monitor Tool 1/2 Link errors, interface drops ethtool -S eth0 3 Route changes, ICMP unreachable ip monitor route 4 Retransmissions, connection states, port exhaustion ss -s, netstat -s 7 Request latency, error rates, throughput Prometheus, application metrics Continuous network monitoring # # Watch for interface errors watch -n 5 \u0026#39;ip -s link show eth0 | grep -E \u0026#34;errors|dropped\u0026#34;\u0026#39; # Monitor conntrack table usage watch -n 5 \u0026#39;cat /proc/sys/net/netfilter/nf_conntrack_count; echo \u0026#34;/\u0026#34;; cat /proc/sys/net/netfilter/nf_conntrack_max\u0026#39; # Alert on TCP retransmissions (quick one-liner) while true; do retrans=$(netstat -s | grep \u0026#34;segments retransmitted\u0026#34; | awk \u0026#39;{print $1}\u0026#39;) echo \u0026#34;$(date): $retrans retransmissions\u0026#34; sleep 60 done # Packet drop reasons (requires dropwatch or perf) sudo dropwatch -l kas Flowlogs and packet metadata # # Capture flow summaries (not full packets) sudo tcpdump -i eth0 -n -q -t | awk \u0026#39;{print $1, $3, $5}\u0026#39; | sort | uniq -c | sort -rn | head -20 # Conntrack flow accounting sudo conntrack -L -o extended | awk \u0026#39;{print $3}\u0026#39; | sort | uniq -c | sort -rn Best Practices # Learn BGP fundamentals even if you don\u0026rsquo;t run it — understanding AS paths helps explain latency and outages Use network namespaces locally to test firewall rules and routing before deploying Implement mTLS between services instead of relying on network perimeter security Consider eBPF-based tools over iptables for high-connection-rate environments Instrument at every layer — a slow HTTP response might be caused by TCP retransmissions, which are caused by MTU issues Treat the network as untrusted by default — zero trust means verifying identity at Layer 6/7 regardless of network position Automate observability — you can\u0026rsquo;t troubleshoot what you can\u0026rsquo;t see ","date":"2 June 2026","externalUrl":null,"permalink":"/posts/osi-model-advanced/","section":"Posts","summary":"Production-level networking — BGP, anycast, container networking, mTLS, eBPF, service meshes, and network observability.","title":"The OSI Model: Advanced Concepts","type":"posts"},{"content":"","date":"5 June 2026","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"","date":"5 June 2026","externalUrl":null,"permalink":"/tags/linux/","section":"Tags","summary":"","title":"Linux","type":"tags"},{"content":"","date":"5 June 2026","externalUrl":null,"permalink":"/","section":"Linux Learning Lab","summary":"","title":"Linux Learning Lab","type":"page"},{"content":"","date":"5 June 2026","externalUrl":null,"permalink":"/posts/","section":"Posts","summary":"","title":"Posts","type":"posts"},{"content":"","date":"5 June 2026","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"},{"content":"","date":"5 June 2026","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"5 June 2026","externalUrl":null,"permalink":"/tags/tutorial/","section":"Tags","summary":"","title":"Tutorial","type":"tags"},{"content":"","date":"5 June 2026","externalUrl":null,"permalink":"/categories/tutorials/","section":"Categories","summary":"","title":"Tutorials","type":"categories"},{"content":"","date":"5 June 2026","externalUrl":null,"permalink":"/tags/vim/","section":"Tags","summary":"","title":"Vim","type":"tags"},{"content":" Why Learn Vim? # Vim is installed on virtually every Linux server, container, and Unix-like system. When you SSH into a production box, edit a crontab, or resolve a git merge conflict — Vim (or its predecessor vi) is there.\nYou don\u0026rsquo;t need to make it your primary editor to benefit from it. Knowing the basics means you\u0026rsquo;re never stuck on a remote machine without a way to edit files.\nOpening and Closing Files # # Open a file vim file.txt # Open at a specific line vim +42 file.txt # Open multiple files vim file1.txt file2.txt Quitting Vim # The commands everyone searches for first:\nCommand Action :q Quit (fails if unsaved changes) :q! Quit without saving :w Save (write) :wq Save and quit ZZ Save and quit (shortcut) ZQ Quit without saving (shortcut) Understanding Modes # Vim is a modal editor — the same keys do different things depending on which mode you\u0026rsquo;re in. This is what makes it confusing at first and powerful once it clicks.\nMode Purpose How to enter Normal Navigate and manipulate text Esc (default mode) Insert Type text i, a, o, etc. Visual Select text v, V, Ctrl-v Command Run commands : The key rule: Press Esc to go back to Normal mode. When in doubt, hit Esc.\nNormal Mode Movement # In Normal mode, you navigate without touching the mouse. Start with these:\nCharacter and line movement # Key Movement h Left j Down k Up l Right These replace arrow keys. Your fingers stay on the home row.\nWord movement # Key Movement w Forward to start of next word b Back to start of current/previous word e Forward to end of current/next word Line movement # Key Movement 0 Beginning of line ^ First non-blank character $ End of line File movement # Key Movement gg Top of file G Bottom of file 42G Go to line 42 Ctrl-d Scroll down half a screen Ctrl-u Scroll up half a screen Entering Insert Mode # From Normal mode, these keys put you into Insert mode at different positions:\nKey Inserts at i Before the cursor a After the cursor I Beginning of the line A End of the line o New line below O New line above Type your text, then press Esc to return to Normal mode.\nBasic Editing in Normal Mode # You don\u0026rsquo;t need to enter Insert mode for every edit. These commands work directly in Normal mode:\nDeleting # Command Action x Delete character under cursor dd Delete entire line dw Delete from cursor to start of next word d$ or D Delete from cursor to end of line Copying (yanking) and pasting # Command Action yy Yank (copy) entire line yw Yank from cursor to start of next word p Paste after cursor P Paste before cursor Undo and redo # Command Action u Undo last change Ctrl-r Redo Other essentials # Command Action r Replace single character under cursor J Join current line with the line below ~ Toggle case of character . Repeat last change Visual Mode (Selecting Text) # Visual mode lets you select text and then act on the selection:\nKey Selection type v Character-wise selection V Line-wise selection Ctrl-v Block (column) selection Once text is selected, you can:\nd — delete the selection y — yank the selection \u0026gt; — indent \u0026lt; — unindent # Example workflow: delete 3 lines V (enter visual line mode) jj (select two more lines) d (delete selection) Putting It Together # Here are some common tasks using what you\u0026rsquo;ve learned:\nDelete a word and type a new one # dw (delete word) i (enter insert mode) ...type replacement... Esc (back to normal mode) Copy a line and paste it below # yy (yank line) p (paste below) Delete everything from the cursor to the end of the file # dG Move to line 10 and delete it # 10G (go to line 10) dd (delete line) Open a file, add a line at the end, save and quit # vim file.txt G (go to end of file) o (new line below, enter insert mode) ...type your text... Esc (back to normal mode) :wq (save and quit) Best Practices # Stay in Normal mode by default — only enter Insert mode when you\u0026rsquo;re actively typing new text Use u liberally — Vim has unlimited undo, so experiment without fear Practice hjkl instead of arrow keys — it\u0026rsquo;s awkward for a day, then faster forever Learn the dot command (.) early — it repeats your last edit and saves enormous time Run vimtutor from your terminal for an interactive 30-minute tutorial built into Vim ","date":"5 June 2026","externalUrl":null,"permalink":"/posts/vim-basics/","section":"Posts","summary":"A practical introduction to Vim — modes, movement, basic editing, and the commands you need to be productive from day one.","title":"Vim Basics: Navigating and Editing","type":"posts"},{"content":" The .vimrc File # Vim reads its configuration from ~/.vimrc on startup. Every setting you apply with :set during a session can be made permanent by adding it to this file.\nvim ~/.vimrc Lines starting with \u0026quot; are comments. Settings take effect immediately when you source the file:\n:source ~/.vimrc Essential Settings # Display # \u0026#34; Show line numbers set number \u0026#34; Show relative line numbers (useful for counts like 5j, 12dd) set relativenumber \u0026#34; Highlight the current line set cursorline \u0026#34; Show matching brackets when cursor is on one set showmatch \u0026#34; Always show the status line set laststatus=2 \u0026#34; Show command as you type it set showcmd \u0026#34; Show current mode in the status line set showmode Search # \u0026#34; Highlight search results set hlsearch \u0026#34; Search as you type (incremental) set incsearch \u0026#34; Case-insensitive search... set ignorecase \u0026#34; ...unless the query contains uppercase letters set smartcase Indentation # \u0026#34; Use spaces instead of tabs set expandtab \u0026#34; Number of spaces per tab set tabstop=4 \u0026#34; Number of spaces for auto-indent set shiftwidth=4 \u0026#34; Insert/delete this many spaces with Tab/Backspace set softtabstop=4 \u0026#34; Auto-indent new lines based on previous line set autoindent \u0026#34; Smart indent for C-like languages set smartindent Behavior # \u0026#34; Allow hidden buffers (switch without saving) set hidden \u0026#34; Don\u0026#39;t create backup files set nobackup set nowritebackup \u0026#34; Don\u0026#39;t create swap files set noswapfile \u0026#34; Use system clipboard set clipboard=unnamedplus \u0026#34; Enable mouse support (useful for scrolling and resizing splits) set mouse=a \u0026#34; Faster updates (for plugins and git gutter) set updatetime=300 \u0026#34; More natural split directions set splitbelow set splitright \u0026#34; Don\u0026#39;t wrap long lines set nowrap \u0026#34; Scroll before reaching the edge set scrolloff=8 \u0026#34; Command-line completion menu set wildmenu set wildmode=longest:list,full Key Mappings # Mappings let you assign custom behavior to keys.\nMapping commands # Command Mode nnoremap Normal mode inoremap Insert mode vnoremap Visual mode cnoremap Command-line mode Always use the noremap variants — they prevent recursive mappings.\nThe leader key # The leader key is a prefix for custom shortcuts. It\u0026rsquo;s \\ by default, but most people remap it to space:\nlet mapleader = \u0026#34; \u0026#34; Now you can create mappings like:\n\u0026#34; Leader+w saves the file nnoremap \u0026lt;leader\u0026gt;w :w\u0026lt;CR\u0026gt; \u0026#34; Leader+q closes the window nnoremap \u0026lt;leader\u0026gt;q :q\u0026lt;CR\u0026gt; Practical mappings # \u0026#34; Clear search highlight with Esc nnoremap \u0026lt;Esc\u0026gt; :nohlsearch\u0026lt;CR\u0026gt; \u0026#34; Move between splits with Ctrl+hjkl nnoremap \u0026lt;C-h\u0026gt; \u0026lt;C-w\u0026gt;h nnoremap \u0026lt;C-j\u0026gt; \u0026lt;C-w\u0026gt;j nnoremap \u0026lt;C-k\u0026gt; \u0026lt;C-w\u0026gt;k nnoremap \u0026lt;C-l\u0026gt; \u0026lt;C-w\u0026gt;l \u0026#34; Move lines up and down in visual mode vnoremap J :m \u0026#39;\u0026gt;+1\u0026lt;CR\u0026gt;gv=gv vnoremap K :m \u0026#39;\u0026lt;-2\u0026lt;CR\u0026gt;gv=gv \u0026#34; Keep visual selection when indenting vnoremap \u0026lt; \u0026lt;gv vnoremap \u0026gt; \u0026gt;gv \u0026#34; Y yanks to end of line (consistent with D and C) nnoremap Y y$ \u0026#34; Keep cursor centered when scrolling nnoremap \u0026lt;C-d\u0026gt; \u0026lt;C-d\u0026gt;zz nnoremap \u0026lt;C-u\u0026gt; \u0026lt;C-u\u0026gt;zz \u0026#34; Keep cursor centered when searching nnoremap n nzzzv nnoremap N Nzzzv Autocommands # Autocommands run actions in response to events:\n\u0026#34; Remove trailing whitespace on save autocmd BufWritePre * %s/\\s\\+$//e \u0026#34; Return to last edit position when opening a file autocmd BufReadPost * \\ if line(\u0026#34;\u0026#39;\\\u0026#34;\u0026#34;) \u0026gt; 0 \u0026amp;\u0026amp; line(\u0026#34;\u0026#39;\\\u0026#34;\u0026#34;) \u0026lt;= line(\u0026#34;$\u0026#34;) | \\ exe \u0026#34;normal! g`\\\u0026#34;\u0026#34; | \\ endif \u0026#34; Set file-specific indentation autocmd FileType python setlocal tabstop=4 shiftwidth=4 autocmd FileType javascript setlocal tabstop=2 shiftwidth=2 autocmd FileType yaml setlocal tabstop=2 shiftwidth=2 A Starter .vimrc # Here\u0026rsquo;s a complete, well-commented starter configuration:\n\u0026#34; ============================================================ \u0026#34; General \u0026#34; ============================================================ set nocompatible \u0026#34; Disable vi compatibility set encoding=utf-8 \u0026#34; UTF-8 encoding set hidden \u0026#34; Allow hidden buffers set nobackup \u0026#34; No backup files set nowritebackup set noswapfile \u0026#34; No swap files set updatetime=300 \u0026#34; Faster updates set mouse=a \u0026#34; Enable mouse \u0026#34; ============================================================ \u0026#34; Display \u0026#34; ============================================================ set number \u0026#34; Line numbers set relativenumber \u0026#34; Relative line numbers set cursorline \u0026#34; Highlight current line set showmatch \u0026#34; Show matching brackets set laststatus=2 \u0026#34; Always show status line set showcmd \u0026#34; Show partial commands set scrolloff=8 \u0026#34; Keep 8 lines visible above/below cursor set signcolumn=yes \u0026#34; Always show sign column set colorcolumn=80 \u0026#34; Mark column 80 syntax enable \u0026#34; Syntax highlighting \u0026#34; ============================================================ \u0026#34; Search \u0026#34; ============================================================ set hlsearch \u0026#34; Highlight matches set incsearch \u0026#34; Incremental search set ignorecase \u0026#34; Case-insensitive... set smartcase \u0026#34; ...unless uppercase is used \u0026#34; ============================================================ \u0026#34; Indentation \u0026#34; ============================================================ set expandtab \u0026#34; Spaces, not tabs set tabstop=4 \u0026#34; Tab width set shiftwidth=4 \u0026#34; Indent width set softtabstop=4 \u0026#34; Backspace through spaces set autoindent \u0026#34; Copy indent from current line set smartindent \u0026#34; Smart auto-indent filetype plugin indent on \u0026#34; File-type specific indentation \u0026#34; ============================================================ \u0026#34; Splits \u0026#34; ============================================================ set splitbelow \u0026#34; Horizontal splits below set splitright \u0026#34; Vertical splits to the right \u0026#34; ============================================================ \u0026#34; Completion \u0026#34; ============================================================ set wildmenu \u0026#34; Command-line completion set wildmode=longest:list,full \u0026#34; ============================================================ \u0026#34; Leader \u0026#34; ============================================================ let mapleader = \u0026#34; \u0026#34; \u0026#34; ============================================================ \u0026#34; Key Mappings \u0026#34; ============================================================ \u0026#34; Save and quit nnoremap \u0026lt;leader\u0026gt;w :w\u0026lt;CR\u0026gt; nnoremap \u0026lt;leader\u0026gt;q :q\u0026lt;CR\u0026gt; \u0026#34; Clear search highlight nnoremap \u0026lt;Esc\u0026gt; :nohlsearch\u0026lt;CR\u0026gt; \u0026#34; Split navigation nnoremap \u0026lt;C-h\u0026gt; \u0026lt;C-w\u0026gt;h nnoremap \u0026lt;C-j\u0026gt; \u0026lt;C-w\u0026gt;j nnoremap \u0026lt;C-k\u0026gt; \u0026lt;C-w\u0026gt;k nnoremap \u0026lt;C-l\u0026gt; \u0026lt;C-w\u0026gt;l \u0026#34; Buffer navigation nnoremap \u0026lt;leader\u0026gt;bn :bn\u0026lt;CR\u0026gt; nnoremap \u0026lt;leader\u0026gt;bp :bp\u0026lt;CR\u0026gt; nnoremap \u0026lt;leader\u0026gt;bd :bd\u0026lt;CR\u0026gt; \u0026#34; Keep visual selection when indenting vnoremap \u0026lt; \u0026lt;gv vnoremap \u0026gt; \u0026gt;gv \u0026#34; Move lines in visual mode vnoremap J :m \u0026#39;\u0026gt;+1\u0026lt;CR\u0026gt;gv=gv vnoremap K :m \u0026#39;\u0026lt;-2\u0026lt;CR\u0026gt;gv=gv \u0026#34; Y yanks to end of line nnoremap Y y$ \u0026#34; Centered scrolling nnoremap \u0026lt;C-d\u0026gt; \u0026lt;C-d\u0026gt;zz nnoremap \u0026lt;C-u\u0026gt; \u0026lt;C-u\u0026gt;zz nnoremap n nzzzv nnoremap N Nzzzv \u0026#34; ============================================================ \u0026#34; Autocommands \u0026#34; ============================================================ \u0026#34; Remove trailing whitespace on save autocmd BufWritePre * %s/\\s\\+$//e \u0026#34; Return to last edit position autocmd BufReadPost * \\ if line(\u0026#34;\u0026#39;\\\u0026#34;\u0026#34;) \u0026gt; 0 \u0026amp;\u0026amp; line(\u0026#34;\u0026#39;\\\u0026#34;\u0026#34;) \u0026lt;= line(\u0026#34;$\u0026#34;) | \\ exe \u0026#34;normal! g`\\\u0026#34;\u0026#34; | \\ endif Neovim Note # If you use Neovim, configuration lives at ~/.config/nvim/init.vim (Vimscript) or ~/.config/nvim/init.lua (Lua). Most Vim settings work identically in Neovim. The Lua configuration path is the modern approach for Neovim-specific features and plugins.\nBest Practices # Start with a minimal .vimrc and add settings as you understand what they do — don\u0026rsquo;t copy a 500-line config you can\u0026rsquo;t debug Use noremap (non-recursive) for all custom mappings to prevent unexpected behavior Set mapleader to space — it\u0026rsquo;s the easiest key to reach and doesn\u0026rsquo;t conflict with built-in commands Use set hidden so you can switch buffers without being forced to save first Enable relative line numbers — they make count-based motions (5j, 12dd) effortless Keep your .vimrc organized with sections and comments — you\u0026rsquo;ll forget why you added something in six months ","date":"5 June 2026","externalUrl":null,"permalink":"/posts/vim-configuration/","section":"Posts","summary":"How to configure Vim with .vimrc — essential settings, key mappings, the leader key, and a practical starter configuration.","title":"Vim Configuration: Making It Yours","type":"posts"},{"content":" The Vim Grammar # Vim commands follow a consistent grammar:\n[count] operator [count] motion/text-object Once you learn a few operators and a few motions, you can combine them freely. This is what makes Vim scale — you\u0026rsquo;re not memorizing hundreds of commands, you\u0026rsquo;re learning a small set of composable pieces.\nOperators # Operators are the \u0026ldquo;verbs\u0026rdquo; — what you want to do to the text:\nOperator Action d Delete c Change (delete and enter Insert mode) y Yank (copy) \u0026gt; Indent right \u0026lt; Indent left = Auto-indent gU Uppercase gu Lowercase An operator on its own does nothing. It waits for a motion or text object to tell it what to act on.\nMotions # Motions are the \u0026ldquo;nouns\u0026rdquo; — they define the range of text:\nMotion Range w Forward to start of next word b Back to start of word e Forward to end of word $ To end of line 0 To beginning of line ^ To first non-blank character gg To top of file G To bottom of file f{char} Forward to next {char} on current line t{char} Forward to just before next {char} } To next blank line (paragraph) { To previous blank line Combining Operators and Motions # The power is in the combination:\nCommand Read as Result dw delete word Deletes from cursor to start of next word d$ delete to end of line Deletes from cursor to end of line d0 delete to beginning Deletes from cursor to beginning of line dG delete to bottom Deletes from cursor to end of file cw change word Deletes word, enters Insert mode c$ change to end of line Deletes to end of line, enters Insert mode y3w yank 3 words Copies the next 3 words \u0026gt;} indent to next paragraph Indents all lines until next blank line gUw uppercase word Uppercases the current word Every new operator you learn works with every motion you already know.\nText Objects # Text objects define structured regions of text. They always start with i (inner — excluding delimiters) or a (around — including delimiters):\nText Object Selects iw Inner word (the word itself) aw A word (word plus surrounding space) i\u0026quot; Inside double quotes a\u0026quot; Around double quotes (includes the quotes) i' Inside single quotes i( or ib Inside parentheses a( or ab Around parentheses i{ or iB Inside curly braces a{ or aB Around curly braces i[ Inside square brackets i\u0026lt; Inside angle brackets it Inside HTML/XML tag at Around HTML/XML tag ip Inner paragraph ap A paragraph (includes trailing blank line) is Inner sentence Text objects in action # Command Result ciw Change inner word (delete word, enter Insert mode) ci\u0026quot; Change inside quotes (delete quoted content, stay in quotes) da( Delete around parentheses (content + the parens) yi{ Yank inside curly braces vat Visually select around HTML tag \u0026gt;ip Indent inner paragraph gUiw Uppercase inner word Why text objects matter # With motions, your cursor position matters. With text objects, you can be anywhere inside the target and it still works:\n# Cursor is on the \u0026#39;e\u0026#39; in \u0026#34;hello\u0026#34; ci\u0026#34; → deletes \u0026#34;hello\u0026#34; and puts you in insert mode between the quotes # Works regardless of where your cursor is inside the quotes Counts (Multipliers) # Prefix any operator+motion with a number to repeat it:\nCommand Result 3dw Delete 3 words 5dd Delete 5 lines 2yy Yank 2 lines 4j Move down 4 lines 3\u0026gt;} Indent 3 paragraphs 10iabc Esc Insert \u0026ldquo;abc \u0026quot; 10 times Counts also work with d + count + motion:\nd3w (delete 3 words) 3dw (same thing — delete word, 3 times) The Dot Command # The . command repeats your last change. It\u0026rsquo;s the single most powerful efficiency tool in Vim.\n# Change a word to \u0026#34;server\u0026#34; ciw server Esc # Move to another word you want to change the same way w w w # Repeat the change . The dot command works with any operator+motion or text object combination:\n# Delete inside parentheses di( # Find the next set of parens and repeat f( . Doubling an Operator # Doubling an operator applies it to the entire current line:\nCommand Result dd Delete line cc Change line (delete and enter Insert mode) yy Yank line \u0026gt;\u0026gt; Indent line \u0026lt;\u0026lt; Unindent line == Auto-indent line gUU Uppercase entire line f and t — Line-Level Precision # f (find) and t (till) jump to a character on the current line:\nCommand Movement f; Jump to next ; F; Jump to previous ; t; Jump to just before next ; T; Jump to just after previous ; ; Repeat last f/F/t/T forward , Repeat last f/F/t/T backward Combined with operators:\n# Delete up to and including the next comma df, # Change everything up to (but not including) the closing paren ct) # Delete from cursor to the next equals sign dt= Practical Examples # Rename a variable # # Cursor on the variable name ciw newName Esc # Find next occurrence and repeat n . n . Wrap content in parentheses # # Select the text viw # Delete into register, type replacement c(Ctrl-r \u0026#34;)Esc Reindent an entire function body # # Cursor inside the function vi{= Delete a function\u0026rsquo;s parameters # # Cursor anywhere inside the parens di( Change an HTML attribute value # # Cursor anywhere inside the quotes of class=\u0026#34;old-value\u0026#34; ci\u0026#34;new-value Esc Best Practices # Think in terms of operator + text object rather than character-by-character edits Learn ci and di combinations first — they cover most editing needs Use f and t for precise jumps on the current line instead of repeatedly pressing w or l Let the dot command do the repetition — make one good edit, then . your way through When an edit feels tedious, you\u0026rsquo;re probably not using the right text object — pause and think about what you\u0026rsquo;re actually trying to select ","date":"5 June 2026","externalUrl":null,"permalink":"/posts/vim-motions-and-operators/","section":"Posts","summary":"Understanding Vim’s composable grammar — operators, motions, text objects, and counts — and why it makes editing faster than any other approach.","title":"Vim Motions and Operators","type":"posts"},{"content":" Registers # Registers are Vim\u0026rsquo;s storage slots. Every yank, delete, and change goes into a register. Understanding them means you never lose text you\u0026rsquo;ve cut and gives you access to multiple \u0026ldquo;clipboards.\u0026rdquo;\nViewing registers # :registers \u0026#34; or shorthand :reg Types of registers # Register Name Purpose \u0026quot;\u0026quot; Unnamed Default — last delete, change, or yank \u0026quot;0 Yank Last yank only (not affected by deletes) \u0026quot;1–\u0026quot;9 Numbered History of deletes (1 = most recent) \u0026quot;a–\u0026quot;z Named Your own storage (you explicitly choose these) \u0026quot;+ System clipboard Copy/paste with other applications \u0026quot;* Selection clipboard X11 primary selection (middle-click paste) \u0026quot;_ Black hole Delete without affecting any register \u0026quot;/ Search Last search pattern \u0026quot;. Last insert Text from last Insert mode session \u0026quot;% Filename Current file name \u0026quot;: Command Last command-line command Using named registers # Prefix any yank or delete with \u0026quot;x to target register x:\n\u0026#34;ayy Yank current line into register a \u0026#34;bdiw Delete word into register b \u0026#34;ap Paste from register a \u0026#34;bp Paste from register b This gives you multiple independent clipboards.\nThe yank register (\u0026quot;0) # The key insight: deletes go into \u0026quot;\u0026quot; and \u0026quot;1, but yanks also go into \u0026quot;0.\nSo if you yank something, then delete text, your yanked content is safe in \u0026quot;0:\nyiw Yank a word dw Delete another word (overwrites unnamed register) \u0026#34;0p Paste the original yanked word (still in register 0) System clipboard # \u0026#34;+y Yank to system clipboard \u0026#34;+p Paste from system clipboard Or with set clipboard=unnamedplus in your .vimrc, regular y and p use the system clipboard.\nThe black hole register # Delete text without saving it anywhere:\n\u0026#34;_dd Delete line, don\u0026#39;t touch registers \u0026#34;_diw Delete word, don\u0026#39;t touch registers Useful when you want to delete something without overwriting what you previously yanked.\nAppending to registers # Use an uppercase letter to append instead of overwrite:\n\u0026#34;ayy Yank line into register a ...move somewhere else... \u0026#34;Ayy Append this line to register a \u0026#34;ap Paste both lines Paste in Insert mode # Ctrl-r a Paste register a while in Insert mode Ctrl-r \u0026#34; Paste unnamed register in Insert mode Ctrl-r + Paste system clipboard in Insert mode Ctrl-r / Paste last search pattern in Insert mode Macros # Macros record a sequence of keystrokes and replay them. They\u0026rsquo;re the fastest way to automate repetitive edits.\nRecording a macro # qa Start recording into register a ...perform your edits... q Stop recording Playing a macro # @a Play macro in register a @@ Replay last played macro 5@a Play macro a five times Macro workflow # The key to a good macro: make it repeatable. End the macro positioned for the next repetition.\nExample — add quotes around the first word on each line:\nqa Start recording into register a 0 Go to beginning of line wi\u0026#34; Go to end of word, insert a quote Esc Back to Normal mode bi\u0026#34; Go to beginning of word, insert a quote Esc Back to Normal mode j Move to next line q Stop recording 5@a Run on the next 5 lines Running macros on visual selections # Select lines with V, then:\n:\u0026#39;\u0026lt;,\u0026#39;\u0026gt;normal @a This applies macro a to each selected line.\nRunning macros across all lines matching a pattern # :g/pattern/normal @a Editing a macro # Macros are just registers. To edit one:\n\u0026#34; Paste register a into the buffer \u0026#34;ap \u0026#34; Edit the keystrokes as text \u0026#34; Yank it back into register a 0\u0026#34;ay$ \u0026#34; Delete the pasted line dd Recursive macros # A macro can call itself for unlimited repetition:\nqa Start recording ...your edits... j Move to next line @a Call itself q Stop recording @a Start it (runs until it hits an error or end of file) The macro stops when any command fails (like j at the last line).\nThe Dot Command Revisited # The . command repeats your last change. It\u0026rsquo;s simpler than macros for one-off repetition:\nciw replacement Esc Change a word n Jump to next search match . Repeat the change n Next match . Repeat again When to use dot vs macros # Scenario Use Same edit, scattered locations . with manual navigation Same edit, sequential lines Macro with j at the end Complex multi-step edit, repeated Macro Simple single change, repeated . Visual Block Mode # Ctrl-v enters visual block mode for column-wise selection.\nInsert text on multiple lines # Ctrl-v Enter block mode jjj Select 4 lines I Insert before block // Type the text Esc Apply to all selected lines Append text on multiple lines # Ctrl-v Enter block mode jjj Select lines $ Extend to end of each line A Append after block ; Type the text Esc Apply to all lines Delete a column # Ctrl-v Enter block mode jjj Select rows ll Extend selection right d Delete the block Replace a column # Ctrl-v Enter block mode jjj Select rows lll Select column width c Change block newtext Type replacement Esc Apply to all rows Power Commands # Shell commands # :!ls \u0026#34; Run a shell command :r !date \u0026#34; Insert command output into buffer :r !curl -s url \u0026#34; Insert curl output :w !bash \u0026#34; Send buffer contents to bash :%!sort \u0026#34; Sort the entire file in place :%!jq . \u0026#34; Format JSON through jq :\u0026#39;\u0026lt;,\u0026#39;\u0026gt;!sort \u0026#34; Sort selected lines The expression register # Ctrl-r = In Insert mode, evaluate an expression Type: 2+2 Enter → inserts \u0026#34;4\u0026#34; Type: system(\u0026#39;date\u0026#39;) Enter → inserts current date Other useful commands # Command Action J Join current line with next (adds space) gJ Join without adding space ~ Toggle case of character g~iw Toggle case of word gUiw Uppercase word guiw Lowercase word Ctrl-a Increment number under cursor Ctrl-x Decrement number under cursor ga Show ASCII value of character gf Open file path under cursor gx Open URL under cursor Practical Examples # Add a prefix to multiple lines # Ctrl-v Block select 4j Select 5 lines I Insert mode - [ ] Type the prefix Esc Apply Record a macro to format CSV as markdown table # qa 0 Go to start of line :s/,/ | /g Enter Replace commas with pipes I| Esc Add leading pipe A |Esc Add trailing pipe j Move to next line q Stop recording 10@a Apply to next 10 lines Increment a sequence of numbers # # Start with: item1 item1 item1 # Select lines 2-3 with visual block on the number Ctrl-v jj g Ctrl-a Increment as a sequence → item1, item2, item3 Delete every other line # :g/pattern/normal dd Or with a macro:\nqa jdd q Record: skip a line, delete next 100@a Run 100 times Best Practices # Use the yank register (\u0026quot;0) when you need to paste something after deleting other text Use named registers (\u0026quot;a–\u0026quot;z) when juggling multiple pieces of text End macros with a movement to the next target so they chain cleanly Test macros on one line first before running them with a count Prefer the dot command over macros for simple, one-step edits Use visual block mode for column operations instead of writing complex macros Use :g/pattern/normal @a to apply macros selectively instead of blindly across the whole file ","date":"5 June 2026","externalUrl":null,"permalink":"/posts/vim-registers-macros/","section":"Posts","summary":"Registers for managing multiple clipboards, macros for automating repetitive edits, and power commands that save time daily.","title":"Vim Productivity: Registers, Macros, and Shortcuts","type":"posts"},{"content":" Searching # Forward and backward search # /pattern Search forward ?pattern Search backward Press Enter to execute the search, then:\nKey Action n Next match (same direction) N Previous match (opposite direction) Search for the word under the cursor # Key Action * Search forward for the exact word under cursor # Search backward for the exact word under cursor These match whole words — searching on port won\u0026rsquo;t match export.\nSearch options # \u0026#34; Case-insensitive search (add \\c to any pattern) /error\\c \u0026#34; Case-sensitive search (add \\C to any pattern) /Error\\C \u0026#34; Enable incremental search (highlights as you type) :set incsearch \u0026#34; Highlight all matches :set hlsearch \u0026#34; Clear current highlights :nohlsearch \u0026#34; or shorthand :noh Search and Replace (Substitution) # The substitution command follows this format:\n:[range]s/pattern/replacement/[flags] Common substitutions # Command Effect :s/old/new/ Replace first occurrence on current line :s/old/new/g Replace all occurrences on current line :%s/old/new/g Replace all occurrences in the entire file :%s/old/new/gc Replace all, but ask for confirmation each time :5,10s/old/new/g Replace on lines 5 through 10 :'\u0026lt;,'\u0026gt;s/old/new/g Replace within visual selection Flags # Flag Meaning g Global — all matches on the line, not just the first c Confirm each replacement i Case-insensitive I Case-sensitive n Count matches without replacing Confirmation prompts # With the c flag, Vim asks for each match:\nKey Action y Replace this match n Skip this match a Replace all remaining q Quit substitution l Replace this one and quit Regex Basics in Vim # Vim uses its own regex flavor. A few things to know:\nCharacters that need escaping # In Vim\u0026rsquo;s default \u0026ldquo;magic\u0026rdquo; mode, these are literal unless escaped:\nTo match Type ( group ) \\( and \\) + (one or more) \\+ ? (zero or one) \\? ` ` (or) {n,m} (quantifier) \\{n,m\\} These work without escaping: . * ^ $ []\nVery magic mode # Prefix with \\v to make all special characters work like standard regex (no escaping parens, plus, etc.):\n\u0026#34; Standard Vim regex — escape everything :%s/\\(foo\\|bar\\)\\+/replacement/g \u0026#34; Very magic — cleaner :%s/\\v(foo|bar)+/replacement/g Useful patterns # \u0026#34; Delete trailing whitespace :%s/\\s\\+$//g \u0026#34; Delete blank lines :g/^$/d \u0026#34; Add a semicolon to the end of every line :%s/$/;/ \u0026#34; Replace multiple spaces with a single space :%s/ \\+/ /g \u0026#34; Swap two words: foo bar → bar foo :%s/\\(foo\\) \\(bar\\)/\\2 \\1/g Capture groups and backreferences # Use \\( and \\) to capture, \\1, \\2, etc. to reference:\n\u0026#34; Wrap each word in quotes :%s/\\(\\w\\+\\)/\u0026#34;\\1\u0026#34;/g \u0026#34; Swap first and last name :%s/\\(\\w\\+\\) \\(\\w\\+\\)/\\2 \\1/g The Global Command # :g executes a command on every line matching a pattern:\n\u0026#34; Delete all lines containing \u0026#34;debug\u0026#34; :g/debug/d \u0026#34; Delete all blank lines :g/^$/d \u0026#34; Move all TODO comments to end of file :g/TODO/m$ \u0026#34; Indent all lines containing \u0026#34;return\u0026#34; :g/return/\u0026gt; The inverse — act on lines that don\u0026rsquo;t match:\n\u0026#34; Delete all lines NOT containing \u0026#34;keep\u0026#34; :v/keep/d \u0026#34; equivalent to :g!/keep/d Jumping Between Locations # Jump list # Vim tracks where you\u0026rsquo;ve been. Navigate your history:\nKey Action Ctrl-o Jump back (older position) Ctrl-i Jump forward (newer position) Searches, gg, G, and other big moves add to the jump list. Small moves like j, k, w don\u0026rsquo;t.\n\u0026#34; View the jump list :jumps Matching brackets # Key Action % Jump to matching bracket: (), {}, [] Works for parentheses, braces, brackets, and with some plugins, HTML tags.\nLine jumps # Command Action 42G or :42 Go to line 42 gg Go to first line G Go to last line H Top of visible screen M Middle of visible screen L Bottom of visible screen Marks # Marks save a position you can return to later.\nSetting marks # ma Set mark \u0026#39;a\u0026#39; at current position mb Set mark \u0026#39;b\u0026#39; at current position Lowercase marks (a–z) are local to the file. Uppercase marks (A–Z) are global across files.\nJumping to marks # Command Jumps to 'a Line of mark a (first non-blank character) `a Exact position of mark a (line and column) '' Previous position (before last jump) `` Exact previous position Special marks # Mark Position '. Last change '^ Last insert '[ and '] Start/end of last yank or change '\u0026lt; and '\u0026gt; Start/end of last visual selection \u0026#34; List all marks :marks Practical Workflows # Find and replace a variable name with confirmation # :%s/oldName/newName/gc Review each occurrence and press y or n.\nJump between function definitions # /^function (search for functions at start of line) n (next match) n (keep going) Use marks to bounce between two locations # ma (mark current position as \u0026#39;a\u0026#39;) ...navigate elsewhere... mb (mark this position as \u0026#39;b\u0026#39;) \u0026#39;a (jump back to mark a) \u0026#39;b (jump back to mark b) Delete all lines matching a pattern # :g/console\\.log/d Operate on search results with gn # gn selects the next search match. Combined with operators:\n/pattern (search for something) cgn (change the next match) ...type replacement... Esc . (dot repeats — changes next match) . (and again) This is one of the fastest ways to rename something selectively.\nBest Practices # Use * and # to quickly search for the word under your cursor — faster than typing it out Use :noh (or map it to a key) to clear search highlights after you\u0026rsquo;re done Prefer \\v (very magic) for complex regex to avoid escaping everything Use gn + dot for selective replacements — more control than :%s///gc when you only need a few Set marks at locations you return to frequently — they\u0026rsquo;re faster than searching each time Use Ctrl-o liberally — it always takes you back to where you were ","date":"5 June 2026","externalUrl":null,"permalink":"/posts/vim-search-and-replace/","section":"Posts","summary":"Searching, substitution, regex, jumping between locations, and marks — the tools that let you move through files with precision.","title":"Vim Search, Replace, and Navigation","type":"posts"},{"content":" The Mental Model # Vim uses three layers for organizing open files:\nBuffers — an open file in memory (you can have many, even without seeing them) Windows — a viewport into a buffer (splits on screen) Tabs — a collection of windows (like workspace layouts) The relationship:\nTab ├── Window (shows Buffer A) ├── Window (shows Buffer B) └── Window (shows Buffer A again — same buffer, two views) Multiple windows can show the same buffer. Buffers exist whether or not they\u0026rsquo;re visible.\nBuffers # A buffer is created every time you open a file. Even if you switch to another file, the first one stays in memory.\nOpening files into buffers # :e file.txt \u0026#34; Open a file in the current window :e src/main.js \u0026#34; Relative paths work :e . \u0026#34; Open file explorer (netrw) Listing buffers # :ls \u0026#34; or :buffers Output looks like:\n1 %a \u0026#34;index.md\u0026#34; line 42 2 # \u0026#34;config.toml\u0026#34; line 1 3 \u0026#34;about.md\u0026#34; line 1 Symbol Meaning % Current buffer (shown in active window) # Alternate buffer (last edited, toggle with Ctrl-^) a Active (loaded and visible) h Hidden (loaded but not visible) + Modified (unsaved changes) Switching buffers # Command Action :bn Next buffer :bp Previous buffer :b3 Go to buffer 3 :b file Go to buffer matching \u0026ldquo;file\u0026rdquo; (partial match works) Ctrl-^ Toggle between current and alternate buffer :bd Close (delete) current buffer :bd 3 Close buffer 3 The alternate buffer # Ctrl-^ switches between your two most recent buffers. This is extremely useful when you\u0026rsquo;re editing two related files (a module and its test, for example).\nWindows (Splits) # Windows divide your screen to show multiple buffers simultaneously.\nCreating splits # Command Action :sp or Ctrl-w s Horizontal split (same file) :vsp or Ctrl-w v Vertical split (same file) :sp file.txt Horizontal split with a different file :vsp file.txt Vertical split with a different file Navigating between windows # All window commands start with Ctrl-w:\nCommand Action Ctrl-w h Move to window left Ctrl-w j Move to window below Ctrl-w k Move to window above Ctrl-w l Move to window right Ctrl-w w Cycle to next window Resizing windows # Command Action Ctrl-w = Equalize all window sizes Ctrl-w + Increase height Ctrl-w - Decrease height Ctrl-w \u0026gt; Increase width Ctrl-w \u0026lt; Decrease width Ctrl-w _ Maximize height `Ctrl-w ` :resize 20 Set height to 20 lines :vertical resize 80 Set width to 80 columns Moving windows # Command Action Ctrl-w H Move window to far left (vertical) Ctrl-w J Move window to bottom (horizontal) Ctrl-w K Move window to top (horizontal) Ctrl-w L Move window to far right (vertical) Ctrl-w r Rotate windows Closing windows # Command Action :q or Ctrl-w q Close current window :only or Ctrl-w o Close all windows except current Closing a window doesn\u0026rsquo;t close the buffer — the file stays in memory.\nTabs # Tabs in Vim are not like browser tabs. Each tab is a layout of windows. Use them when you want completely different workspace arrangements.\nManaging tabs # Command Action :tabnew Open a new empty tab :tabnew file.txt Open file in a new tab :tabn or gt Next tab :tabp or gT Previous tab :tabclose Close current tab :tabonly Close all other tabs 3gt Go to tab 3 When to use tabs # Tabs are best for separate contexts, not separate files:\nTab 1: application code (splits for module + test) Tab 2: configuration files Tab 3: documentation If you just want to see multiple files, splits are usually better.\nThe Argument List # The argument list tracks files you opened from the command line:\nvim src/*.js :args \u0026#34; Show the argument list :next \u0026#34; Go to next file in arglist :prev \u0026#34; Go to previous file :first \u0026#34; Go to first file :last \u0026#34; Go to last file Run a command across all files in the arglist # \u0026#34; Replace in all argument files :argdo %s/old/new/gc | update \u0026#34; Set indentation in all files :argdo set tabstop=4 | update Modify the arglist # :args src/*.js \u0026#34; Set arglist to all JS files in src/ :argadd test/*.js \u0026#34; Add test files to arglist Practical Workflows # Edit a file and its test side by side # :e src/auth.js :vsp test/auth.test.js Use Ctrl-w l and Ctrl-w h to move between them. Use Ctrl-^ in either window to toggle to the last file you viewed there.\nCompare two files # vim -d file1.txt file2.txt Opens in diff mode with changes highlighted.\nOpen a file from netrw (file explorer) # :e . \u0026#34; Open explorer in current directory :vsp . \u0026#34; Open explorer in a split Navigate with j/k, press Enter to open a file.\nQuick reference lookup while editing # \u0026#34; You\u0026#39;re editing code, need to check something :sp /etc/hosts \u0026#34; Open reference in a split \u0026#34; ...read what you need... Ctrl-w q \u0026#34; Close the reference split Run a substitution across multiple files # :args src/**/*.js :argdo %s/oldFunction/newFunction/g | update Best Practices # Think of buffers as open files and windows as views — don\u0026rsquo;t close buffers just because you can\u0026rsquo;t see them Use Ctrl-^ constantly to toggle between two related files Use splits for files you need to see at the same time Use tabs for separate workspaces, not as a replacement for buffers Use :b with partial names instead of buffer numbers — :b auth is faster than remembering :b7 Learn Ctrl-w = to reset window sizes after resizing your terminal Use :argdo for batch operations across files — it\u0026rsquo;s Vim\u0026rsquo;s version of find-and-replace across a project ","date":"5 June 2026","externalUrl":null,"permalink":"/posts/vim-buffers-windows-tabs/","section":"Posts","summary":"How to work with multiple files in Vim using buffers, splits, and tabs — and when to use each one.","title":"Vim Workflow: Buffers, Windows, and Tabs","type":"posts"},{"content":"","date":"5 June 2026","externalUrl":null,"permalink":"/series/vim-essentials/","section":"Series","summary":"","title":"Vim-Essentials","type":"series"},{"content":"","date":"4 June 2026","externalUrl":null,"permalink":"/tags/bash/","section":"Tags","summary":"","title":"Bash","type":"tags"},{"content":"","date":"4 June 2026","externalUrl":null,"permalink":"/tags/gzip/","section":"Tags","summary":"","title":"Gzip","type":"tags"},{"content":" What is SCP? # SCP (Secure Copy Protocol) transfers files between hosts over an SSH connection. It uses the same authentication and encryption as SSH, so if you can ssh into a machine, you can scp files to and from it.\nscp file.txt user@remote:/path/to/destination/ That\u0026rsquo;s the core pattern: scp \u0026lt;source\u0026gt; \u0026lt;destination\u0026gt;, where either side can be a remote host.\nBasic Syntax # scp [options] \u0026lt;source\u0026gt; \u0026lt;destination\u0026gt; Remote paths use the format user@host:/path. Local paths are just regular file paths.\nDirection Command Local → Remote scp file.txt user@server:/tmp/ Remote → Local scp user@server:/tmp/file.txt ./ Remote → Remote scp user@server1:/tmp/file.txt user@server2:/tmp/ Key Options # -r — Recursive (directories) # Copy an entire directory and its contents:\nscp -r ./project/ user@server:/home/user/project/ Without -r, attempting to copy a directory will fail.\n-P — Port # Connect on a non-standard SSH port (note: uppercase -P, unlike ssh which uses lowercase -p):\nscp -P 2222 file.txt user@server:/tmp/ -i — Identity file # Use a specific SSH private key:\nscp -i ~/.ssh/deploy_key app.tar.gz user@server:/opt/releases/ -C — Compression # Compress data during transfer. Useful on slow connections with compressible data:\nscp -C largefile.sql user@server:/backups/ -l — Bandwidth limit # Limit bandwidth in Kbit/s. Prevents saturating the connection:\n# Limit to 5000 Kbit/s (~625 KB/s) scp -l 5000 backup.tar.gz user@server:/backups/ -q — Quiet mode # Suppress the progress bar and non-error messages:\nscp -q file.txt user@server:/tmp/ -o — SSH options # Pass any SSH configuration option directly:\nscp -o StrictHostKeyChecking=no file.txt user@server:/tmp/ Practical Examples # Deploy a build artifact to a server # scp -i ~/.ssh/deploy_key dist/app-v1.2.0.tar.gz deploy@prod:/opt/releases/ Pull logs from a remote server # scp user@server:/var/log/app/error.log ./error-$(date +%F).log Copy a directory to a remote host # scp -r ./configs/ user@server:/etc/myapp/ Transfer between two remote servers # scp user@server1:/backups/db.sql.gz user@server2:/backups/ Note: this routes traffic through your local machine by default. Both servers must be reachable from your workstation.\nUse with SSH config aliases # If your ~/.ssh/config defines a host:\nHost prod HostName 10.0.1.50 User deploy IdentityFile ~/.ssh/deploy_key Port 2222 Then you can simply:\nscp dist/app.tar.gz prod:/opt/releases/ Copy multiple files # scp file1.txt file2.txt user@server:/tmp/ # Or use a glob scp *.log user@server:/backups/logs/ Using Wildcards on Remote Paths # To copy files matching a pattern from a remote host, quote the path to prevent local shell expansion:\nscp user@server:\u0026#34;/var/log/app/*.log\u0026#34; ./logs/ Without quotes, your local shell expands the * before SCP sees it.\nTroubleshooting # Permission denied # # Check you can SSH to the host first ssh user@server # Verify the destination directory is writable ssh user@server \u0026#39;ls -ld /path/to/destination/\u0026#39; Connection refused or timeout # # Test SSH connectivity ssh -v user@server # Verify the port nc -zv server 22 Slow transfers # # Enable compression scp -C largefile user@server:/tmp/ # Check if the bottleneck is network or disk ssh user@server \u0026#39;dd if=/dev/zero bs=1M count=100\u0026#39; | pv \u0026gt; /dev/null Host key verification failed # This usually means the server\u0026rsquo;s key changed (reinstall, IP reuse). Verify the change is expected, then:\nssh-keygen -R server SCP vs Alternatives # Tool Best For scp Quick one-off transfers, simple syntax rsync Incremental sync, resumable, better for large/repeated transfers sftp Interactive file browsing, resume support ssh + tar Preserving permissions/ownership, streaming directories For recurring or large transfers, rsync is generally preferred:\n# rsync equivalent of scp -r rsync -avz ./project/ user@server:/home/user/project/ Best Practices # Use SSH keys instead of passwords for all SCP operations Prefer rsync for repeated or large transfers — it only sends differences Always quote remote wildcards to avoid local shell expansion Set up ~/.ssh/config aliases to avoid retyping hosts, ports, and key paths Use -l to limit bandwidth on shared or production connections Verify transfers with checksums when integrity matters: sha256sum on both sides ","date":"4 June 2026","externalUrl":null,"permalink":"/posts/scp-command-basics/","section":"Posts","summary":"A practical guide to using scp for secure file transfers between local and remote systems, covering common flags, patterns, and troubleshooting.","title":"How to Use SCP to Transfer Files Over SSH","type":"posts"},{"content":" What Are tar and gzip? # tar (tape archive) bundles multiple files and directories into a single file while preserving permissions, ownership, and directory structure. It does not compress by itself.\ngzip compresses a single file to reduce its size. It doesn\u0026rsquo;t handle multiple files or directories on its own.\nTogether they\u0026rsquo;re the standard approach on Linux: tar bundles the files, gzip compresses the bundle. The result is the familiar .tar.gz (or .tgz) file.\ntar Basics # Create an archive # tar -cf archive.tar file1.txt file2.txt directory/ Flag Meaning -c Create a new archive -f Specify the archive filename (must come last before the filename) Extract an archive # tar -xf archive.tar Flag Meaning -x Extract -f Specify the archive to extract List contents without extracting # tar -tf archive.tar Extract to a specific directory # tar -xf archive.tar -C /opt/myapp/ Verbose output # Add -v to any command to see each file being processed:\ntar -cvf archive.tar ./project/ tar -xvf archive.tar gzip Basics # Compress a file # gzip file.txt # Produces file.txt.gz (original is removed) Decompress a file # gunzip file.txt.gz # Restores file.txt (compressed file is removed) # Or equivalently gzip -d file.txt.gz Keep the original file # gzip -k file.txt # Produces file.txt.gz AND keeps file.txt Check compression ratio # gzip -l file.txt.gz Combining tar and gzip # tar can invoke gzip directly with the -z flag, so you don\u0026rsquo;t need to run them separately.\nCreate a compressed archive # tar -czf archive.tar.gz ./project/ Flag Meaning -c Create -z Compress with gzip -f Output filename Extract a compressed archive # tar -xzf archive.tar.gz List contents of a compressed archive # tar -tzf archive.tar.gz Other Compression Options # tar supports multiple compression algorithms via different flags:\nFlag Algorithm Extension Notes -z gzip .tar.gz, .tgz Fast, universally available -j bzip2 .tar.bz2 Better compression, slower -J xz .tar.xz Best compression, slowest --zstd zstandard .tar.zst Fast compression with good ratios # bzip2 tar -cjf archive.tar.bz2 ./project/ # xz tar -cJf archive.tar.xz ./project/ # zstandard tar --zstd -cf archive.tar.zst ./project/ Practical Examples # Back up a directory # tar -czf backup-$(date +%F).tar.gz ./myapp/ Extract a single file from an archive # tar -xzf archive.tar.gz path/to/specific/file.txt The path must match exactly as shown in tar -tzf.\nExclude files or directories # tar -czf project.tar.gz ./project/ --exclude=\u0026#39;*.log\u0026#39; --exclude=\u0026#39;node_modules\u0026#39; Archive and preserve permissions (as root) # sudo tar -czpf full-backup.tar.gz /etc/ The -p flag preserves permissions. This is the default when running as root, but explicit is clearer.\nStream an archive over SSH # # Send a directory to a remote host without creating a local file tar -cz ./project/ | ssh user@server \u0026#39;tar -xz -C /opt/\u0026#39; Create an archive with a top-level directory # # Puts everything under a project-v1.0/ prefix tar -czf release.tar.gz --transform=\u0026#39;s,^\\./,project-v1.0/,\u0026#39; ./src/ ./README.md Split a large archive into parts # tar -czf - ./large-dir/ | split -b 100M - backup-part- # Reassemble and extract cat backup-part-* | tar -xzf - Common File Extensions # Extension What it is .tar Uncompressed tar archive .tar.gz or .tgz gzip-compressed tar archive .tar.bz2 or .tbz2 bzip2-compressed tar archive .tar.xz or .txz xz-compressed tar archive .tar.zst zstandard-compressed tar archive .gz gzip-compressed single file Verifying Archive Integrity # # Test that a gzip file is valid gzip -t archive.tar.gz # Verify tar contents are readable tar -tzf archive.tar.gz \u0026gt; /dev/null Troubleshooting # \u0026ldquo;tar: Removing leading \u0026lsquo;/\u0026rsquo; from member names\u0026rdquo; # tar strips absolute paths by default to prevent accidentally overwriting system files on extraction. This is intentional and safe.\nTo extract to the original absolute paths (dangerous):\ntar -xzf archive.tar.gz -C / --absolute-names \u0026ldquo;gzip: stdin: not in gzip format\u0026rdquo; # The file isn\u0026rsquo;t actually gzip-compressed. Check what it is:\nfile archive.tar.gz Permission errors during extraction # # Extract as yourself, ignoring stored ownership tar -xzf archive.tar.gz --no-same-owner Best Practices # Use tar -czf as your default for creating archives — gzip is fast and universal Use xz or zstd when archive size matters more than speed Always list contents (tar -tzf) before extracting archives from untrusted sources Include a top-level directory in archives so extraction doesn\u0026rsquo;t scatter files into the current directory Use --exclude to leave out build artifacts, logs, and dependency directories Add a date stamp to backup filenames: backup-$(date +%F).tar.gz For large transfers, pipe tar over SSH instead of creating intermediate files ","date":"4 June 2026","externalUrl":null,"permalink":"/posts/tar-and-gzip-basics/","section":"Posts","summary":"A practical guide to tar and gzip — creating archives, compressing files, extracting contents, and common patterns you’ll use daily.","title":"How to Use tar and gzip for Archiving and Compression","type":"posts"},{"content":"","date":"4 June 2026","externalUrl":null,"permalink":"/tags/scp/","section":"Tags","summary":"","title":"Scp","type":"tags"},{"content":"","date":"4 June 2026","externalUrl":null,"permalink":"/tags/shell/","section":"Tags","summary":"","title":"Shell","type":"tags"},{"content":"","date":"4 June 2026","externalUrl":null,"permalink":"/tags/ssh/","section":"Tags","summary":"","title":"Ssh","type":"tags"},{"content":"","date":"4 June 2026","externalUrl":null,"permalink":"/tags/tar/","section":"Tags","summary":"","title":"Tar","type":"tags"},{"content":" What Are Environment Variables? # Environment variables are key-value pairs that configure the behavior of processes on a Linux system. They\u0026rsquo;re inherited by child processes, which means setting a variable in your shell makes it available to every command you run from that shell.\necho $HOME # /home/mike Programs use environment variables for configuration without hardcoding values — paths, credentials, locale settings, and runtime options are all commonly passed this way.\nViewing Environment Variables # List all variables # # All exported environment variables env # Or equivalently printenv Print a specific variable # printenv PATH echo $HOME Show all variables including shell-local ones # # Includes unexported shell variables and functions set Setting Variables # Temporary (current session only) # # Set and export in one step export MY_APP_ENV=production # Or set first, then export MY_APP_ENV=production export MY_APP_ENV For a single command # Prefix the command with the variable assignment:\nDEBUG=true ./my-script.sh This sets DEBUG only for that command — it doesn\u0026rsquo;t affect your current shell.\nUnsetting a variable # unset MY_APP_ENV Shell Variables vs Environment Variables # Not every shell variable is an environment variable:\n# Shell variable (local to this shell, NOT inherited by child processes) MY_VAR=\u0026#34;hello\u0026#34; # Environment variable (inherited by child processes) export MY_VAR=\u0026#34;hello\u0026#34; To check if a variable is exported:\n# Shows only exported variables export -p | grep MY_VAR Persistent Variables # Session variables disappear when you close the terminal. To make them persist, add them to shell startup files.\nWhere to put them # File Scope When it\u0026rsquo;s read ~/.bashrc Current user, interactive shells Every new interactive bash shell ~/.bash_profile Current user, login shells Login (SSH, TTY, new terminal session) ~/.profile Current user, login shells (sh-compatible) Login, if .bash_profile doesn\u0026rsquo;t exist /etc/environment All users Login (PAM), not a script — just KEY=value lines /etc/profile All users Login shells /etc/profile.d/*.sh All users Login shells (sourced by /etc/profile) Example: add a persistent variable for your user # echo \u0026#39;export EDITOR=vim\u0026#39; \u0026gt;\u0026gt; ~/.bashrc Reload without logging out:\nsource ~/.bashrc Example: add a system-wide variable # # /etc/environment uses simple KEY=value syntax (no export, no shell commands) sudo sh -c \u0026#39;echo \u0026#34;JAVA_HOME=/usr/lib/jvm/java-17\u0026#34; \u0026gt;\u0026gt; /etc/environment\u0026#39; Common Environment Variables # Variable Purpose Typical Value PATH Directories to search for commands /usr/local/bin:/usr/bin:/bin HOME Current user\u0026rsquo;s home directory /home/mike USER Current username mike SHELL Current user\u0026rsquo;s default shell /bin/bash EDITOR Default text editor vim, nano LANG System locale en_US.UTF-8 PWD Current working directory /home/mike/projects TERM Terminal type xterm-256color XDG_CONFIG_HOME User config directory ~/.config LD_LIBRARY_PATH Additional shared library paths /usr/local/lib The PATH Variable # PATH is the most important environment variable. It tells the shell where to find executable programs.\necho $PATH # /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin The shell searches directories left to right. The first match wins.\nAdding to PATH # # Prepend (your directory is searched first) export PATH=\u0026#34;$HOME/.local/bin:$PATH\u0026#34; # Append (searched last) export PATH=\u0026#34;$PATH:/opt/myapp/bin\u0026#34; Make it persistent:\necho \u0026#39;export PATH=\u0026#34;$HOME/.local/bin:$PATH\u0026#34;\u0026#39; \u0026gt;\u0026gt; ~/.bashrc Check where a command resolves from # which python3 # /usr/bin/python3 type -a python3 # Shows ALL matches in PATH Variable Expansion # The shell expands variables before executing commands:\nAPP_DIR=/opt/myapp echo \u0026#34;$APP_DIR/bin\u0026#34; # /opt/myapp/bin Braces for disambiguation # VERSION=3 echo \u0026#34;${VERSION}_final\u0026#34; # 3_final # Without braces, shell looks for $VERSION_final (undefined) echo \u0026#34;$VERSION_final\u0026#34; # (empty) Default values # # Use default if variable is unset or empty echo \u0026#34;${DB_HOST:-localhost}\u0026#34; # Assign default if unset : \u0026#34;${DB_PORT:=5432}\u0026#34; echo $DB_PORT # 5432 Environment Variables in Scripts # Scripts inherit the environment of the parent shell. You can also load variables from a file:\n.env file pattern # # .env DB_HOST=localhost DB_PORT=5432 DB_NAME=myapp Load it into your shell:\nexport $(grep -v \u0026#39;^#\u0026#39; .env | xargs) Or source it if it uses export:\n# .env (with export) export DB_HOST=localhost export DB_PORT=5432 source .env Passing variables to child processes # # Only exported variables are inherited export API_KEY=\u0026#34;secret123\u0026#34; ./my-script.sh # can access $API_KEY # Non-exported variables are NOT inherited LOCAL_VAR=\u0026#34;hello\u0026#34; ./my-script.sh # cannot access $LOCAL_VAR Inspecting a Process\u0026rsquo;s Environment # View the environment of a running process:\n# By PID cat /proc/\u0026lt;pid\u0026gt;/environ | tr \u0026#39;\\0\u0026#39; \u0026#39;\\n\u0026#39; # For a specific process cat /proc/$(pgrep nginx | head -1)/environ | tr \u0026#39;\\0\u0026#39; \u0026#39;\\n\u0026#39; Best Practices # Keep secrets out of shell history — use read -s or load from files with restricted permissions instead of typing export SECRET=value directly Use /etc/environment for system-wide variables that all users and services need Use ~/.bashrc for user-specific interactive settings and ~/.bash_profile for login-time setup Always quote variable expansions (\u0026quot;$VAR\u0026quot;) to prevent word splitting and globbing Use ${VAR:-default} syntax in scripts to handle missing variables gracefully Don\u0026rsquo;t put sensitive values in /etc/environment or profile scripts — use secret management tools for production credentials Prepend to PATH with $HOME/.local/bin:$PATH rather than overwriting it entirely ","date":"4 June 2026","externalUrl":null,"permalink":"/posts/linux-environment-variables/","section":"Posts","summary":"A practical guide to environment variables in Linux — how they work, how to set them, where they’re loaded from, and common use cases.","title":"Understanding Linux Environment Variables","type":"posts"},{"content":"","date":"2 June 2026","externalUrl":null,"permalink":"/tags/containers/","section":"Tags","summary":"","title":"Containers","type":"tags"},{"content":"","date":"2 June 2026","externalUrl":null,"permalink":"/tags/dns/","section":"Tags","summary":"","title":"Dns","type":"tags"},{"content":"","date":"2 June 2026","externalUrl":null,"permalink":"/tags/networking/","section":"Tags","summary":"","title":"Networking","type":"tags"},{"content":"","date":"2 June 2026","externalUrl":null,"permalink":"/series/networking-fundamentals/","section":"Series","summary":"","title":"Networking-Fundamentals","type":"series"},{"content":"","date":"2 June 2026","externalUrl":null,"permalink":"/tags/osi/","section":"Tags","summary":"","title":"Osi","type":"tags"},{"content":"","date":"2 June 2026","externalUrl":null,"permalink":"/tags/tcp/","section":"Tags","summary":"","title":"Tcp","type":"tags"},{"content":" What is DNS? # DNS (Domain Name System) translates human-readable domain names like example.com into IP addresses like 93.184.216.34. It\u0026rsquo;s often called the \u0026ldquo;phone book of the internet.\u0026rdquo;\nWithout DNS, you\u0026rsquo;d need to memorize IP addresses for every website you visit.\nHow DNS Resolution Works # When you type example.com in your browser, this happens:\nBrowser cache — checks if it already knows the IP OS resolver — checks /etc/hosts and the local stub resolver Recursive resolver — your ISP or configured DNS server (e.g., 1.1.1.1) Root nameservers — directs the query to the correct TLD server TLD nameservers — .com, .org, etc. point to the authoritative server Authoritative nameserver — returns the actual IP address You → Recursive Resolver → Root → TLD (.com) → Authoritative → IP returned DNS Record Types # A Record # Maps a domain to an IPv4 address:\nexample.com. A 93.184.216.34 AAAA Record # Maps a domain to an IPv6 address:\nexample.com. AAAA 2606:2800:220:1:248:1893:25c8:1946 CNAME Record # An alias pointing one domain to another:\nwww.example.com. CNAME example.com. A CNAME cannot coexist with other record types for the same name.\nMX Record # Specifies mail servers for a domain. The number is priority (lower = preferred):\nexample.com. MX 10 mail1.example.com. example.com. MX 20 mail2.example.com. TXT Record # Stores arbitrary text. Commonly used for verification and email security:\nexample.com. TXT \u0026#34;v=spf1 include:_spf.google.com ~all\u0026#34; NS Record # Delegates a domain to specific nameservers:\nexample.com. NS ns1.example.com. example.com. NS ns2.example.com. SOA Record # Start of Authority — contains metadata about the zone:\nexample.com. SOA ns1.example.com. admin.example.com. ( 2026060201 ; serial 3600 ; refresh 900 ; retry 1209600 ; expire 86400 ) ; minimum TTL Summary Table # Type Purpose Example Value A IPv4 address 93.184.216.34 AAAA IPv6 address 2606:2800:220:1:... CNAME Alias to another name example.com. MX Mail server 10 mail.example.com. TXT Text data (SPF, DKIM, etc.) \u0026quot;v=spf1 ...\u0026quot; NS Nameserver delegation ns1.example.com. SOA Zone authority metadata serial, refresh, etc. SRV Service location _sip._tcp.example.com. PTR Reverse lookup (IP → name) 34.216.184.93.in-addr.arpa. TTL (Time to Live) # Every DNS record has a TTL value in seconds. This tells resolvers how long to cache the result:\nexample.com. 300 A 93.184.216.34 This record is cached for 5 minutes. After that, resolvers must query again.\nCommon TTL values:\nTTL Duration Use Case 60 1 minute During migrations or failover 300 5 minutes Frequently changing records 3600 1 hour Standard for most records 86400 24 hours Stable records that rarely change Tip: Lower TTL before making changes, wait for the old TTL to expire, then make the change. This minimizes downtime.\nDNS Caching Layers # DNS responses are cached at multiple levels:\nBrowser — Chrome, Firefox each maintain their own cache Operating system — systemd-resolved, nscd, or the OS stub resolver Router — many home routers cache DNS Recursive resolver — your ISP or public resolver (Cloudflare, Google) To flush local cache on Linux:\n# systemd-resolved sudo resolvectl flush-caches # Verify it was flushed resolvectl statistics Querying DNS with dig # dig is the standard tool for DNS troubleshooting.\nBasic query # dig example.com Query a specific record type # dig example.com MX dig example.com TXT dig example.com AAAA Query a specific nameserver # dig @1.1.1.1 example.com dig @8.8.8.8 example.com A Short output # dig +short example.com # 93.184.216.34 Trace the full resolution path # dig +trace example.com This shows every step from root servers to the final answer — invaluable for debugging propagation issues.\nCheck a specific authoritative server # dig @ns1.example.com example.com A +norecurse Querying DNS with nslookup # A simpler alternative to dig:\nnslookup example.com nslookup -type=MX example.com nslookup example.com 1.1.1.1 Querying DNS with host # Even more concise:\nhost example.com host -t MX example.com host 93.184.216.34 # reverse lookup Reverse DNS (PTR Records) # Maps an IP address back to a domain name:\ndig -x 93.184.216.34 PTR records are managed by whoever owns the IP block (usually your hosting provider). They\u0026rsquo;re important for email deliverability — mail servers check that the sending IP resolves back to the domain.\nDNS Propagation # When you change a DNS record, the update doesn\u0026rsquo;t happen instantly worldwide. Caches at every level must expire based on the old TTL.\nChecking propagation:\n# Query multiple public resolvers dig @1.1.1.1 example.com A +short dig @8.8.8.8 example.com A +short dig @9.9.9.9 example.com A +short Propagation typically completes within the old TTL duration, but can take up to 48 hours in edge cases.\nLocal DNS Configuration # /etc/resolv.conf # Defines which resolver your system uses:\nnameserver 1.1.1.1 nameserver 8.8.8.8 On systems using systemd-resolved, this file is managed automatically. Check the actual config with:\nresolvectl status /etc/hosts # Local overrides that bypass DNS entirely:\n127.0.0.1 myapp.local 192.168.1.50 devserver Useful for local development and testing.\nCommon Public DNS Resolvers # Provider Primary Secondary Cloudflare 1.1.1.1 1.0.0.1 Google 8.8.8.8 8.8.4.4 Quad9 9.9.9.9 149.112.112.112 Best Practices # Use short TTLs (60–300s) before making DNS changes Always set up both A and AAAA records if you support IPv6 Use multiple NS records for redundancy Don\u0026rsquo;t use CNAMEs at the zone apex (use A/AAAA or your provider\u0026rsquo;s ALIAS/ANAME feature) Set up SPF, DKIM, and DMARC TXT records for email security Monitor records with dig +trace when troubleshooting Document your DNS records outside your provider\u0026rsquo;s dashboard ","date":"2 June 2026","externalUrl":null,"permalink":"/posts/understanding-dns/","section":"Posts","summary":"A practical guide to DNS covering record types, resolution flow, caching, and common tools for troubleshooting.","title":"Understanding DNS: From Basics to Intermediate Concepts","type":"posts"},{"content":" What is an SSH Key? # SSH keys are cryptographic key pairs used for authenticating to remote servers without a password. A key pair consists of:\nPrivate key — stays on your machine, never shared Public key — placed on servers you want to access Generating a Key Pair # The basic command:\nssh-keygen This creates a key pair with default settings and saves it to ~/.ssh/id_ed25519 (or ~/.ssh/id_rsa on older systems).\nFor most use cases, you\u0026rsquo;ll want to be explicit:\nssh-keygen -t ed25519 -C \u0026#34;mike@workstation\u0026#34; Key Parameters # -t — Key Type # Specifies the algorithm. Common options:\nType Command Notes Ed25519 ssh-keygen -t ed25519 Recommended. Fast, secure, short keys RSA ssh-keygen -t rsa -b 4096 Widely compatible, use 4096 bits minimum ECDSA ssh-keygen -t ecdsa -b 521 Good performance, some trust concerns with NIST curves # Ed25519 (preferred) ssh-keygen -t ed25519 # RSA with 4096-bit key length ssh-keygen -t rsa -b 4096 -b — Bit Length # Sets the key size. Only relevant for RSA and ECDSA:\n# RSA: minimum 2048, recommended 4096 ssh-keygen -t rsa -b 4096 # ECDSA: 256, 384, or 521 ssh-keygen -t ecdsa -b 521 Ed25519 has a fixed key size, so -b is ignored.\n-C — Comment # Adds a label to the key (stored in the public key file). Useful for identifying keys:\nssh-keygen -t ed25519 -C \u0026#34;mike@laptop-2026\u0026#34; -f — Output File # Specifies where to save the key:\nssh-keygen -t ed25519 -f ~/.ssh/github_key This creates ~/.ssh/github_key (private) and ~/.ssh/github_key.pub (public).\n-N — Passphrase # Sets the passphrase non-interactively:\n# With a passphrase ssh-keygen -t ed25519 -N \u0026#34;my-secure-passphrase\u0026#34; # Without a passphrase (use cautiously) ssh-keygen -t ed25519 -N \u0026#34;\u0026#34; -p — Change Passphrase # Change the passphrase on an existing key:\nssh-keygen -p -f ~/.ssh/id_ed25519 Practical Examples # Generate a key for GitHub # ssh-keygen -t ed25519 -C \u0026#34;your_email@example.com\u0026#34; -f ~/.ssh/github Then add the public key to GitHub:\ncat ~/.ssh/github.pub # Copy the output and paste it into GitHub → Settings → SSH Keys Generate a key for a specific server # ssh-keygen -t ed25519 -f ~/.ssh/prod_server -C \u0026#34;mike@prod\u0026#34; Configure ~/.ssh/config to use it automatically:\nHost prod HostName 192.168.1.100 User deploy IdentityFile ~/.ssh/prod_server Copy your public key to a server # ssh-copy-id -i ~/.ssh/prod_server.pub user@192.168.1.100 Viewing Key Info # Check the fingerprint of an existing key:\nssh-keygen -l -f ~/.ssh/id_ed25519.pub Show the key in a different format:\nssh-keygen -l -E md5 -f ~/.ssh/id_ed25519.pub Best Practices # Use Ed25519 unless you need RSA for compatibility Always set a passphrase on keys used for sensitive systems Use ssh-agent so you don\u0026rsquo;t retype the passphrase constantly Use separate keys for different services (GitHub, work servers, personal servers) Set proper permissions: chmod 700 ~/.ssh \u0026amp;\u0026amp; chmod 600 ~/.ssh/id_* ","date":"31 May 2026","externalUrl":null,"permalink":"/posts/how-to-create-ssh-keys/","section":"Posts","summary":"A practical guide to generating SSH keys with ssh-keygen, covering key types, common parameters, and best practices.","title":"How to Create SSH Keys on Linux","type":"posts"},{"content":"","date":"31 May 2026","externalUrl":null,"permalink":"/tags/security/","section":"Tags","summary":"","title":"Security","type":"tags"},{"content":"","externalUrl":null,"permalink":"/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"}]