<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><title>firstfinger</title><subtitle>Notes on devops, infrastructure, self-hosting, homelab, software engineering, and AI — by Anurag Vishwakarma.</subtitle><link href="https://firstfinger.io/atom.xml" rel="self" type="application/atom+xml"/><link href="https://firstfinger.io/"/><id>https://firstfinger.io/</id><updated>2026-06-01T04:44:17Z</updated><author><name>Anurag Vishwakarma</name></author><generator>Hugo</generator><entry><title>Why the OS Never Lets Your Process Touch Real Memory</title><link href="https://firstfinger.io/why-the-os-never-lets-your-process-touch-real-memory/"/><id>https://firstfinger.io/why-the-os-never-lets-your-process-touch-real-memory/</id><updated>2026-05-29T00:00:00Z</updated><published>2026-05-29T00:00:00Z</published><category term="Linux"/><category term="Container"/><category term="Processor"/><summary>Every process thinks it owns all of RAM. It doesn't. Your process has never touched real memory at all and why the CPU lies to your code on every single memory access.</summary><content type="html">&lt;p&gt;A while back I was staring at &lt;code&gt;htop&lt;/code&gt; on one of our production servers. A handful of Node.js workers, a couple of Go services, the usual stack. The VIRT column was showing numbers that did not add up. One process alone was showing 18 GB of virtual memory. The machine had 16 GB of RAM. My first thought was that something was seriously wrong.&lt;/p&gt;
&lt;p&gt;Nothing was wrong. The OS was doing exactly what it was designed to do. But that moment stuck with me because I realised I had been operating Linux systems for years without being able to explain what was actually happening when a process touched memory. I knew the terms: virtual memory, page table, MMU. I just could not connect them into a coherent picture.&lt;/p&gt;
&lt;p&gt;This article is that picture. We will start from the raw problem, work our way through what paging is and why it exists, and then look at how the kernel and CPU work together on every single memory access. At the end there is a section on what this means when you are actually running production systems.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-problem-with-raw-physical-memory"&gt;The Problem With Raw Physical Memory&lt;/h2&gt;
&lt;p&gt;Physical RAM is a flat array of bytes. If you have 16 GB of RAM, you have roughly 17 billion individually addressable bytes, each with a unique address. No structure, no ownership, just bytes sitting in silicon.&lt;/p&gt;
&lt;p&gt;Now imagine running three processes simultaneously. Process A writes some data to address &lt;code&gt;0x100000&lt;/code&gt;. A moment later Process B also writes to &lt;code&gt;0x100000&lt;/code&gt;. Process A&amp;rsquo;s data is overwritten. There is no concept of ownership in raw physical memory. The address space is shared among everyone. Any process can write anywhere.&lt;/p&gt;
&lt;div align="center"&gt; &lt;svg viewBox="0 0 760 400" xmlns="http://www.w3.org/2000/svg" font-family="system-ui, -apple-system, sans-serif"&gt; &lt;defs&gt; &lt;marker id="a1" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto"&gt; &lt;path d="M0,0 L8,3 L0,6 Z" fill="#94a3b8"/&gt; &lt;/marker&gt; &lt;marker id="aRed" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto"&gt; &lt;path d="M0,0 L8,3 L0,6 Z" fill="#ef4444"/&gt; &lt;/marker&gt; &lt;/defs&gt; &lt;rect x="30" y="30" width="190" height="70" rx="8" fill="#1e40af" stroke="#60a5fa" stroke-width="1.5"/&gt; &lt;text x="125" y="60" text-anchor="middle" fill="#ffffff" font-size="15" font-weight="600"&gt;Process A&lt;/text&gt; &lt;text x="125" y="82" text-anchor="middle" fill="#bfdbfe" font-size="12" font-family="monospace"&gt;writes to 0x1000&lt;/text&gt; &lt;rect x="30" y="140" width="190" height="70" rx="8" fill="#047857" stroke="#34d399" stroke-width="1.5"/&gt; &lt;text x="125" y="170" text-anchor="middle" fill="#ffffff" font-size="15" font-weight="600"&gt;Process B&lt;/text&gt; &lt;text x="125" y="192" text-anchor="middle" fill="#d1fae5" font-size="12" font-family="monospace"&gt;writes to 0x1000&lt;/text&gt; &lt;rect x="30" y="250" width="190" height="70" rx="8" fill="#0e7490" stroke="#22d3ee" stroke-width="1.5"/&gt; &lt;text x="125" y="280" text-anchor="middle" fill="#ffffff" font-size="15" font-weight="600"&gt;Process C&lt;/text&gt; &lt;text x="125" y="302" text-anchor="middle" fill="#cffafe" font-size="12" font-family="monospace"&gt;reads from 0x1000&lt;/text&gt; &lt;rect x="320" y="105" width="180" height="150" rx="8" fill="#1e293b" stroke="#64748b" stroke-width="2"/&gt; &lt;text x="410" y="145" text-anchor="middle" fill="#f1f5f9" font-size="16" font-weight="700"&gt;Physical RAM&lt;/text&gt; &lt;text x="410" y="168" text-anchor="middle" fill="#94a3b8" font-size="12"&gt;flat array of bytes&lt;/text&gt; &lt;text x="410" y="186" text-anchor="middle" fill="#94a3b8" font-size="12"&gt;no ownership&lt;/text&gt; &lt;rect x="345" y="205" width="130" height="34" rx="4" fill="#334155" stroke="#475569" stroke-width="1"/&gt; &lt;text x="410" y="227" text-anchor="middle" fill="#fbbf24" font-size="12" font-family="monospace"&gt;0x1000 shared&lt;/text&gt; &lt;rect x="560" y="150" width="175" height="92" rx="8" fill="#7f1d1d" stroke="#ef4444" stroke-width="2"/&gt; &lt;text x="647" y="180" text-anchor="middle" fill="#fecaca" font-size="13" font-weight="600"&gt;Data corruption&lt;/text&gt; &lt;text x="647" y="201" text-anchor="middle" fill="#fecaca" font-size="13" font-weight="600"&gt;No isolation&lt;/text&gt; &lt;text x="647" y="222" text-anchor="middle" fill="#fecaca" font-size="13" font-weight="600"&gt;Security breach&lt;/text&gt; &lt;path d="M220,65 L312,135" fill="none" stroke="#94a3b8" stroke-width="2" marker-end="url(#a1)"/&gt; &lt;path d="M220,175 L312,180" fill="none" stroke="#94a3b8" stroke-width="2" marker-end="url(#a1)"/&gt; &lt;path d="M220,285 L312,225" fill="none" stroke="#94a3b8" stroke-width="2" marker-end="url(#a1)"/&gt; &lt;path d="M500,190 L552,193" fill="none" stroke="#ef4444" stroke-width="2.5" marker-end="url(#aRed)"/&gt; &lt;/svg&gt; &lt;/div&gt;
&lt;p&gt;Early computing dealt with this. MS-DOS was largely single-tasking precisely because real-mode x86 had no hardware enforcement of memory boundaries. Running multiple programs at once was a recipe for instability. The moment you want a proper multitasking OS with a shell, a database, a web server all running concurrently, raw physical addressing is fundamentally broken.&lt;/p&gt;
&lt;p&gt;Something had to change at the architecture level.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="virtual-memory"&gt;Virtual Memory&lt;/h2&gt;
&lt;p&gt;The solution the kernel offers is to give every process a private view of memory that does not correspond to physical addresses. This is &lt;a href="https://docs.kernel.org/admin-guide/mm/concepts.html" target="_blank" rel="noopener noreferrer"&gt;virtual memory&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Every process on a 64-bit Linux system believes it has the entire address space to itself. In practice, x86-64 hardware uses 48 bits of the address (the full 64-bit space is impractically large, 2^64 bytes is more than a million times the world&amp;rsquo;s total storage capacity). That gives 2^48 = 256 TB split between user space (lower 128 TB) and kernel space (upper 128 TB). Your process sees addresses from &lt;code&gt;0x0000000000000000&lt;/code&gt; to &lt;code&gt;0x00007FFFFFFFFFFF&lt;/code&gt; as its own private real estate.&lt;/p&gt;
&lt;p&gt;These addresses are not real. They are virtual. When your code reads from &lt;code&gt;0x7fff1234abcd&lt;/code&gt;, the CPU translates that virtual address to a physical one before touching RAM. Your process never knows where in physical memory its data actually lives, and it never knows other processes exist from a memory standpoint.&lt;/p&gt;
&lt;div align="center"&gt; &lt;svg viewBox="0 0 780 420" xmlns="http://www.w3.org/2000/svg" font-family="system-ui, -apple-system, sans-serif"&gt; &lt;defs&gt; &lt;marker id="va" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto"&gt; &lt;path d="M0,0 L8,3 L0,6 Z" fill="#94a3b8"/&gt; &lt;/marker&gt; &lt;/defs&gt; &lt;rect x="30" y="42" width="230" height="128" rx="10" fill="none" stroke="#3b82f6" stroke-width="2" stroke-dasharray="6 4"/&gt; &lt;text x="145" y="32" text-anchor="middle" fill="#93c5fd" font-size="14" font-weight="700"&gt;Process A — Virtual Space&lt;/text&gt; &lt;rect x="50" y="62" width="190" height="42" rx="6" fill="#1e3a8a" stroke="#3b82f6" stroke-width="1.5"/&gt; &lt;text x="145" y="83" text-anchor="middle" fill="#ffffff" font-size="12" font-family="monospace"&gt;0x1000&lt;/text&gt; &lt;text x="145" y="98" text-anchor="middle" fill="#bfdbfe" font-size="10"&gt;code&lt;/text&gt; &lt;rect x="50" y="112" width="190" height="42" rx="6" fill="#1e3a8a" stroke="#3b82f6" stroke-width="1.5"/&gt; &lt;text x="145" y="133" text-anchor="middle" fill="#ffffff" font-size="12" font-family="monospace"&gt;0x2000&lt;/text&gt; &lt;text x="145" y="148" text-anchor="middle" fill="#bfdbfe" font-size="10"&gt;data&lt;/text&gt; &lt;rect x="30" y="252" width="230" height="128" rx="10" fill="none" stroke="#10b981" stroke-width="2" stroke-dasharray="6 4"/&gt; &lt;text x="145" y="242" text-anchor="middle" fill="#6ee7b7" font-size="14" font-weight="700"&gt;Process B — Virtual Space&lt;/text&gt; &lt;rect x="50" y="272" width="190" height="42" rx="6" fill="#064e3b" stroke="#10b981" stroke-width="1.5"/&gt; &lt;text x="145" y="293" text-anchor="middle" fill="#ffffff" font-size="12" font-family="monospace"&gt;0x1000&lt;/text&gt; &lt;text x="145" y="308" text-anchor="middle" fill="#a7f3d0" font-size="10"&gt;code&lt;/text&gt; &lt;rect x="50" y="322" width="190" height="42" rx="6" fill="#064e3b" stroke="#10b981" stroke-width="1.5"/&gt; &lt;text x="145" y="343" text-anchor="middle" fill="#ffffff" font-size="12" font-family="monospace"&gt;0x2000&lt;/text&gt; &lt;text x="145" y="358" text-anchor="middle" fill="#a7f3d0" font-size="10"&gt;data&lt;/text&gt; &lt;rect x="520" y="60" width="230" height="300" rx="10" fill="none" stroke="#a78bfa" stroke-width="2"/&gt; &lt;text x="635" y="50" text-anchor="middle" fill="#c4b5fd" font-size="14" font-weight="700"&gt;Physical RAM&lt;/text&gt; &lt;rect x="540" y="82" width="190" height="50" rx="6" fill="#4c1d95" stroke="#8b5cf6" stroke-width="1.5"/&gt; &lt;text x="635" y="112" text-anchor="middle" fill="#ffffff" font-size="12" font-family="monospace"&gt;Frame 0xA0000&lt;/text&gt; &lt;rect x="540" y="142" width="190" height="50" rx="6" fill="#4c1d95" stroke="#8b5cf6" stroke-width="1.5"/&gt; &lt;text x="635" y="172" text-anchor="middle" fill="#ffffff" font-size="12" font-family="monospace"&gt;Frame 0xB0000&lt;/text&gt; &lt;rect x="540" y="202" width="190" height="50" rx="6" fill="#4c1d95" stroke="#8b5cf6" stroke-width="1.5"/&gt; &lt;text x="635" y="232" text-anchor="middle" fill="#ffffff" font-size="12" font-family="monospace"&gt;Frame 0xC0000&lt;/text&gt; &lt;rect x="540" y="262" width="190" height="50" rx="6" fill="#4c1d95" stroke="#8b5cf6" stroke-width="1.5"/&gt; &lt;text x="635" y="292" text-anchor="middle" fill="#ffffff" font-size="12" font-family="monospace"&gt;Frame 0xD0000&lt;/text&gt; &lt;path d="M240,83 C360,83 410,107 532,107" fill="none" stroke="#94a3b8" stroke-width="2" marker-end="url(#va)"/&gt; &lt;path d="M240,133 C360,133 410,167 532,167" fill="none" stroke="#94a3b8" stroke-width="2" marker-end="url(#va)"/&gt; &lt;path d="M240,293 C360,293 410,227 532,227" fill="none" stroke="#94a3b8" stroke-width="2" marker-end="url(#va)"/&gt; &lt;path d="M240,343 C360,343 410,287 532,287" fill="none" stroke="#94a3b8" stroke-width="2" marker-end="url(#va)"/&gt; &lt;text x="386" y="405" text-anchor="middle" fill="#64748b" font-size="11" font-style="italic"&gt;same virtual address, different physical frames&lt;/text&gt; &lt;/svg&gt; &lt;/div&gt;
&lt;p&gt;Both processes use virtual address &lt;code&gt;0x1000&lt;/code&gt; but they map to completely different physical frames. Isolation is enforced at the hardware level before anything reaches RAM.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="what-is-paging"&gt;What is Paging?&lt;/h2&gt;
&lt;p&gt;To understand how virtual-to-physical translation works, you need paging. Everything else builds on top of it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Paging divides both virtual memory and physical memory into fixed-size chunks.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;On Linux the standard page size is &lt;strong&gt;4 KB (4096 bytes)&lt;/strong&gt;. Virtual memory is divided into virtual pages. Physical memory is divided into physical frames (also called page frames). A virtual page maps to exactly one physical frame. The kernel maintains the table of these mappings.&lt;/p&gt;
&lt;div align="center"&gt; &lt;svg viewBox="0 0 820 400" xmlns="http://www.w3.org/2000/svg" font-family="system-ui, -apple-system, sans-serif"&gt; &lt;defs&gt; &lt;marker id="pg" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto"&gt; &lt;path d="M0,0 L8,3 L0,6 Z" fill="#94a3b8"/&gt; &lt;/marker&gt; &lt;marker id="pgGray" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto"&gt; &lt;path d="M0,0 L8,3 L0,6 Z" fill="#9ca3af"/&gt; &lt;/marker&gt; &lt;/defs&gt; &lt;text x="145" y="40" text-anchor="middle" fill="#93c5fd" font-size="14" font-weight="700"&gt;Virtual Address Space&lt;/text&gt; &lt;rect x="40" y="55" width="210" height="58" rx="6" fill="#1e3a8a" stroke="#3b82f6" stroke-width="1.5"/&gt; &lt;text x="145" y="89" text-anchor="middle" fill="#ffffff" font-size="13"&gt;Page 0 · 4 KB&lt;/text&gt; &lt;rect x="40" y="121" width="210" height="58" rx="6" fill="#1e3a8a" stroke="#3b82f6" stroke-width="1.5"/&gt; &lt;text x="145" y="155" text-anchor="middle" fill="#ffffff" font-size="13"&gt;Page 1 · 4 KB&lt;/text&gt; &lt;rect x="40" y="187" width="210" height="58" rx="6" fill="#1e3a8a" stroke="#3b82f6" stroke-width="1.5"/&gt; &lt;text x="145" y="221" text-anchor="middle" fill="#ffffff" font-size="13"&gt;Page 2 · 4 KB&lt;/text&gt; &lt;rect x="40" y="253" width="210" height="58" rx="6" fill="#2d2a3a" stroke="#9ca3af" stroke-width="1.5" stroke-dasharray="5 3"/&gt; &lt;text x="145" y="280" text-anchor="middle" fill="#e5e7eb" font-size="13"&gt;Page 3 · 4 KB&lt;/text&gt; &lt;text x="145" y="298" text-anchor="middle" fill="#9ca3af" font-size="10"&gt;not in RAM&lt;/text&gt; &lt;text x="555" y="40" text-anchor="middle" fill="#c4b5fd" font-size="14" font-weight="700"&gt;Physical RAM&lt;/text&gt; &lt;rect x="450" y="55" width="210" height="58" rx="6" fill="#4c1d95" stroke="#8b5cf6" stroke-width="1.5"/&gt; &lt;text x="555" y="89" text-anchor="middle" fill="#ffffff" font-size="13"&gt;Frame 5&lt;/text&gt; &lt;rect x="450" y="121" width="210" height="58" rx="6" fill="#4c1d95" stroke="#8b5cf6" stroke-width="1.5"/&gt; &lt;text x="555" y="155" text-anchor="middle" fill="#ffffff" font-size="13"&gt;Frame 2&lt;/text&gt; &lt;rect x="450" y="187" width="210" height="58" rx="6" fill="#4c1d95" stroke="#8b5cf6" stroke-width="1.5"/&gt; &lt;text x="555" y="221" text-anchor="middle" fill="#ffffff" font-size="13"&gt;Frame 9&lt;/text&gt; &lt;rect x="640" y="298" width="150" height="66" rx="8" fill="#374151" stroke="#9ca3af" stroke-width="1.5"/&gt; &lt;text x="715" y="328" text-anchor="middle" fill="#e5e7eb" font-size="13" font-weight="600"&gt;Swap on Disk&lt;/text&gt; &lt;text x="715" y="348" text-anchor="middle" fill="#9ca3af" font-size="11"&gt;page evicted&lt;/text&gt; &lt;path d="M250,84 L442,84" fill="none" stroke="#94a3b8" stroke-width="2" marker-end="url(#pg)"/&gt; &lt;path d="M250,150 L442,150" fill="none" stroke="#94a3b8" stroke-width="2" marker-end="url(#pg)"/&gt; &lt;path d="M250,216 L442,216" fill="none" stroke="#94a3b8" stroke-width="2" marker-end="url(#pg)"/&gt; &lt;path d="M250,282 C440,282 500,331 632,331" fill="none" stroke="#9ca3af" stroke-width="2" stroke-dasharray="6 4" marker-end="url(#pgGray)"/&gt; &lt;text x="346" y="74" text-anchor="middle" fill="#64748b" font-size="10" font-style="italic"&gt;mapped&lt;/text&gt; &lt;/svg&gt; &lt;/div&gt;
&lt;p&gt;A few things fall directly out of this design:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The kernel tracks memory page by page, not byte by byte.&lt;/strong&gt; If your process allocates 1 byte, you get a full 4 KB page assigned. This is why RSS in &lt;code&gt;ps&lt;/code&gt; or &lt;code&gt;htop&lt;/code&gt; is always a multiple of 4096 bytes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Not every virtual page needs to be in RAM at the same time.&lt;/strong&gt; A virtual page can be in RAM, swapped to disk, or not yet backed by any physical memory at all. The page table entry for that page records its current state. This is how swap works, and it is how the kernel can satisfy a large &lt;code&gt;malloc()&lt;/code&gt; without immediately allocating physical frames (lazy allocation).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Each page has permission bits.&lt;/strong&gt; Read, write, execute, user/supervisor. If your process tries to write to a read-only page (like a shared library&amp;rsquo;s code segment), the CPU fires an exception. The kernel catches it and sends SIGSEGV. This hardware enforcement of permissions is what makes memory protection possible, and it falls out naturally from paging without any extra software overhead.&lt;/p&gt;
&lt;p&gt;The data structure that stores all the mappings (virtual page to physical frame, plus state and permissions) is called the &lt;strong&gt;page table&lt;/strong&gt;. Every process has its own. The kernel creates it and keeps it updated. The CPU uses it on every memory access.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="how-linux-builds-the-page-table"&gt;How Linux Builds the Page Table&lt;/h2&gt;
&lt;p&gt;The naive approach: a flat array indexed by virtual page number. For a 48-bit address space with 4 KB pages you need 2^36 entries. At 8 bytes each that is 512 GB per process just for the page table. Not viable.&lt;/p&gt;
&lt;p&gt;Linux uses a &lt;a href="https://docs.kernel.org/mm/page_tables.html" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;multi-level page table&lt;/strong&gt;&lt;/a&gt;
. Instead of one flat array, it is a tree. Only the parts of the address space that are actually in use get table nodes allocated. A sparse process (most of the 128 TB virtual space unused) has a very small page table. Only the live regions exist as allocated nodes.&lt;/p&gt;
&lt;p&gt;On x86-64 Linux, there are four levels. A 48-bit virtual address is split into five fields:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Bits | Level | Name | Entries
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---------|--------|---------------------------------|--------
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[47:39] | L4 | PGD - Page Global Directory | 512
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[38:30] | L3 | PUD - Page Upper Directory | 512
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[29:21] | L2 | PMD - Page Middle Directory | 512
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[20:12] | L1 | PTE - Page Table Entry | 512
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[11:0] | Offset | Byte offset within the page | 4096
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;9 bits per level, 512 entries per table. Each table node is exactly 4 KB, which is exactly one page, convenient for the kernel&amp;rsquo;s own allocator. Four levels of 512 each covers 2^36 pages, which maps the full 48-bit space.&lt;/p&gt;
&lt;p&gt;To resolve any virtual address, you walk the tree from root to leaf:&lt;/p&gt;
&lt;div align="center"&gt; &lt;svg viewBox="0 0 900 420" xmlns="http://www.w3.org/2000/svg" font-family="system-ui, -apple-system, sans-serif"&gt; &lt;defs&gt; &lt;marker id="w" markerWidth="9" markerHeight="9" refX="7" refY="3" orient="auto"&gt; &lt;path d="M0,0 L7,3 L0,6 Z" fill="#94a3b8"/&gt; &lt;/marker&gt; &lt;marker id="wO" markerWidth="9" markerHeight="9" refX="7" refY="3" orient="auto"&gt; &lt;path d="M0,0 L7,3 L0,6 Z" fill="#f59e0b"/&gt; &lt;/marker&gt; &lt;marker id="wT" markerWidth="9" markerHeight="9" refX="7" refY="3" orient="auto"&gt; &lt;path d="M0,0 L7,3 L0,6 Z" fill="#14b8a6"/&gt; &lt;/marker&gt; &lt;/defs&gt; &lt;text x="450" y="26" text-anchor="middle" fill="#e2e8f0" font-size="15" font-weight="700"&gt;Resolving a 48-bit Virtual Address&lt;/text&gt; &lt;!-- address segments --&gt; &lt;rect x="145" y="46" width="150" height="54" rx="4" fill="#1e3a8a" stroke="#3b82f6" stroke-width="1.5"/&gt; &lt;text x="220" y="70" text-anchor="middle" fill="#ffffff" font-size="12" font-weight="600"&gt;PGD index&lt;/text&gt; &lt;text x="220" y="89" text-anchor="middle" fill="#bfdbfe" font-size="11" font-family="monospace"&gt;bits 47:39&lt;/text&gt; &lt;rect x="295" y="46" width="150" height="54" rx="4" fill="#1e40af" stroke="#3b82f6" stroke-width="1.5"/&gt; &lt;text x="370" y="70" text-anchor="middle" fill="#ffffff" font-size="12" font-weight="600"&gt;PUD index&lt;/text&gt; &lt;text x="370" y="89" text-anchor="middle" fill="#bfdbfe" font-size="11" font-family="monospace"&gt;bits 38:30&lt;/text&gt; &lt;rect x="445" y="46" width="150" height="54" rx="4" fill="#1e3a8a" stroke="#3b82f6" stroke-width="1.5"/&gt; &lt;text x="520" y="70" text-anchor="middle" fill="#ffffff" font-size="12" font-weight="600"&gt;PMD index&lt;/text&gt; &lt;text x="520" y="89" text-anchor="middle" fill="#bfdbfe" font-size="11" font-family="monospace"&gt;bits 29:21&lt;/text&gt; &lt;rect x="595" y="46" width="150" height="54" rx="4" fill="#1e40af" stroke="#3b82f6" stroke-width="1.5"/&gt; &lt;text x="670" y="70" text-anchor="middle" fill="#ffffff" font-size="12" font-weight="600"&gt;PTE index&lt;/text&gt; &lt;text x="670" y="89" text-anchor="middle" fill="#bfdbfe" font-size="11" font-family="monospace"&gt;bits 20:12&lt;/text&gt; &lt;rect x="745" y="46" width="150" height="54" rx="4" fill="#0f766e" stroke="#14b8a6" stroke-width="1.5"/&gt; &lt;text x="820" y="70" text-anchor="middle" fill="#ffffff" font-size="12" font-weight="600"&gt;Page offset&lt;/text&gt; &lt;text x="820" y="89" text-anchor="middle" fill="#99f6e4" font-size="11" font-family="monospace"&gt;bits 11:0&lt;/text&gt; &lt;!-- dotted segment to table connectors --&gt; &lt;path d="M220,100 L220,200" stroke="#3b82f6" stroke-width="1.2" stroke-dasharray="3 3" fill="none"/&gt; &lt;path d="M370,100 L370,200" stroke="#3b82f6" stroke-width="1.2" stroke-dasharray="3 3" fill="none"/&gt; &lt;path d="M520,100 L520,200" stroke="#3b82f6" stroke-width="1.2" stroke-dasharray="3 3" fill="none"/&gt; &lt;path d="M670,100 L670,200" stroke="#3b82f6" stroke-width="1.2" stroke-dasharray="3 3" fill="none"/&gt; &lt;path d="M820,100 L820,200" stroke="#14b8a6" stroke-width="1.2" stroke-dasharray="3 3" fill="none"/&gt; &lt;!-- CR3 --&gt; &lt;rect x="20" y="204" width="110" height="72" rx="8" fill="#b45309" stroke="#f59e0b" stroke-width="2"/&gt; &lt;text x="75" y="234" text-anchor="middle" fill="#ffffff" font-size="13" font-weight="700"&gt;CR3&lt;/text&gt; &lt;text x="75" y="253" text-anchor="middle" fill="#fde68a" font-size="10"&gt;phys addr&lt;/text&gt; &lt;text x="75" y="267" text-anchor="middle" fill="#fde68a" font-size="10"&gt;of PGD&lt;/text&gt; &lt;!-- tables --&gt; &lt;rect x="160" y="200" width="120" height="80" rx="8" fill="#312e81" stroke="#6366f1" stroke-width="1.5"/&gt; &lt;text x="220" y="232" text-anchor="middle" fill="#ffffff" font-size="14" font-weight="700"&gt;PGD&lt;/text&gt; &lt;text x="220" y="252" text-anchor="middle" fill="#c7d2fe" font-size="10"&gt;512 entries&lt;/text&gt; &lt;text x="220" y="268" text-anchor="middle" fill="#c7d2fe" font-size="10"&gt;→ PUD ptr&lt;/text&gt; &lt;rect x="310" y="200" width="120" height="80" rx="8" fill="#312e81" stroke="#6366f1" stroke-width="1.5"/&gt; &lt;text x="370" y="232" text-anchor="middle" fill="#ffffff" font-size="14" font-weight="700"&gt;PUD&lt;/text&gt; &lt;text x="370" y="252" text-anchor="middle" fill="#c7d2fe" font-size="10"&gt;512 entries&lt;/text&gt; &lt;text x="370" y="268" text-anchor="middle" fill="#c7d2fe" font-size="10"&gt;→ PMD ptr&lt;/text&gt; &lt;rect x="460" y="200" width="120" height="80" rx="8" fill="#312e81" stroke="#6366f1" stroke-width="1.5"/&gt; &lt;text x="520" y="232" text-anchor="middle" fill="#ffffff" font-size="14" font-weight="700"&gt;PMD&lt;/text&gt; &lt;text x="520" y="252" text-anchor="middle" fill="#c7d2fe" font-size="10"&gt;512 entries&lt;/text&gt; &lt;text x="520" y="268" text-anchor="middle" fill="#c7d2fe" font-size="10"&gt;→ PTE ptr&lt;/text&gt; &lt;rect x="610" y="200" width="120" height="80" rx="8" fill="#5b21b6" stroke="#8b5cf6" stroke-width="2"/&gt; &lt;text x="670" y="232" text-anchor="middle" fill="#ffffff" font-size="13" font-weight="700"&gt;PTE leaf&lt;/text&gt; &lt;text x="670" y="252" text-anchor="middle" fill="#ddd6fe" font-size="10"&gt;frame addr&lt;/text&gt; &lt;text x="670" y="268" text-anchor="middle" fill="#ddd6fe" font-size="10"&gt;+ flags&lt;/text&gt; &lt;rect x="760" y="200" width="120" height="80" rx="8" fill="#0f766e" stroke="#14b8a6" stroke-width="2"/&gt; &lt;text x="820" y="236" text-anchor="middle" fill="#ffffff" font-size="13" font-weight="700"&gt;Frame&lt;/text&gt; &lt;text x="820" y="256" text-anchor="middle" fill="#99f6e4" font-size="10"&gt;4 KB of RAM&lt;/text&gt; &lt;!-- CR3 to PGD --&gt; &lt;path d="M130,240 L156,240" stroke="#f59e0b" stroke-width="2.5" fill="none" marker-end="url(#wO)"/&gt; &lt;!-- walk arrows --&gt; &lt;path d="M280,240 L306,240" stroke="#94a3b8" stroke-width="2" fill="none" marker-end="url(#w)"/&gt; &lt;path d="M430,240 L456,240" stroke="#94a3b8" stroke-width="2" fill="none" marker-end="url(#w)"/&gt; &lt;path d="M580,240 L606,240" stroke="#94a3b8" stroke-width="2" fill="none" marker-end="url(#w)"/&gt; &lt;path d="M730,240 L756,240" stroke="#14b8a6" stroke-width="2" fill="none" marker-end="url(#wT)"/&gt; &lt;!-- result --&gt; &lt;rect x="595" y="338" width="300" height="56" rx="8" fill="#064e3b" stroke="#10b981" stroke-width="2"/&gt; &lt;text x="745" y="362" text-anchor="middle" fill="#ffffff" font-size="13" font-weight="700"&gt;Final Physical Address&lt;/text&gt; &lt;text x="745" y="381" text-anchor="middle" fill="#a7f3d0" font-size="11"&gt;frame base + page offset&lt;/text&gt; &lt;path d="M820,280 L820,334" stroke="#10b981" stroke-width="2.5" fill="none" marker-end="url(#wT)"/&gt; &lt;/svg&gt; &lt;/div&gt;
&lt;p&gt;Each entry in PGD, PUD, PMD points to the physical address of the next level table. The leaf PTE entry holds the physical frame address plus a set of flags:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Present&lt;/strong&gt;: page is in RAM right now&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writable&lt;/strong&gt;: writes allowed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User&lt;/strong&gt;: user-mode code can access (kernel pages have this cleared)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dirty&lt;/strong&gt;: page has been written since last load (used by kernel to decide if it needs to be written back to disk on eviction)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accessed&lt;/strong&gt;: page has been read or written recently (used by eviction heuristics)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NX (No-Execute)&lt;/strong&gt;: instruction fetches from this page are blocked (enforces W^X on data pages)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="the-cpus-role-in-mmu-and-cr3-translation"&gt;The CPU&amp;rsquo;s Role in MMU and CR3 Translation&lt;/h2&gt;
&lt;p&gt;Here is where most articles hand-wave: &amp;ldquo;the OS translates addresses.&amp;rdquo; That is not quite right. The OS creates and maintains the page tables. The actual translation on every single memory access is done by the &lt;strong&gt;CPU in hardware&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The CPU has a dedicated unit called the &lt;strong&gt;Memory Management Unit (MMU)&lt;/strong&gt;. It intercepts every memory reference before it hits the memory bus and runs the translation. This includes instruction fetches, data loads, data stores, everything. There is no bypassing it once virtual addressing is enabled.&lt;/p&gt;
&lt;p&gt;The CPU knows which page table to use via a register called &lt;strong&gt;CR3&lt;/strong&gt;. CR3 holds the physical address of the current process&amp;rsquo;s PGD table. When a memory access happens, the MMU reads CR3 and starts the four-level walk through physical memory.&lt;/p&gt;
&lt;p&gt;The walk takes four memory reads, one per level. That is expensive to do on every access. So the CPU caches recent translations in a small, fast on-chip cache called the &lt;strong&gt;TLB (Translation Lookaside Buffer)&lt;/strong&gt;. Most accesses hit the TLB and translate in roughly one cycle. A TLB miss falls back to the full hardware page table walk.&lt;/p&gt;
&lt;div align="center"&gt; &lt;svg viewBox="0 0 980 440" xmlns="http://www.w3.org/2000/svg" font-family="system-ui, -apple-system, sans-serif"&gt; &lt;defs&gt; &lt;marker id="m" markerWidth="9" markerHeight="9" refX="7" refY="3" orient="auto"&gt; &lt;path d="M0,0 L7,3 L0,6 Z" fill="#94a3b8"/&gt; &lt;/marker&gt; &lt;marker id="mG" markerWidth="9" markerHeight="9" refX="7" refY="3" orient="auto"&gt; &lt;path d="M0,0 L7,3 L0,6 Z" fill="#10b981"/&gt; &lt;/marker&gt; &lt;marker id="mA" markerWidth="9" markerHeight="9" refX="7" refY="3" orient="auto"&gt; &lt;path d="M0,0 L7,3 L0,6 Z" fill="#f59e0b"/&gt; &lt;/marker&gt; &lt;/defs&gt; &lt;rect x="20" y="180" width="140" height="80" rx="8" fill="#1e40af" stroke="#60a5fa" stroke-width="1.5"/&gt; &lt;text x="90" y="216" text-anchor="middle" fill="#ffffff" font-size="14" font-weight="700"&gt;Process&lt;/text&gt; &lt;text x="90" y="236" text-anchor="middle" fill="#bfdbfe" font-size="11"&gt;issues access&lt;/text&gt; &lt;rect x="200" y="180" width="140" height="80" rx="8" fill="#3730a3" stroke="#818cf8" stroke-width="1.5"/&gt; &lt;text x="270" y="216" text-anchor="middle" fill="#ffffff" font-size="14" font-weight="700"&gt;MMU&lt;/text&gt; &lt;text x="270" y="236" text-anchor="middle" fill="#c7d2fe" font-size="11"&gt;in the CPU&lt;/text&gt; &lt;rect x="400" y="68" width="180" height="84" rx="8" fill="#0f766e" stroke="#2dd4bf" stroke-width="1.5"/&gt; &lt;text x="490" y="98" text-anchor="middle" fill="#ffffff" font-size="14" font-weight="700"&gt;TLB Cache&lt;/text&gt; &lt;text x="490" y="118" text-anchor="middle" fill="#99f6e4" font-size="11"&gt;recent translations&lt;/text&gt; &lt;text x="490" y="136" text-anchor="middle" fill="#99f6e4" font-size="11"&gt;hit ≈ 1 cycle&lt;/text&gt; &lt;rect x="400" y="288" width="180" height="92" rx="8" fill="#5b21b6" stroke="#a78bfa" stroke-width="1.5"/&gt; &lt;text x="490" y="318" text-anchor="middle" fill="#ffffff" font-size="14" font-weight="700"&gt;Page Table Walk&lt;/text&gt; &lt;text x="490" y="338" text-anchor="middle" fill="#ddd6fe" font-size="11"&gt;CR3 → PGD → ... → PTE&lt;/text&gt; &lt;text x="490" y="356" text-anchor="middle" fill="#ddd6fe" font-size="11"&gt;4 memory reads&lt;/text&gt; &lt;rect x="640" y="180" width="150" height="80" rx="8" fill="#1e293b" stroke="#64748b" stroke-width="1.5"/&gt; &lt;text x="715" y="212" text-anchor="middle" fill="#f1f5f9" font-size="13" font-weight="700"&gt;Physical&lt;/text&gt; &lt;text x="715" y="232" text-anchor="middle" fill="#f1f5f9" font-size="13" font-weight="700"&gt;address ready&lt;/text&gt; &lt;rect x="820" y="180" width="140" height="80" rx="8" fill="#1e293b" stroke="#a78bfa" stroke-width="1.5"/&gt; &lt;text x="890" y="216" text-anchor="middle" fill="#e9d5ff" font-size="14" font-weight="700"&gt;RAM&lt;/text&gt; &lt;text x="890" y="236" text-anchor="middle" fill="#c4b5fd" font-size="11"&gt;read / write&lt;/text&gt; &lt;!-- 1 process to mmu --&gt; &lt;path d="M160,220 L196,220" stroke="#94a3b8" stroke-width="2" fill="none" marker-end="url(#m)"/&gt; &lt;text x="178" y="246" text-anchor="middle" fill="#94a3b8" font-size="10"&gt;1 VA&lt;/text&gt; &lt;!-- 2 mmu to tlb --&gt; &lt;path d="M340,200 C375,180 380,135 396,122" stroke="#94a3b8" stroke-width="2" fill="none" marker-end="url(#m)"/&gt; &lt;text x="345" y="150" text-anchor="middle" fill="#cbd5e1" font-size="10"&gt;2 lookup&lt;/text&gt; &lt;!-- hit: tlb to resolved --&gt; &lt;path d="M580,118 C620,135 625,180 638,200" stroke="#10b981" stroke-width="2" fill="none" marker-end="url(#mG)"/&gt; &lt;text x="628" y="150" text-anchor="middle" fill="#34d399" font-size="10" font-weight="600"&gt;HIT&lt;/text&gt; &lt;!-- miss: tlb to walk --&gt; &lt;path d="M490,152 L490,284" stroke="#f59e0b" stroke-width="2" fill="none" stroke-dasharray="6 4" marker-end="url(#mA)"/&gt; &lt;text x="512" y="222" text-anchor="middle" fill="#fbbf24" font-size="10" font-weight="600"&gt;MISS&lt;/text&gt; &lt;!-- walk to resolved --&gt; &lt;path d="M580,338 C625,320 628,270 640,250" stroke="#a78bfa" stroke-width="2" fill="none" marker-end="url(#m)"/&gt; &lt;text x="640" y="320" text-anchor="middle" fill="#c4b5fd" font-size="10"&gt;phys addr&lt;/text&gt; &lt;text x="640" y="335" text-anchor="middle" fill="#c4b5fd" font-size="10"&gt;+ fill TLB&lt;/text&gt; &lt;!-- resolved to ram --&gt; &lt;path d="M790,220 L816,220" stroke="#94a3b8" stroke-width="2" fill="none" marker-end="url(#m)"/&gt; &lt;!-- ram back to process --&gt; &lt;path d="M890,260 L890,410 L90,410 L90,262" stroke="#64748b" stroke-width="1.8" fill="none" stroke-dasharray="5 4" marker-end="url(#m)"/&gt; &lt;text x="490" y="402" text-anchor="middle" fill="#94a3b8" font-size="10"&gt;data returned to process&lt;/text&gt; &lt;/svg&gt; &lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Page Faults&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If the MMU walks the page table and hits a PTE with the present bit cleared, it fires a &lt;strong&gt;page fault exception&lt;/strong&gt;. Control transfers to the kernel&amp;rsquo;s page fault handler. The handler checks why the page is not present:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Page is in swap: read it from disk, update PTE present bit, resume the process&lt;/li&gt;
&lt;li&gt;Page was never allocated: allocate a fresh frame, zero it out, update PTE, resume&lt;/li&gt;
&lt;li&gt;Access is genuinely illegal: wrong permissions, out of mapped range. Kernel sends SIGSEGV.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the first two cases the process resumes as if nothing happened. It has no idea a disk read occurred. From its perspective the memory was always there.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="context-switching-and-cr3"&gt;Context Switching and CR3&lt;/h2&gt;
&lt;p&gt;When the kernel switches the CPU from process A to process B, it needs to switch the entire address space. It does this by writing process B&amp;rsquo;s PGD address into CR3.&lt;/p&gt;
&lt;div align="center"&gt; &lt;svg viewBox="0 0 640 540" xmlns="http://www.w3.org/2000/svg" font-family="system-ui, -apple-system, sans-serif"&gt; &lt;defs&gt; &lt;marker id="c" markerWidth="9" markerHeight="9" refX="7" refY="3" orient="auto"&gt; &lt;path d="M0,0 L7,3 L0,6 Z" fill="#94a3b8"/&gt; &lt;/marker&gt; &lt;/defs&gt; &lt;rect x="120" y="30" width="300" height="60" rx="8" fill="#1e293b" stroke="#64748b" stroke-width="1.5"/&gt; &lt;text x="270" y="56" text-anchor="middle" fill="#f1f5f9" font-size="14" font-weight="700"&gt;Kernel Scheduler&lt;/text&gt; &lt;text x="270" y="76" text-anchor="middle" fill="#94a3b8" font-size="11"&gt;decides: switch Process A → Process B&lt;/text&gt; &lt;rect x="120" y="120" width="300" height="72" rx="8" fill="#1e3a8a" stroke="#3b82f6" stroke-width="1.5"/&gt; &lt;text x="270" y="148" text-anchor="middle" fill="#ffffff" font-size="14" font-weight="700"&gt;Save Process A state&lt;/text&gt; &lt;text x="270" y="168" text-anchor="middle" fill="#bfdbfe" font-size="11"&gt;registers saved, including current CR3&lt;/text&gt; &lt;text x="270" y="184" text-anchor="middle" fill="#bfdbfe" font-size="11" font-family="monospace"&gt;CR3_A stored&lt;/text&gt; &lt;rect x="120" y="222" width="300" height="72" rx="8" fill="#b45309" stroke="#f59e0b" stroke-width="2"/&gt; &lt;text x="270" y="250" text-anchor="middle" fill="#ffffff" font-size="14" font-weight="700"&gt;Load CR3 with Process B page table&lt;/text&gt; &lt;text x="270" y="270" text-anchor="middle" fill="#fde68a" font-size="11"&gt;one register write switches the entire&lt;/text&gt; &lt;text x="270" y="286" text-anchor="middle" fill="#fde68a" font-size="11"&gt;address space&lt;/text&gt; &lt;rect x="120" y="324" width="300" height="78" rx="8" fill="#92400e" stroke="#fbbf24" stroke-width="1.5"/&gt; &lt;text x="270" y="352" text-anchor="middle" fill="#ffffff" font-size="14" font-weight="700"&gt;TLB invalidation&lt;/text&gt; &lt;text x="270" y="372" text-anchor="middle" fill="#fef3c7" font-size="11"&gt;flush stale entries, or retain them&lt;/text&gt; &lt;text x="270" y="388" text-anchor="middle" fill="#fef3c7" font-size="11"&gt;using PCID tags (modern x86)&lt;/text&gt; &lt;rect x="120" y="432" width="300" height="60" rx="8" fill="#064e3b" stroke="#10b981" stroke-width="2"/&gt; &lt;text x="270" y="458" text-anchor="middle" fill="#ffffff" font-size="14" font-weight="700"&gt;Process B address space active&lt;/text&gt; &lt;text x="270" y="478" text-anchor="middle" fill="#a7f3d0" font-size="11"&gt;CPU now resolves B's virtual addresses&lt;/text&gt; &lt;path d="M270,90 L270,116" stroke="#94a3b8" stroke-width="2" fill="none" marker-end="url(#c)"/&gt; &lt;path d="M270,192 L270,218" stroke="#94a3b8" stroke-width="2" fill="none" marker-end="url(#c)"/&gt; &lt;path d="M270,294 L270,320" stroke="#94a3b8" stroke-width="2" fill="none" marker-end="url(#c)"/&gt; &lt;path d="M270,402 L270,428" stroke="#94a3b8" stroke-width="2" fill="none" marker-end="url(#c)"/&gt; &lt;!-- CR3 register glyph --&gt; &lt;rect x="450" y="226" width="170" height="64" rx="8" fill="#0f172a" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/&gt; &lt;text x="535" y="248" text-anchor="middle" fill="#f59e0b" font-size="12" font-weight="700"&gt;CR3 register&lt;/text&gt; &lt;text x="535" y="267" text-anchor="middle" fill="#64748b" font-size="11" font-family="monospace" text-decoration="line-through"&gt;CR3_A&lt;/text&gt; &lt;text x="535" y="283" text-anchor="middle" fill="#fde68a" font-size="11" font-family="monospace"&gt;CR3_B&lt;/text&gt; &lt;path d="M448,258 L424,258" stroke="#f59e0b" stroke-width="1.5" fill="none" stroke-dasharray="3 3" marker-end="url(#c)"/&gt; &lt;/svg&gt; &lt;/div&gt;
&lt;p&gt;On older hardware every context switch triggered a full TLB flush. Every cached translation from process A was invalidated because the entries had no process tag. Process B started with a cold TLB, paying the page table walk cost on its first accesses.&lt;/p&gt;
&lt;p&gt;Modern x86 CPUs support &lt;strong&gt;PCID (Process-Context Identifiers)&lt;/strong&gt;, a 12-bit tag on each TLB entry. When the kernel restores CR3 for process B, it can keep valid entries from other processes in the TLB and simply start tagging new entries with B&amp;rsquo;s PCID. Returning to process A later can reuse its still-valid TLB entries.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;KPTI (Kernel Page Table Isolation)&lt;/strong&gt;, introduced as the &lt;a href="https://meltdownattack.com/" target="_blank" rel="noopener noreferrer"&gt;Meltdown&lt;/a&gt;
mitigation in early 2018, added cost here. With KPTI, user space and kernel space use separate page tables, requiring a CR3 switch on every syscall entry and exit. Every &lt;code&gt;read()&lt;/code&gt;, every &lt;code&gt;write()&lt;/code&gt;, every &lt;code&gt;epoll_wait()&lt;/code&gt; crosses a CR3 boundary twice. This is why Meltdown patches had measurable throughput impact on syscall-heavy workloads.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="what-this-architecture-unlocks-"&gt;What This Architecture Unlocks ?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Swap&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When physical RAM is under pressure, the kernel can evict a page by writing it to the swap partition and clearing its PTE present bit. The next access to that virtual address fires a page fault, the kernel reads the page back from disk, sets the present bit again, and resumes. The process never knew. This is how Linux can run more total allocated memory than you have physical RAM, at the cost of latency when cold pages are fetched.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Copy-on-Write&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When you call &lt;code&gt;fork()&lt;/code&gt;, the kernel does not copy all the parent&amp;rsquo;s memory. That would be prohibitively expensive for a process with several gigabytes of RSS. Instead, both parent and child get page tables pointing to the same physical frames. All those shared PTEs are marked read-only. When either process writes to a page, the MMU fires a fault (write to a read-only page). The kernel catches it, copies that specific 4 KB page for the writing process, marks the copy writable, updates the PTE, and resumes. Only the pages that actually diverge ever get copied.&lt;/p&gt;
&lt;p&gt;This is copy-on-write. Most forked processes immediately call &lt;code&gt;exec()&lt;/code&gt;. With COW, &lt;code&gt;fork()&lt;/code&gt; overhead is proportional to page table size, not RSS. This matters enormously for shell scripts spawning hundreds of subprocesses.&lt;/p&gt;
&lt;p&gt;The same mechanism serves shared libraries. &lt;code&gt;libc&lt;/code&gt; is mapped into one set of physical frames. Every process that links against it has its PTEs for the libc region pointing to those same frames. Code pages are read-only so COW never fires. One copy in RAM serves all running processes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Memory Protection&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;PTE supervisor bits mean user-mode code cannot access kernel memory pages. Attempting a read from a kernel address from userspace fires a page fault, the kernel sees the illegal access, and sends SIGSEGV to the process. No software check is involved. The MMU enforces it on every single access.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="what-this-means-when-you-operate-linux-systems"&gt;What This Means When You Operate Linux Systems&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Virtual Size vs RSS vs PSS&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That 18 GB VIRT I saw in htop was not a memory leak. VIRT (VSZ) is the size of the virtual address space mapped by the process, including regions that have no physical backing yet: mmapped files, reserved stack space, shared library address ranges. Most of it was not in RAM.&lt;/p&gt;
&lt;p&gt;RSS is the count of pages currently resident in physical RAM. That is what matters for memory pressure. PSS (Proportional Set Size) is even more accurate because it divides shared pages proportionally among all processes that map them.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# VSZ vs RSS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ps -o pid,vsz,rss,comm -p &amp;lt;pid&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# PSS is the honest number for shared-memory-heavy processes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /proc/&amp;lt;pid&amp;gt;/smaps_rollup &lt;span class="p"&gt;|&lt;/span&gt; grep Pss
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Per-mapping breakdown&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /proc/&amp;lt;pid&amp;gt;/smaps
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Memory Overcommit&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Linux allows processes to &lt;a href="https://docs.kernel.org/mm/overcommit-accounting.html" target="_blank" rel="noopener noreferrer"&gt;commit more virtual memory&lt;/a&gt;
than RAM plus swap can back. &lt;code&gt;malloc()&lt;/code&gt; succeeds immediately because physical frames are only assigned when pages are actually written. This is controlled by &lt;code&gt;vm.overcommit_memory&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 0 = heuristic (default): allows overcommit up to a point&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 1 = always allow: malloc never returns NULL regardless of RAM state&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 2 = strict: total commit bounded by swap + overcommit_ratio percent of RAM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /proc/sys/vm/overcommit_memory
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# For databases and critical services where OOM kill is worse than allocation failure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &amp;gt; /proc/sys/vm/overcommit_memory
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sysctl vm.overcommit_ratio&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt; &lt;span class="c1"&gt;# allow committing up to 80% of RAM + all swap&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;OOM Killer&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When physical RAM is exhausted and swap is full, the kernel&amp;rsquo;s OOM killer fires. It scores all processes based on memory usage plus heuristics and kills the highest scorer. You can influence the scoring:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Protect a critical process (range is -1000 to 1000)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; -1000 &amp;gt; /proc/&amp;lt;pid&amp;gt;/oom_score_adj
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Make a process the preferred OOM target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt; &amp;gt; /proc/&amp;lt;pid&amp;gt;/oom_score_adj
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check current calculated score&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /proc/&amp;lt;pid&amp;gt;/oom_score
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Watch for OOM kill events&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dmesg -T &lt;span class="p"&gt;|&lt;/span&gt; grep -i &lt;span class="s2"&gt;&amp;#34;oom\|killed process&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If your service is getting OOM killed on a machine that still shows free VIRT, check RSS and PSS. Also check if another process is the actual memory hog and your service is just collateral damage based on oom_score.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Huge Pages and TLB Pressure&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Default page size is 4 KB. A process with 10 GB RSS has around 2.5 million resident pages, each potentially needing a TLB entry. Modern CPUs have L1 TLBs of a few hundred entries and L2 TLBs of a few thousand. With a large working set you will miss the TLB constantly, paying the full four-level page table walk cost on every miss.&lt;/p&gt;
&lt;p&gt;Huge pages (2 MB) cover 512x more memory per TLB entry. For workloads with a large, frequently accessed working set, this can meaningfully reduce latency.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check THP (Transparent Huge Pages) status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /sys/kernel/mm/transparent_hugepage/enabled
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Disable THP for latency-sensitive services&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Redis and Kafka both recommend this - THP defragmentation causes latency spikes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Reserve explicit 2 MB huge pages upfront (avoids defragmentation cost)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="m"&gt;512&lt;/span&gt; &amp;gt; /proc/sys/vm/nr_hugepages
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check allocation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grep -i huge /proc/meminfo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Measure TLB pressure with perf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;perf stat -e dTLB-load-misses,iTLB-load-misses,dTLB-loads -p &amp;lt;pid&amp;gt; sleep &lt;span class="m"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="https://docs.kernel.org/admin-guide/mm/transhuge.html" target="_blank" rel="noopener noreferrer"&gt;THP&lt;/a&gt;
allocates huge pages transparently but needs to find 512 contiguous 4 KB frames to form a 2 MB huge page. On a fragmented system this triggers memory compaction, which can stall allocation for tens of milliseconds. Redis latency spikes of 50-200ms on high-memory systems are commonly traced back to THP compaction. Disable it and pre-reserve explicit huge pages if the workload justifies it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reading /proc/meminfo Correctly&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MemTotal: &lt;span class="m"&gt;65536000&lt;/span&gt; kB &lt;span class="c1"&gt;# total physical RAM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MemFree: &lt;span class="m"&gt;2345000&lt;/span&gt; kB &lt;span class="c1"&gt;# completely unused frames&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;MemAvailable: &lt;span class="m"&gt;40123000&lt;/span&gt; kB &lt;span class="c1"&gt;# what processes can actually use&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# = MemFree + reclaimable cache&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Cached: &lt;span class="m"&gt;28000000&lt;/span&gt; kB &lt;span class="c1"&gt;# page cache (file data, reclaimable)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SwapTotal: &lt;span class="m"&gt;8388608&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SwapUsed: &lt;span class="m"&gt;512000&lt;/span&gt; kB &lt;span class="c1"&gt;# non-zero = you have memory pressure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AnonPages: &lt;span class="m"&gt;18000000&lt;/span&gt; kB &lt;span class="c1"&gt;# anonymous pages (heap, stack, mmap&amp;#39;d)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Mapped: &lt;span class="m"&gt;3200000&lt;/span&gt; kB &lt;span class="c1"&gt;# pages mapped into at least one process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;HugePages_Total: &lt;span class="m"&gt;512&lt;/span&gt; &lt;span class="c1"&gt;# pre-reserved 2 MB huge pages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;HugePages_Free: &lt;span class="m"&gt;312&lt;/span&gt; &lt;span class="c1"&gt;# available huge pages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alert on &lt;code&gt;MemAvailable&lt;/code&gt; going low, not &lt;code&gt;MemFree&lt;/code&gt;. &lt;code&gt;MemFree&lt;/code&gt; being low just means the kernel has filled the page cache with file data, which is expected and fine. &lt;code&gt;MemAvailable&lt;/code&gt; being low means processes are competing for physical frames.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Containers and cgroups v2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Containers do not change the virtual memory model. Each container process has its own virtual address space and its own page table, exactly like any other process. What cgroups v2 adds is a hard cap on the number of physical frames that group of processes can have resident:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Set memory limit for a cgroup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;512M&amp;#34;&lt;/span&gt; &amp;gt; /sys/fs/cgroup/myservice/memory.max
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Current physical memory used by the cgroup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /sys/fs/cgroup/myservice/memory.current
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Swap limit (cgroups v2 tracks them separately)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;256M&amp;#34;&lt;/span&gt; &amp;gt; /sys/fs/cgroup/myservice/memory.swap.max
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When a container hits &lt;code&gt;memory.max&lt;/code&gt;, the kernel tries to reclaim pages from that cgroup first (evict page cache, swap anonymous pages) before firing an OOM kill scoped to that cgroup. The virtual address space of processes inside the container is still technically unlimited unless you set &lt;code&gt;RLIMIT_AS&lt;/code&gt; explicitly.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Virtual memory is one of those abstractions that is completely invisible when things are working. Your process gets its pages, the kernel handles swapping, shared libraries load once for everyone, and the MMU does its four-level page table walk on every single instruction fetch and every data access, thousands of times per millisecond, without you ever thinking about it.&lt;/p&gt;
&lt;p&gt;When it breaks down, knowing what is actually happening at the page table level gives you something most runbooks do not: an understanding of &lt;em&gt;why&lt;/em&gt;, not just what command to run. OOM kills on a machine still showing high VIRT, latency spikes from THP compaction, throughput degradation after Meltdown patches, TLB pressure in a database under load. All of these trace back to the mechanics covered here.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Further reading&lt;/strong&gt;&lt;/p&gt;
&lt;a class="attachment-card" href="https://cdn.firstfinger.io/2026/05/why-the-os-never-lets-your-process-touch-real-memory/What%20Every%20Programmer%20Should%20Know%20About%20Memory.pdf" target="_blank" rel="noopener"&gt;
&lt;svg class="attachment-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/&gt;&lt;polyline points="14 2 14 8 20 8"/&gt;&lt;line x1="16" y1="13" x2="8" y2="13"/&gt;&lt;line x1="16" y1="17" x2="8" y2="17"/&gt;&lt;line x1="10" y1="9" x2="8" y2="9"/&gt;&lt;/svg&gt;
&lt;span class="attachment-name"&gt;What Every Programmer Should Know About Memory.pdf&lt;/span&gt;&lt;small class="attachment-size"&gt;912 KB&lt;/small&gt;
&lt;/a&gt;
&lt;p&gt;The kernel never lets your process touch real memory because the one time it did, nothing worked reliably. The private address space it hands every process is one of the best design decisions in operating systems history.&lt;/p&gt;</content></entry><entry><title>Leaving Ghost for a Static Site</title><link href="https://firstfinger.io/leaving-ghost-for-a-static-site/"/><id>https://firstfinger.io/leaving-ghost-for-a-static-site/</id><updated>2026-05-28T00:00:00Z</updated><published>2026-05-28T00:00:00Z</published><author><name>Anurag Vishwakarma</name></author><category term="Self Host"/><category term="Cloud"/><summary>Why I moved my personal blog off Ghost CMS to a static Hugo site on Cloudflare. The frustration that built up over two years, how the migration tool works layer by layer, the Obsidian publishing setup, and why running less infrastructure was the whole point.</summary><content type="html">&lt;p&gt;I write maybe two posts a month, and the writing itself was never the problem. Everything around it was.&lt;/p&gt;
&lt;p&gt;My blog ran on &lt;a href="https://ghost.org" target="_blank" rel="noopener noreferrer"&gt;Ghost&lt;/a&gt;
, and Ghost is a real application. It needs a Node.js server, a MySQL database, and a few background services, all running in Docker on a small server I rented. Keeping it running took steady attention: database backups, version updates, and the occasional &amp;ldquo;why is the site slow today.&amp;rdquo; I was doing infrastructure work for a blog I posted to twice a month, and at some point I realized I was spending more time maintaining it than writing on it.&lt;/p&gt;
&lt;p&gt;So I took it all down and rebuilt the blog as a plain static site. No database, no server to babysit, nothing running in the background. This is the story of why, and how I did it, including the migration tool I wrote and the way I publish posts now.&lt;/p&gt;
&lt;h2 id="first-some-credit"&gt;first, some credit&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t want this to read as a Ghost hit piece. When I moved over from &lt;a href="https://wordpress.org" target="_blank" rel="noopener noreferrer"&gt;WordPress&lt;/a&gt;
in 2023, I genuinely liked Ghost. The editor was clean, setup was simple, and it stayed out of the way when I wanted to write. After years of WordPress plugins, that felt much lighter. I even sent them a small donation early on, because I wanted the project to do well.&lt;/p&gt;
&lt;p&gt;Ghost is a good product. It just turned out to be a good product for a problem I don&amp;rsquo;t have.&lt;/p&gt;
&lt;h2 id="the-problem-it-solves-isnt-mine"&gt;the problem it solves isn&amp;rsquo;t mine&lt;/h2&gt;
&lt;p&gt;Ghost is built around paid newsletters and memberships. Subscriptions, paid tiers, email to your audience. That is where the product puts its energy, and it is genuinely good at it.&lt;/p&gt;
&lt;p&gt;I never used any of that. No paid subscribers, no newsletter. I write posts and put them on the internet for free. So every feature built for the membership business was something I ran and maintained without ever touching.&lt;/p&gt;
&lt;p&gt;And the stack kept growing. Over two years it got heavier instead of lighter: MySQL, the Node app, ActivityPub support, all wrapped in Docker. Every one of those makes sense if you run a newsletter business. None of it made sense for me. Ghost can also run on SQLite, which is a simple file-based database with no separate server, but officially that mode is meant for development, not production. So in practice I was running and backing up a full MySQL database for a personal blog.&lt;/p&gt;
&lt;h2 id="running-something-for-yourself-vs-for-other-people"&gt;running something for yourself vs for other people&lt;/h2&gt;
&lt;p&gt;There is a real difference between self-hosting something only you use and self-hosting something other people read. Once a few people are reading, a database hiccup or a bad night for the host is no longer something you can ignore. It is your site that is down, so you end up keeping an eye on it.&lt;/p&gt;
&lt;p&gt;That is how the ratio went backwards. I was spending more attention on MySQL, backups, and keeping containers happy than on the posts themselves. That is a poor trade for any blog. For a personal one, it makes no sense.&lt;/p&gt;
&lt;h2 id="i-couldnt-write-where-i-wanted"&gt;i couldn&amp;rsquo;t write where i wanted&lt;/h2&gt;
&lt;p&gt;The other daily annoyance was writing on the move. Ghost had no app I trusted and no real way to draft from my phone when an idea showed up away from my desk. So I would write in Apple Notes or Notion wherever I was, then paste it into Ghost later when I was back at my machine. It worked, but it added a step to the one part that should be effortless.&lt;/p&gt;
&lt;h2 id="the-theming-i-never-enjoyed"&gt;the theming i never enjoyed&lt;/h2&gt;
&lt;p&gt;A smaller thing also wore on me. I never liked theming Ghost. WordPress, for all its faults, lets you build a template and shape the site however you like. Ghost is code-only: you either take a theme as it is or edit it by hand, and I never found that time worthwhile. I ran the Journal theme and mostly left it alone. But I like owning how my site looks, and Ghost never made that easy.&lt;/p&gt;
&lt;h2 id="choosing-what-came-next"&gt;choosing what came next&lt;/h2&gt;
&lt;p&gt;For a while I thought about going back to WordPress. It is more polished than people give it credit for, and it is well optimized. But it is the same shape of problem with a different name: a database, a server, an admin panel, constant updates. That would not really solve anything.&lt;/p&gt;
&lt;p&gt;So I made the real decision. No CMS at all. Not WordPress, not Ghost, not the next one. Just a static site: plain HTML files generated ahead of time and served as they are, with nothing running in the background.&lt;/p&gt;
&lt;p&gt;The timing makes this easy. Hosting a static site in 2026 is basically free. Something that used to need a full-time person and a server room is now a setting you turn on. Cloudflare Pages, &lt;a href="https://pages.github.com" target="_blank" rel="noopener noreferrer"&gt;GitHub Pages&lt;/a&gt;
, and others give you a global CDN, caching, and HTTPS at no cost for a site my size.&lt;/p&gt;
&lt;h2 id="the-stack"&gt;the stack&lt;/h2&gt;
&lt;p&gt;Here is what I settled on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://gohugo.io" target="_blank" rel="noopener noreferrer"&gt;Hugo&lt;/a&gt;
&lt;/strong&gt; turns my markdown files into the finished HTML site. I looked at &lt;a href="https://www.11ty.dev" target="_blank" rel="noopener noreferrer"&gt;Eleventy (11ty)&lt;/a&gt;
too, but I wanted a strong ready-made theme more than templating freedom, and Hugo had it. The look here is the &lt;a href="https://github.com/panr/hugo-theme-terminal" target="_blank" rel="noopener noreferrer"&gt;Terminal theme&lt;/a&gt;
by panr, with my own colour tweaks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://pages.cloudflare.com" target="_blank" rel="noopener noreferrer"&gt;Cloudflare Pages&lt;/a&gt;
&lt;/strong&gt; builds the site and serves it from servers close to whoever is reading.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.cloudflare.com/developer-platform/products/r2/" target="_blank" rel="noopener noreferrer"&gt;Cloudflare R2&lt;/a&gt;
&lt;/strong&gt; stores the images. R2 is cheap, and more importantly it has no egress fees, which means you don&amp;rsquo;t get charged every time someone loads one of your images. That surprise cost is what S3-style storage is famous for, and R2 simply doesn&amp;rsquo;t have it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://pagefind.app" target="_blank" rel="noopener noreferrer"&gt;Pagefind&lt;/a&gt;
&lt;/strong&gt; handles search. It builds a search index when the site is built and runs the search entirely in the reader&amp;rsquo;s browser, so there is full-text search with nothing running on a server.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-migration-tool"&gt;the migration tool&lt;/h2&gt;
&lt;p&gt;The actual move took about three days. Day one was planning: what the content looked like coming out of Ghost, where each piece needed to land in Hugo, and how Cloudflare and R2 fit together. The other two days went into writing and testing a migration tool in Python, because I wanted this done properly and repeatably, not by hand.&lt;/p&gt;
&lt;p&gt;I had around 150 posts and four years of writing, and two hard rules. Don&amp;rsquo;t lose any SEO, so every old URL had to keep working. And don&amp;rsquo;t break a single image. So I built the tool to be careful and to check its own work.&lt;/p&gt;
&lt;h3 id="one-post-at-a-time-many-posts-at-once"&gt;one post at a time, many posts at once&lt;/h3&gt;
&lt;p&gt;The tool is built as a pipeline. Each post flows through a fixed sequence of stages, and every stage does one small job. Posts don&amp;rsquo;t depend on each other, so the stages inside a single post run in order, but many posts run through the pipeline at the same time across a pool of workers (eight by default). One worker takes one post and carries it all the way through. That is why the whole migration finishes in about the time the slowest post takes, not the sum of all of them.&lt;/p&gt;
&lt;h3 id="the-layers"&gt;the layers&lt;/h3&gt;
&lt;p&gt;Here is the path each post takes, end to end:&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TB
export[(&amp;#34;Ghost JSON export&amp;lt;br/&amp;gt;~150 posts&amp;#34;)]
subgraph worker[&amp;#34;one worker, one post · eight running in parallel&amp;#34;]
direction TB
p1[&amp;#34;Parse source&amp;#34;] --&amp;gt; p2[&amp;#34;Metadata + slug&amp;#34;]
p2 --&amp;gt; p3[&amp;#34;Body into blocks&amp;#34;]
p3 --&amp;gt; p4[&amp;#34;Clean text + format&amp;#34;]
p4 --&amp;gt; p5[&amp;#34;Re-host assets&amp;#34;]
p5 --&amp;gt; p6[&amp;#34;Map cards to&amp;lt;br/&amp;gt;shortcodes&amp;#34;]
p6 --&amp;gt; p7[&amp;#34;Assemble markdown&amp;#34;]
end
export --&amp;gt; p1
p7 --&amp;gt; gate{&amp;#34;Validate&amp;lt;br/&amp;gt;every stage&amp;#34;}
gate --&amp;gt;|pass| out[&amp;#34;content/posts/&amp;lt;br/&amp;gt;slug/index.md&amp;#34;]
gate --&amp;gt;|fail| quar[[&amp;#34;Quarantine&amp;lt;br/&amp;gt;+ reason&amp;#34;]]
p5 -.-&amp;gt;|&amp;#34;sha256&amp;lt;br/&amp;gt;dedupe&amp;#34;| r2[(&amp;#34;Cloudflare R2&amp;#34;)]
out --&amp;gt; report[&amp;#34;Report +&amp;lt;br/&amp;gt;resume state&amp;#34;]
quar --&amp;gt; report
report -.-&amp;gt;|&amp;#34;re-run skips&amp;lt;br/&amp;gt;finished posts&amp;#34;| export&lt;/pre&gt;
&lt;p&gt;There are eleven stages in total. The main ones, in plain terms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Parse the source.&lt;/strong&gt; Ghost has changed editors over the years, so posts are stored in a few different internal formats. The first stage reads all of them and converts each post into one common structure the rest of the tool understands.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pull out the metadata.&lt;/strong&gt; Title, slug, dates, tags, authors, cover image, social tags. The slug is the URL, so this stage makes sure it matches the old one exactly. That is the &amp;ldquo;zero SEO loss&amp;rdquo; rule in action.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Break the body into blocks.&lt;/strong&gt; Headings, paragraphs, lists, code, images, cards, each as its own typed piece, so later stages can handle them precisely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clean up the text.&lt;/strong&gt; Strip invisible characters, fix non-breaking spaces, and catch mojibake (garbled characters left over from bad encoding) so none of it leaks into the new files.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Render the formatting.&lt;/strong&gt; Bold, italics, links, properly nested lists, and code blocks preserved exactly, byte for byte. This is really a few stages doing one job: turning the structured blocks back into clean markdown.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Re-host every asset.&lt;/strong&gt; This is the important one for &amp;ldquo;no broken images.&amp;rdquo; Every image, file, and video is downloaded from the old site, hashed, uploaded to R2 under a filename based on its contents, and its URL rewritten to point at R2. Because the filename is the hash of the contents, an image used by five posts is uploaded once and reused. After this stage, no link to the old Ghost domain is left.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Map Ghost&amp;rsquo;s special cards.&lt;/strong&gt; Ghost has custom blocks (callouts, bookmarks, galleries, embeds, toggles, audio, video) that aren&amp;rsquo;t plain markdown. Each kind gets translated: some become plain markdown, and the interactive ones become Hugo shortcodes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Assemble and write.&lt;/strong&gt; Combine the metadata and body, write the final &lt;code&gt;content/posts/&amp;lt;slug&amp;gt;/index.md&lt;/code&gt;, and confirm it is valid and Hugo can build it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="it-checks-its-own-work"&gt;it checks its own work&lt;/h3&gt;
&lt;p&gt;This is the part I cared about most. Every stage has a validator. If a stage produces something wrong, the post is quarantined: it gets set aside, and the tool records exactly which stage failed and why, instead of writing a broken post and moving on. At the end of a run it produces a report: how many posts were in the export, how many were written, how many were quarantined, and a pass rate for every single layer.&lt;/p&gt;
&lt;p&gt;The point was simple. I didn&amp;rsquo;t want to discover broken posts weeks later. A run isn&amp;rsquo;t &amp;ldquo;done&amp;rdquo; until the report shows zero quarantined posts, every layer at 100%, Hugo builds with no warnings, and a search for any leftover old-domain URLs comes back empty.&lt;/p&gt;
&lt;p&gt;It is also resumable. Every finished post is recorded, so if the network drops halfway or one post fails, I fix it and re-run, and it only processes what&amp;rsquo;s left. The R2 uploads are safe to repeat too, because the content-based filenames mean re-uploading the same image does nothing.&lt;/p&gt;
&lt;h3 id="where-it-actually-got-hard"&gt;where it actually got hard&lt;/h3&gt;
&lt;p&gt;The difficult parts were exactly where you&amp;rsquo;d guess. Ghost&amp;rsquo;s custom cards don&amp;rsquo;t map cleanly onto markdown, so each type needed its own translation rule. On top of that were the usual formatting edge cases and getting code blocks to survive exactly as written. Most of the testing time went into those odd cases, not the normal posts. The normal posts were never the problem.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve open-sourced this tool: &lt;a href="https://github.com/Harsh-2002/ghost2hugo" target="_blank" rel="noopener noreferrer"&gt;ghost2hugo&lt;/a&gt;
. It started out tuned to my own content, but the shape of it, a layered pipeline that validates each step and re-hosts assets, carries over to anyone making the same move.&lt;/p&gt;
&lt;h2 id="keeping-every-old-url-working"&gt;keeping every old url working&lt;/h2&gt;
&lt;p&gt;The thing that scares people most about leaving a CMS is breaking their own links. Years of posts, search rankings, and inbound links all point at URLs that are about to change. If the new site serves those same paths, nobody notices the move. If it doesn&amp;rsquo;t, you get a lot of 404s and your search traffic drops off.&lt;/p&gt;
&lt;p&gt;So this was a hard requirement, not a nice-to-have. Two things made it work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The post URLs didn&amp;rsquo;t change at all.&lt;/strong&gt; Ghost served my posts at the top level, like &lt;code&gt;/my-post-slug/&lt;/code&gt;. I set Hugo up to do exactly the same, so every old post link resolves to the same place on the new site. No redirect needed, because nothing actually moved.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The one path that did change gets a redirect.&lt;/strong&gt; Ghost puts tags at &lt;code&gt;/tag/&amp;lt;name&amp;gt;/&lt;/code&gt;; Hugo uses &lt;code&gt;/tags/&amp;lt;name&amp;gt;/&lt;/code&gt;. That is the only structural difference, and a single 301 rule on Cloudflare Pages forwards the old shape to the new one.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is the whole SEO story. Because the migration tool treats the slug as something to preserve exactly rather than regenerate, the new site is URL-for-URL compatible with the old one, and the move was invisible to anyone reading or linking to it.&lt;/p&gt;
&lt;h2 id="how-i-publish-now"&gt;how i publish now&lt;/h2&gt;
&lt;p&gt;With the old blog gone, I needed a way to actually publish. The site is just markdown files in a Git repository, so in the simplest case publishing a post is one move: write the markdown, commit, push. I can do that from VS Code, from the terminal, from any editor, on any machine. No login, no admin panel.&lt;/p&gt;
&lt;p&gt;Before I settled on that, I did look at whether some existing tool could smooth it out. There is a whole category of git-based CMSs now, editors that read and write your content straight in a GitHub repo, so you get a writing interface without giving up plain files. I tried a few of them.&lt;/p&gt;
&lt;p&gt;None did exactly what I wanted, and each one came with something I hadn&amp;rsquo;t asked for: an account to sign into, a config schema to keep in sync, or yet another editing UI to learn. After two years of living inside Ghost&amp;rsquo;s admin panel, signing up for one more dashboard was the exact thing I was trying to get away from. So I dropped the idea of a CMS altogether and built my own small tool instead.&lt;/p&gt;
&lt;p&gt;It is an &lt;a href="https://obsidian.md" target="_blank" rel="noopener noreferrer"&gt;Obsidian&lt;/a&gt;
plugin I call Smithy, and I kept its job deliberately tiny. It does three things, and nothing else:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Publish over git.&lt;/strong&gt; It pushes the finished post to the blog&amp;rsquo;s GitHub repo for me. It talks to GitHub through its API rather than shelling out to Git, so it behaves the same on my phone as on my laptop.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto-upload assets.&lt;/strong&gt; Any image in the post is uploaded to my S3-compatible storage (Cloudflare R2) on publish, and the links are rewritten to point at it. The same bucket the migration tool filled.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep the content in the repo.&lt;/strong&gt; The markdown stays as plain files inside the GitHub repo. Nothing lives in a database or a hosted service I don&amp;rsquo;t own.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is the entire plugin. I write a post as a normal Obsidian note, run one command, and those three things happen. It needs a GitHub token and my R2 keys entered once, and after that publishing is a single command. The remote-writing problem that pushed me off Ghost in the first place is simply gone: I can draft and publish from my phone if I feel like it.&lt;/p&gt;
&lt;p&gt;Here is how the whole thing fits together once a post is ready to go out:&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
subgraph author[&amp;#34;write anywhere&amp;#34;]
direction TB
obs[&amp;#34;Obsidian + Smithy&amp;#34;]
phone[&amp;#34;iPhone + Smithy&amp;#34;]
code[&amp;#34;VS Code / terminal&amp;#34;]
end
subgraph repo[&amp;#34;GitHub repo&amp;#34;]
direction TB
md[&amp;#34;Markdown + frontmatter&amp;#34;]
end
r2[(&amp;#34;Cloudflare R2&amp;lt;br/&amp;gt;images &amp;amp; assets&amp;#34;)]
subgraph cf[&amp;#34;Cloudflare Pages&amp;#34;]
direction TB
build[&amp;#34;Hugo build&amp;lt;br/&amp;gt;+ Pagefind index&amp;#34;] --&amp;gt; edge[&amp;#34;CDN edge cache&amp;#34;]
end
reader([&amp;#34;reader&amp;#34;])
obs --&amp;gt;|&amp;#34;GitHub API&amp;#34;| md
phone --&amp;gt;|&amp;#34;GitHub API&amp;#34;| md
code --&amp;gt;|&amp;#34;git push&amp;#34;| md
obs -.-&amp;gt;|&amp;#34;S3 API upload&amp;#34;| r2
phone -.-&amp;gt;|&amp;#34;S3 API upload&amp;#34;| r2
md ==&amp;gt;|&amp;#34;on push, auto-build&amp;#34;| build
r2 --&amp;gt; edge
edge ==&amp;gt; reader&lt;/pre&gt;
&lt;p&gt;It&amp;rsquo;s here if you want to try it: &lt;a href="https://github.com/Harsh-2002/obsidian-smithy" target="_blank" rel="noopener noreferrer"&gt;Smithy&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Is any of this as instant as clicking &amp;ldquo;Publish&amp;rdquo; in a CMS? Not quite. There is a little friction. But for two or three posts a month it is nothing, and in return I get no servers, no database, no lock-in, and content that lives as plain files I will still be able to open years from now.&lt;/p&gt;
&lt;h2 id="what-changed-in-practice"&gt;what changed, in practice&lt;/h2&gt;
&lt;p&gt;The honest summary is that there is no infrastructure left to run. The site is static files on Cloudflare&amp;rsquo;s edge, so uptime is their job, not mine. R2 holds the images for almost nothing. There is no server to patch, no database to back up, no security hardening, and nothing exposed to attack. The operations side of running a blog basically disappeared.&lt;/p&gt;
&lt;p&gt;It is also just faster. Plain files on a CDN beat a Node app querying a database on every request. The site loads quicker than it ever did on Ghost, from more places.&lt;/p&gt;
&lt;h2 id="what-i-gave-up"&gt;what i gave up&lt;/h2&gt;
&lt;p&gt;A static site isn&amp;rsquo;t free of trade-offs, and it would be dishonest to pretend otherwise. Moving to one means giving up a few things a CMS hands you for free:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No built-in comments.&lt;/strong&gt; A static page can&amp;rsquo;t run a comment system on its own. If you want one, you bolt on a third-party service. I don&amp;rsquo;t, so for me this was a feature to delete, but it is a real loss if a comment section matters to you.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No dynamic anything.&lt;/strong&gt; No server means no forms, no member logins, no per-visitor pages, no newsletter or paid membership built in. Every reader gets the same files. For me that is the whole point; for a different blog it would be a dealbreaker.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No writing in the browser.&lt;/strong&gt; Ghost let me open a tab and write from anywhere. Now I write in an editor and publish through Smithy or a git commit. That is friction I chose on purpose, but it is still friction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Search ships with the page.&lt;/strong&gt; Pagefind builds the search index at build time, so it grows with the site and the reader downloads part of it to search. At my size that is nothing. A site with tens of thousands of pages would have to think harder about it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of these were hard to give up for a personal blog. But they are exactly why &amp;ldquo;just go static&amp;rdquo; is the right call for me and the wrong one for plenty of other people.&lt;/p&gt;
&lt;h2 id="the-part-i-keep-relearning"&gt;the part i keep relearning&lt;/h2&gt;
&lt;p&gt;This is the lesson I keep coming back to as someone who does infrastructure for a living. Keep it simple, and don&amp;rsquo;t take on complexity just because you can handle it. I could run the Ghost stack. I did, for two years. Being able to manage something is not a reason to. For a personal blog, the right amount of infrastructure turned out to be almost none.&lt;/p&gt;
&lt;p&gt;One last honest note. Blogs aren&amp;rsquo;t what they were. As AI gets better at answering the questions people used to type into a search box, fewer of them end up on posts like this one, and I expect my traffic to keep drifting down. That is fine. I&amp;rsquo;m not writing for the traffic. I write this for myself, as a place to keep the things I work out so I don&amp;rsquo;t have to work them out again, and as a kind of memory. If you got here and something helped, even better.&lt;/p&gt;
&lt;p&gt;If you want to see what else I&amp;rsquo;m building, my projects are on &lt;a href="https://github.com/Harsh-2002" target="_blank" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
, and my DMs are open. Say hi.&lt;/p&gt;</content></entry><entry><title>Running Hermes Agent on Your Own Box</title><link href="https://firstfinger.io/running-hermes-agent-on-your-own-box/"/><id>https://firstfinger.io/running-hermes-agent-on-your-own-box/</id><updated>2026-05-28T00:00:00Z</updated><published>2026-05-28T00:00:00Z</published><category term="Linux"/><category term="Container"/><category term="MacOS"/><summary>A complete self-hosted AI agent on your own box. Reachable from Telegram by text or voice, runs your servers, connects to your tools via MCP, updates itself nightly.</summary><content type="html">&lt;p&gt;Self-hosted AI agent on Linux. Talks to you on Telegram, runs commands, manages servers, connects to tools via MCP. This is the fast path. Run the blocks top to bottom. Replace &lt;code&gt;youruser&lt;/code&gt; with your Linux username everywhere.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/2026/05/running-hermes-agent-on-your-own-box/pasted-image-20260528175133.png" alt="Pasted image 20260528175133"&gt;&lt;/p&gt;
&lt;p&gt;Hermes is the agent. You plug a model into it (OpenAI, Gemini, local endpoint). Keep that straight.&lt;/p&gt;
&lt;h2 id="1-install"&gt;1. Install&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh &lt;span class="p"&gt;|&lt;/span&gt; bash
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;which hermes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note the path (usually &lt;code&gt;~/.local/bin/hermes&lt;/code&gt;). You need it for the service.&lt;/p&gt;
&lt;h2 id="2-setup-wizard"&gt;2. Setup wizard&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hermes setup
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pick your model provider and API key. Terminal: local. Skip TTS.&lt;/p&gt;
&lt;h2 id="3-telegram-bot"&gt;3. Telegram bot&lt;/h2&gt;
&lt;p&gt;In Telegram: message &lt;code&gt;@BotFather&lt;/code&gt;, &lt;code&gt;/newbot&lt;/code&gt;, copy the token. Message &lt;code&gt;@userinfobot&lt;/code&gt;, copy your numeric ID.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt;&amp;gt; ~/.hermes/.env &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;TELEGRAM_BOT_TOKEN=your_bot_token
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;TELEGRAM_ALLOWED_USERS=your_numeric_id
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;TELEGRAM_HOME_CHANNEL=your_numeric_id
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="4-run-as-a-system-service"&gt;4. Run as a system service&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo &lt;span class="k"&gt;$(&lt;/span&gt;which hermes&lt;span class="k"&gt;)&lt;/span&gt; gateway install --system --run-as-user youruser
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo &lt;span class="k"&gt;$(&lt;/span&gt;which hermes&lt;span class="k"&gt;)&lt;/span&gt; gateway start --system
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl status hermes-gateway
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Message your bot &amp;ldquo;hi&amp;rdquo; on Telegram. It should reply.&lt;/p&gt;
&lt;h2 id="5-voice-groq-stt"&gt;5. Voice (Groq STT)&lt;/h2&gt;
&lt;p&gt;Key from console.groq.com.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt;&amp;gt; ~/.hermes/.env &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;GROQ_API_KEY=your_groq_key
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;STT_GROQ_MODEL=whisper-large-v3-turbo
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hermes config &lt;span class="nb"&gt;set&lt;/span&gt; stt.provider groq
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl restart hermes-gateway
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="6-web-search-tavily"&gt;6. Web search (Tavily)&lt;/h2&gt;
&lt;p&gt;Free key from app.tavily.com.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;TAVILY_API_KEY=your_tavily_key&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.hermes/.env
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl restart hermes-gateway
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="7-github"&gt;7. GitHub&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo apt install -y curl
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg &lt;span class="p"&gt;|&lt;/span&gt; sudo dd &lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/share/keyrings/githubcli-archive-keyring.gpg
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;deb [arch=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;dpkg --print-architecture&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sudo tee /etc/apt/sources.list.d/github-cli.list &amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo apt install -y gh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gh auth login
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pick GitHub.com, HTTPS, browser login. Open github.com/login/device, paste the code. Then:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;GITHUB_TOKEN=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;gh auth token&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; ~/.hermes/.env
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl restart hermes-gateway
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="8-persona-soulmd"&gt;8. Persona (SOUL.md)&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; ~/.hermes/SOUL.md &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;# Identity
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;You are a pragmatic senior engineer. Talk to me as a technical peer.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;# Style
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Lead with the answer or command. No preamble.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Terse by default. Code first, short explanation after.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- No em-dashes. No emojis. Plain, direct language.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Say when something is a bad idea and give the better option.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- State uncertainty instead of guessing. Verify with tools.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;# Defaults
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- On ambiguity, assume the reasonable thing, state it, proceed.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;- Multi-step work: brief plan, then execute end to end.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl restart hermes-gateway
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="9-fallback-model-gemini"&gt;9. Fallback model (Gemini)&lt;/h2&gt;
&lt;p&gt;Free key from aistudio.google.com.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;GOOGLE_API_KEY=your_aistudio_key&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.hermes/.env
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hermes fallback add
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pick Gemini, API key, gemini-2.5-flash. Check: &lt;code&gt;hermes fallback list&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="10-mcp-servers"&gt;10. MCP servers&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt;&amp;gt; ~/.hermes/.env &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;CONTEXT7_API_KEY=your_context7_key
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;N8N_MCP_TOKEN=your_n8n_token
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nano ~/.hermes/config.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add under &lt;code&gt;mcp_servers:&lt;/code&gt; (2-space indent, spaces only):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;mcp_servers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;github&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;npx&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;-y&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;@modelcontextprotocol/server-github&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;GITHUB_PERSONAL_ACCESS_TOKEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;${GITHUB_TOKEN}&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;context7&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://mcp.context7.com/mcp&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Bearer ${CONTEXT7_API_KEY}&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;n8n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://your-n8n-domain/mcp-server/http&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Bearer ${N8N_MCP_TOKEN}&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Validate and restart:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 -c &lt;span class="s2"&gt;&amp;#34;import yaml; yaml.safe_load(open(&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.hermes/config.yaml&amp;#39;))&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; valid
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl restart hermes-gateway
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hermes mcp list
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hermes mcp &lt;span class="nb"&gt;test&lt;/span&gt; github
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Servers with &lt;code&gt;url:&lt;/code&gt; are HTTP. Servers with &lt;code&gt;command:&lt;/code&gt; are spawned by Hermes. Use what the server documents.&lt;/p&gt;
&lt;h2 id="11-fix-the-auto-update-password-problem"&gt;11. Fix the auto-update password problem&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;hermes update&lt;/code&gt; restarts the service, which needs passwordless sudo. Without this it prompts for a password and the nightly cron breaks. Check your systemctl path first:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;which systemctl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Use that exact path in the rule. If it says &lt;code&gt;/usr/bin/systemctl&lt;/code&gt; but your rule says &lt;code&gt;/bin/systemctl&lt;/code&gt;, sudo ignores it and asks for a password. This is the most common mistake.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo tee /etc/sudoers.d/hermes-gateway &amp;gt; /dev/null &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;youruser ALL=(root) NOPASSWD: /usr/bin/systemctl restart hermes-gateway, /usr/bin/systemctl start hermes-gateway, /usr/bin/systemctl stop hermes-gateway, /usr/bin/systemctl reset-failed hermes-gateway, /usr/bin/systemctl is-active hermes-gateway, /usr/bin/systemctl status hermes-gateway
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chmod &lt;span class="m"&gt;440&lt;/span&gt; /etc/sudoers.d/hermes-gateway
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo visudo -c
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Test, should NOT ask for a password:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl restart hermes-gateway
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hermes update
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="12-nightly-auto-update-cron"&gt;12. Nightly auto-update cron&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install -y cron
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; --now cron
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo timedatectl set-timezone Your/Timezone
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;crontab -e
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add this line (runs 3:30 AM):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;30 3 * * * $HOME/.local/bin/hermes update --check &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp;&amp;amp; $HOME/.local/bin/hermes update &amp;gt;&amp;gt; $HOME/.hermes/logs/auto-update.log 2&amp;gt;&amp;amp;1; sleep 30; /usr/bin/systemctl is-active hermes-gateway &amp;gt;&amp;gt; $HOME/.hermes/logs/auto-update.log 2&amp;gt;&amp;amp;1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="13-validate"&gt;13. Validate&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl is-active hermes-gateway
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hermes -z &lt;span class="s2"&gt;&amp;#34;say hi in 3 words&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hermes mcp list
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hermes doctor
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;From Telegram: send text, send a voice note, ask &amp;ldquo;list files in /tmp&amp;rdquo;, ask &amp;ldquo;list my GitHub issues&amp;rdquo;. If all work, done.&lt;/p&gt;
&lt;h2 id="notes"&gt;Notes&lt;/h2&gt;
&lt;p&gt;Lock &lt;code&gt;TELEGRAM_ALLOWED_USERS&lt;/code&gt; to just your ID. Anyone on that list can run commands through the agent.&lt;/p&gt;
&lt;p&gt;Use a dedicated Linux user and a dedicated VM. The agent gets shell access, treat the box as disposable.&lt;/p&gt;
&lt;p&gt;For zero approval prompts on a trusted box, set in config.yaml:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;approvals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;auto&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cron_mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;allow&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This lets the agent run anything without asking. Right for a single-user locked-down VM, wrong if others can reach the bot.&lt;/p&gt;
&lt;h2 id="manage-the-service"&gt;Manage the service&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl restart hermes-gateway
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl status hermes-gateway
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo journalctl -u hermes-gateway -f
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That is the whole setup. The real value comes after: tell the agent to save useful multi-step solutions as skills, and tell it facts about your environment so it learns you over time.&lt;/p&gt;</content></entry><entry><title>Fixing xterm-ghostty: unknown terminal type Over SSH</title><link href="https://firstfinger.io/fixing-xterm-ghostty-unknown-terminal-type-ssh/"/><id>https://firstfinger.io/fixing-xterm-ghostty-unknown-terminal-type-ssh/</id><updated>2026-05-27T13:10:00Z</updated><published>2026-05-27T13:10:00Z</published><author><name>Anurag Vishwakarma</name></author><category term="Linux"/><category term="How to"/><category term="MacOS"/><summary>Why Ghostty's xterm-ghostty terminfo breaks SSH into remote Linux servers, why ssh-terminfo makes it worse, and the two-step fix that makes the problem go away for good.</summary><content type="html">&lt;p&gt;If you use Ghostty as your terminal on macOS and SSH into remote Linux servers, you&amp;rsquo;ve probably seen this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;root@server:~# clear
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;#39;xterm-ghostty&amp;#39;: unknown terminal type.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;missing or unsuitable terminal: xterm-ghostty
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This happens to everyone who uses Ghostty with remote servers. Here&amp;rsquo;s why it happens and how to fix it properly.&lt;/p&gt;
&lt;h2 id="why-this-happens"&gt;Why this happens&lt;/h2&gt;
&lt;p&gt;Ghostty ships with its own terminfo entry called &lt;code&gt;xterm-ghostty&lt;/code&gt;. When you open a terminal, Ghostty sets &lt;code&gt;TERM=xterm-ghostty&lt;/code&gt; in your local shell. When you SSH into a remote server, that &lt;code&gt;TERM&lt;/code&gt; value gets forwarded. The remote server then looks up &lt;code&gt;xterm-ghostty&lt;/code&gt; in its terminfo database — and finds nothing, because &lt;code&gt;xterm-ghostty&lt;/code&gt; is not in any standard Linux distribution yet.&lt;/p&gt;
&lt;p&gt;Commands like &lt;code&gt;clear&lt;/code&gt;, &lt;code&gt;vim&lt;/code&gt;, &lt;code&gt;tmux&lt;/code&gt;, and &lt;code&gt;htop&lt;/code&gt; all rely on terminfo to know how to talk to your terminal. No terminfo entry means broken output.&lt;/p&gt;
&lt;h2 id="the-trap-ssh-terminfo-makes-it-worse"&gt;The trap: &lt;code&gt;ssh-terminfo&lt;/code&gt; makes it worse&lt;/h2&gt;
&lt;p&gt;Ghostty has a built-in feature called &lt;code&gt;ssh-terminfo&lt;/code&gt; that tries to automatically install the &lt;code&gt;xterm-ghostty&lt;/code&gt; terminfo on remote hosts before connecting. On paper this sounds like the right fix. In practice it causes a worse problem.&lt;/p&gt;
&lt;p&gt;The feature wraps your &lt;code&gt;ssh&lt;/code&gt; command as a shell function. Every time you SSH, it tries to run &lt;code&gt;tic&lt;/code&gt; on the remote host to install the terminfo. For servers behind a &lt;code&gt;ProxyJump&lt;/code&gt;, air-gapped servers, or servers with restricted environments, the install process partially succeeds — returns exit 0 — but the terminfo is not actually usable. The function then assumes success and sets &lt;code&gt;TERM=xterm-ghostty&lt;/code&gt; for the session anyway. You land on the server with a broken terminal.&lt;/p&gt;
&lt;p&gt;Worse, this shell function override happens &lt;strong&gt;after&lt;/strong&gt; your &lt;code&gt;~/.ssh/config&lt;/code&gt; is read, so any &lt;code&gt;SetEnv TERM=xterm-256color&lt;/code&gt; you put there gets silently overridden.&lt;/p&gt;
&lt;p&gt;This is the config that enables the broken behavior:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;shell-integration-features = ssh-env,ssh-terminfo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="the-actual-fix"&gt;The actual fix&lt;/h2&gt;
&lt;p&gt;There are two parts. Fix them both.&lt;/p&gt;
&lt;h3 id="1-disable-ssh-terminfo-in-ghostty-config"&gt;1. Disable ssh-terminfo in Ghostty config&lt;/h3&gt;
&lt;p&gt;Find your Ghostty config file. On macOS it is usually at:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;~/Library/Application Support/com.mitchellh.ghostty/config
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Change your &lt;code&gt;shell-integration-features&lt;/code&gt; line to remove &lt;code&gt;ssh-env&lt;/code&gt; and &lt;code&gt;ssh-terminfo&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;shell-integration-features = cursor,title,path
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Reload the config with &lt;code&gt;Cmd+Shift+,&lt;/code&gt; or fully quit and reopen Ghostty.&lt;/p&gt;
&lt;p&gt;Verify the ssh shell function is no longer overriding TERM:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$GHOSTTY_SHELL_FEATURES&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# should not contain ssh-env or ssh-terminfo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-set-term-globally-in-sshconfig"&gt;2. Set TERM globally in ~/.ssh/config&lt;/h3&gt;
&lt;p&gt;Add &lt;code&gt;SetEnv TERM=xterm-256color&lt;/code&gt; to your global &lt;code&gt;Host *&lt;/code&gt; block. This tells the remote server to use &lt;code&gt;xterm-256color&lt;/code&gt;, which has been in every Linux terminfo database for over 20 years.&lt;/p&gt;
&lt;p&gt;One important rule: &lt;code&gt;Host *&lt;/code&gt; must be at the &lt;strong&gt;bottom&lt;/strong&gt; of your &lt;code&gt;~/.ssh/config&lt;/code&gt;. SSH reads the file top to bottom and the first match wins for each option. If &lt;code&gt;Host *&lt;/code&gt; is at the top, it overrides all your specific host blocks.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# specific hosts first
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Host myserver
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; HostName 10.0.0.1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; User deploy
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# global defaults last
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Host *
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; User root
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; StrictHostKeyChecking no
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; UserKnownHostsFile /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; SetEnv TERM=xterm-256color
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After both changes, SSH into any server and run &lt;code&gt;clear&lt;/code&gt; — it works.&lt;/p&gt;
&lt;h2 id="why-not-just-push-terminfo-to-every-server"&gt;Why not just push terminfo to every server?&lt;/h2&gt;
&lt;p&gt;The official Ghostty docs suggest running this on each remote host:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;infocmp -x xterm-ghostty &lt;span class="p"&gt;|&lt;/span&gt; ssh user@server -- tic -x -
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works for servers you own and access regularly. It is not practical if you manage dozens or hundreds of servers, have air-gapped hosts with no outbound connectivity, or SSH into servers you do not control.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;xterm-256color&lt;/code&gt; approach trades a small amount of Ghostty-specific terminal features for universal compatibility. In practice you keep full 256 color support, all standard cursor sequences, and everything TUI apps need. The only things you lose are a few Ghostty-specific extensions that most remote workflows do not use anyway.&lt;/p&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;xterm-ghostty: unknown terminal type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remote server has no Ghostty terminfo&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;TERM=xterm-256color&lt;/code&gt; via &lt;code&gt;~/.ssh/config&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SetEnv&lt;/code&gt; in ssh config is ignored&lt;/td&gt;
&lt;td&gt;Ghostty &lt;code&gt;ssh-terminfo&lt;/code&gt; shell function overrides it&lt;/td&gt;
&lt;td&gt;Disable &lt;code&gt;ssh-terminfo&lt;/code&gt; in Ghostty config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Specific hosts use wrong user&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Host *&lt;/code&gt; is at top of ssh config&lt;/td&gt;
&lt;td&gt;Move &lt;code&gt;Host *&lt;/code&gt; to bottom&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Two files to get right, and the problem never comes back.&lt;/p&gt;</content></entry><entry><title>Why Postgres is the last database you'll need ?</title><link href="https://firstfinger.io/why-postgres-is-the-last-database-youll-need/"/><id>https://firstfinger.io/why-postgres-is-the-last-database-youll-need/</id><updated>2026-04-24T20:10:12Z</updated><published>2026-04-24T20:10:12Z</published><author><name>Anurag Vishwakarma</name></author><summary>Postgres can handle cache, queues, full-text search, pub/sub and vector workloads out of the box.</summary><content type="html">&lt;p&gt;Every few months someone on the team opens a Slack thread with &amp;ldquo;should we add Redis?&amp;rdquo; or &amp;ldquo;do we really need Kafka for this?&amp;rdquo; The answer is usually the same. Not yet. Possibly never.&lt;/p&gt;
&lt;p&gt;I have been running Postgres in production for a while now. Over the years I have watched it quietly absorb features that people used to stand up entirely separate services for. At some point you stop thinking of Postgres as &amp;ldquo;the relational database&amp;rdquo; and start thinking of it as the default place data goes. Everything else has to earn its spot on the architecture diagram.&lt;/p&gt;
&lt;p&gt;This is a short tour of what a single Postgres instance can do before you start adding other boxes to that diagram.&lt;/p&gt;
&lt;h2 id="it-is-a-relational-database-that-is-the-boring-part"&gt;It is a relational database. That is the boring part.&lt;/h2&gt;
&lt;p&gt;ACID transactions, foreign keys, joins, row level security, materialised views, window functions, CTEs, declarative partitioning. You already know this part. MVCC means readers don&amp;rsquo;t block writers and writers don&amp;rsquo;t block readers. The planner is mature. Decades of production hardening sit behind it. None of this is new.&lt;/p&gt;
&lt;p&gt;What people miss is that the same engine running your OLTP workload is also good enough to replace three or four other services in most applications.&lt;/p&gt;
&lt;h2 id="a-cache-that-you-already-have"&gt;A cache that you already have&lt;/h2&gt;
&lt;p&gt;For session data, rate limit counters, or computed results that are annoying to regenerate, an &lt;code&gt;UNLOGGED&lt;/code&gt; table gets you most of the way there.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UNLOGGED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cache_entries&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;JSONB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;expires_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;UNLOGGED&lt;/code&gt; tells Postgres to skip the WAL for this table. Writes are faster because nothing is being streamed to the write-ahead log, and there is no replication overhead. The tradeoff is that the table is truncated on crash recovery. For a cache, that is acceptable behaviour. It is a cache only. It is supposed to be refillable.&lt;/p&gt;
&lt;p&gt;The write path tells the story:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/04/image.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Fewer fsyncs, no WAL record, no network traffic to replicas. On a write-heavy cache workload, this is where the speed comes from.&lt;/p&gt;
&lt;p&gt;You will not beat Redis on sub-millisecond hot path work. If you are running a real-time bidding system or a game leaderboard with thousands of concurrent updates per key, keep Redis. For most web applications where the user cannot tell the difference between 2 ms and 5 ms, an unlogged table works fine and you have one less daemon to operate.&lt;/p&gt;
&lt;h2 id="a-job-queue-without-the-broker"&gt;A job queue, without the broker&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;SELECT ... FOR UPDATE SKIP LOCKED&lt;/code&gt; turns a regular table into a proper worker queue.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;job_queue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;processing&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;started_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;job_queue&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pending&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SKIP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LOCKED&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;RETURNING&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each worker locks exactly one row. Other workers see the lock, skip it, and take the next available row. No duplicate delivery. If a worker crashes mid-job, the transaction rolls back and the row goes back into the pool on its own.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/04/image-3.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Pair it with a partial index on &lt;code&gt;WHERE status = 'pending'&lt;/code&gt; and the index stays small forever, even after you have processed ten million jobs. The completed rows drop out of the index as their status changes.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pg-boss&lt;/code&gt; in Node, &lt;code&gt;river&lt;/code&gt; in Go, Solid Queue in Rails, all of them are built on this exact pattern. If your job volume is under a few thousand per second, you do not need RabbitMQ. A table and a partial index will do.&lt;/p&gt;
&lt;h2 id="full-text-search-properly-indexed"&gt;Full-text search, properly indexed&lt;/h2&gt;
&lt;p&gt;If you have written &lt;code&gt;WHERE title ILIKE '%something%'&lt;/code&gt; on a production table, you know how this ends. A leading wildcard forces a sequential scan, and sequential scans get slower as the table grows.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tsvector&lt;/code&gt; and GIN indexes solve this properly.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;articles&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;SERIAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;search_vector&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tsvector&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;idx_articles_search&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;articles&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;USING&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;search_vector&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The difference at the planner level is stark:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/04/image-1.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;You also get stemming, stop-word removal, ranking with &lt;code&gt;ts_rank&lt;/code&gt;, phrase search, prefix matching, weighted fields. All of it in core. No extension required. If you need more, &lt;code&gt;pg_trgm&lt;/code&gt; adds trigram similarity for typo-tolerant search, and &lt;code&gt;pgvector&lt;/code&gt; handles semantic search through embeddings.&lt;/p&gt;
&lt;p&gt;For a product catalog, blog search, or an internal admin tool, this is enough. You probably do not need Elasticsearch until well past the first million documents.&lt;/p&gt;
&lt;h2 id="pubsub-without-another-daemon"&gt;Pub/sub without another daemon&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;LISTEN/NOTIFY&lt;/code&gt; has been in Postgres for a long time and most people have not touched it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- subscriber side
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LISTEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new_order&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- publisher side, from another session or a trigger
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;new_order&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{&amp;#34;id&amp;#34;: 42, &amp;#34;amount&amp;#34;: 1500}&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Drop a trigger on &lt;code&gt;INSERT&lt;/code&gt; that calls &lt;code&gt;pg_notify&lt;/code&gt;, and every new row fans out to whoever is listening.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/04/image-2.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Works for real-time dashboards, cache invalidation, websocket fan-out, and background worker wake-ups.&lt;/p&gt;
&lt;p&gt;The caveats are real. Payload limit is 8000 bytes. It does not play well with PgBouncer in transaction pooling mode because connection affinity breaks. Messages are not persisted, so if nobody is listening when &lt;code&gt;NOTIFY&lt;/code&gt; fires, the message is gone. For what it is, it solves a real problem without adding infrastructure.&lt;/p&gt;
&lt;h2 id="jsonb-for-when-your-schema-is-not-ready"&gt;JSONB, for when your schema is not ready&lt;/h2&gt;
&lt;p&gt;Sometimes you have genuinely unstructured data. Webhook payloads from vendors who change their schema on a whim. Feature flags. User preferences. Audit logs where each event type has different fields.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;JSONB&lt;/code&gt; gives you document storage inside your relational database. You can index individual keys with GIN, query with &lt;code&gt;-&amp;gt;&lt;/code&gt;, &lt;code&gt;-&amp;gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;@&amp;gt;&lt;/code&gt;, &lt;code&gt;jsonb_path_query&lt;/code&gt;. You can enforce partial schema through check constraints where it matters, and leave the rest flexible.&lt;/p&gt;
&lt;p&gt;This is not a reason to stop using proper columns when you know the schema. It is a reason to stop running MongoDB next to Postgres for one table full of half-known JSON.&lt;/p&gt;
&lt;h2 id="extensions"&gt;Extensions&lt;/h2&gt;
&lt;p&gt;Core Postgres is already doing a lot. Then you have the extension ecosystem.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pgvector&lt;/code&gt; for vector similarity search with HNSW and IVFFlat indexes. RAG pipelines, recommendation engines, semantic search.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TimescaleDB&lt;/code&gt; turns Postgres into a proper time-series database with hypertables, native compression, and continuous aggregates. Metrics, IoT telemetry, financial ticks.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PostGIS&lt;/code&gt; is still the gold standard for geospatial. Not &amp;ldquo;good enough&amp;rdquo;, actually best in class.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pg_cron&lt;/code&gt; schedules jobs inside the database itself. No separate cron container, no Kubernetes CronJob object. A row in a table that says &amp;ldquo;run this SQL every five minutes&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pg_partman&lt;/code&gt; automates partition creation and retention for time-based tables.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pg_stat_statements&lt;/code&gt; and &lt;code&gt;auto_explain&lt;/code&gt; are how you figure out what is slow in production. If you are not using these, you are flying blind.&lt;/li&gt;
&lt;li&gt;Foreign Data Wrappers let you query other Postgres instances, MySQL, MongoDB, even a CSV file, as if they were local tables.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Extensions are first class citizens. &lt;code&gt;CREATE EXTENSION pgvector;&lt;/code&gt; and you are done. No separate service, no separate wire protocol, no separate auth model.&lt;/p&gt;
&lt;h2 id="who-actually-runs-on-postgres"&gt;Who actually runs on Postgres&lt;/h2&gt;
&lt;p&gt;You do not have to take this on faith. Some of the largest workloads on the internet run on Postgres, and the engineering teams have written publicly about how.&lt;/p&gt;
&lt;h3 id="openai"&gt;OpenAI&lt;/h3&gt;
&lt;p&gt;OpenAI runs ChatGPT and the API platform for roughly 800 million users on a single-primary Postgres instance on Azure, backed by close to 50 read replicas spread across regions. Millions of queries per second, p99 latency in the low double-digit milliseconds. They did not shard the primary, they tuned and optimised aggressively.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/04/image-4.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Their engineering writeup: &lt;a href="https://openai.com/index/scaling-postgresql/" target="_blank" rel="noopener noreferrer"&gt;https://openai.com/index/scaling-postgresql/&lt;/a&gt;
&lt;/p&gt;
&lt;a class="bookmark" href="https://posetteconf.com/2025/talks/scaling-postgres-to-the-next-level-at-openai/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/thumbnail/Bohan_Zhang-posetteconf2025-1200x630.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Scaling Postgres to the next level at OpenAI | POSETTE: An Event for Postgres 2025&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;“Scaling Postgres to the next level at OpenAI” is a talk by Bohan Zhang for Livestream 1 of POSETTE: An Event for Postgres 2025.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;POSETTE&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h3 id="notion"&gt;Notion&lt;/h3&gt;
&lt;p&gt;Notion stores roughly 200 billion blocks across 480 logical shards on 96 physical Postgres instances. Every page, every block, every comment is a relatively simple Postgres row, replicated across shards with application-level routing keyed on &lt;code&gt;workspace_id&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/04/image-5.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Their &amp;ldquo;Herding Elephants&amp;rdquo; post covers the original 2021 shard &amp;amp; The follow-up on adding capacity with zero downtime:&lt;/p&gt;
&lt;a class="bookmark" href="https://www.notion.com/blog/sharding-postgres-at-notion"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/thumbnail/sharding-thumb.png" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Herding elephants: lessons learned from sharding Postgres at Notion&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;With an effort to make Notion faster and more reliable for years to come — we migrated Notion’s PostgreSQL monolith into a horizontally-partitioned database fleet.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;Notion · Garrett Fidalgo&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://www.notion.com/blog/the-great-re-shard"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/thumbnail/sharding-2-thumb.png" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;The Great Re-shard: adding Postgres capacity (again) with zero downtime&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Why and how we horizontally re-sharded our databases&lt;/p&gt;
&lt;span class="bookmark-host"&gt;Notion · Arka Ganguli, Tanner Johnson, Ben Kraft, Nathan Northcutt&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h3 id="figma"&gt;Figma&lt;/h3&gt;
&lt;p&gt;Figma went the other direction from Notion and did vertical partitioning, splitting tables across servers rather than sharding rows across instances. Different approach, same underlying database.&lt;/p&gt;
&lt;a class="bookmark" href="https://www.figma.com/blog/how-figmas-databases-team-lived-to-tell-the-scale/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/thumbnail/eb69f56265b7cda32a4b043d80147928a3a400ab-1608x1204.png" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;How Figma’s Databases Team Lived to Tell the Scale | Figma Blog&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Our nine month journey to horizontally shard Figma’s Postgres stack, and the key to unlocking (nearly) infinite scalability.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;Figma · Sammy Steele&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h3 id="instagram"&gt;Instagram&lt;/h3&gt;
&lt;p&gt;Instagram has run on Postgres since before the Facebook acquisition and publicly stayed with it through hundreds of millions of users. Their early engineering posts on scaling Postgres are still referenced in sharding discussions today.&lt;/p&gt;
&lt;h3 id="others-worth-knowing-about"&gt;Others worth knowing about&lt;/h3&gt;
&lt;p&gt;GitLab runs on Postgres. Heroku&amp;rsquo;s own control plane does. Reddit has used it for core metadata for years. A long tail of fintechs, SaaS companies, and government systems sit on Postgres and do not talk about it publicly.&lt;/p&gt;
&lt;p&gt;The common thread across these stories is the same. They hit scaling limits, they optimised, they sharded or partitioned when they had to, but they did not abandon Postgres. The engineering effort to scale it turned out to be meaningfully less than the engineering effort to migrate off it.&lt;/p&gt;
&lt;h2 id="the-part-nobody-talks-about---you-own-your-data"&gt;The part nobody talks about - you own your data&lt;/h2&gt;
&lt;p&gt;Every managed cloud database is also a vendor lock-in story. DynamoDB data lives inside AWS. Firestore is GCP only. Cosmos DB belongs to Azure. Moving off any of them is a migration project, not a config change.&lt;/p&gt;
&lt;p&gt;Postgres is open source under a permissive license. Your data sits in a format a hundred tools can read. You can run it on RDS, Aurora, Cloud SQL, Azure Database, Neon, Supabase, Crunchy Data, or your own Ubuntu box in a rack. The wire protocol is the same. The dump format is the same. &lt;code&gt;pg_dump&lt;/code&gt; from one provider, &lt;code&gt;pg_restore&lt;/code&gt; to another, a weekend of work rather than a quarter.&lt;/p&gt;
&lt;p&gt;This matters when pricing changes. When a provider has an outage pattern you cannot tolerate. When compliance requirements shift and data has to sit inside the country. When you simply want to leave. Optionality is a feature and very few databases actually give it to you.&lt;/p&gt;
&lt;h2 id="where-you-genuinely-should-stop"&gt;Where you genuinely should stop&lt;/h2&gt;
&lt;p&gt;Postgres does not do everything, and pretending otherwise is how teams end up with production incidents.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sub-millisecond cache hits at a million QPS, you want Redis or Memcached.&lt;/li&gt;
&lt;li&gt;Millions of messages per second with durable fan-out, consumer groups, and replay semantics, you want Kafka.&lt;/li&gt;
&lt;li&gt;Distributed search across terabytes with complex CJK analyzers and deep faceted aggregations, you want Elasticsearch or OpenSearch.&lt;/li&gt;
&lt;li&gt;Petabyte-scale analytical scans, you want ClickHouse, Druid, or a proper warehouse like Snowflake or BigQuery.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These tools exist because the problems they solve are real. If you hit those walls, your benchmarks will tell you which workload is the actual bottleneck.&lt;/p&gt;
&lt;h2 id="in-simple-words"&gt;In simple words&amp;hellip;&lt;/h2&gt;
&lt;p&gt;Start with Postgres. One database to back up, one to monitor, one connection pooler to tune, one replication topology, one set of alerts in Grafana, one thing to patch when the next CVE drops. When Postgres starts hurting on a specific workload, and only then, extract that workload into a dedicated service. By that point you will have production metrics that tell you exactly why, which is a much better place to be than guessing on day one.&lt;/p&gt;</content></entry><entry><title>The Userspace Tax Behind Protocols - QUIC(UDP) vs TCP</title><link href="https://firstfinger.io/quic-udp-vs-tcp-protocol/"/><id>https://firstfinger.io/quic-udp-vs-tcp-protocol/</id><updated>2026-03-19T11:24:27Z</updated><published>2026-03-19T08:24:43Z</published><author><name>Anurag Vishwakarma</name></author><category term="Network"/><category term="Linux"/><summary>QUIC and TCP are not interchangeable.</summary><content type="html">&lt;p&gt;When you&amp;rsquo;re building a service that requires inter-node communication, one of the earliest decisions is choosing a transport protocol. Nodes need to talk to each other reliably, consistently, and fast. That means picking a foundation to build on.&lt;/p&gt;
&lt;p&gt;At the transport layer, there are really only two foundations: &lt;strong&gt;TCP&lt;/strong&gt; and &lt;strong&gt;UDP&lt;/strong&gt;. Everything else is built on top of one of these two. On top of TCP, we have protocols battle-tested in production for years like HTTPS, gRPC, WebSocket, and other custom protocols. These inherit TCP&amp;rsquo;s reliability, ordering, and congestion control for free because TCP handles all of that at the kernel level. On top of UDP, the most prominent protocol today is &lt;strong&gt;QUIC&lt;/strong&gt;. Designed by Google, standardized as RFC 9000, and powering HTTP/3, QUIC is the one that keeps coming up when teams discuss transport choices.&lt;/p&gt;
&lt;p&gt;So when a team needs to decide how their cluster nodes communicate internally, the conversation often lands on: should we use something over TCP, or should we use QUIC over UDP? And this is where the misconception begins.&lt;/p&gt;
&lt;h2 id="the-misconception"&gt;The misconception&lt;/h2&gt;
&lt;p&gt;QUIC sounds like a strong candidate. It is modern. It has built-in encryption. It solves head-of-line blocking. Google uses it. HTTP/3 runs on it. It is, by most accounts, a well-engineered protocol.&lt;/p&gt;
&lt;p&gt;Push back with TCP, and the rebuttal is almost always: &amp;ldquo;&lt;em&gt;&lt;strong&gt;gRPC also runs in userspace too. So does HTTP. So does WebSocket. Every protocol above the kernel is userspace. QUIC being in userspace is no different.&lt;/strong&gt;&lt;/em&gt;&amp;rdquo; That sounds convincing. It is also wrong. But the reason it&amp;rsquo;s wrong is not obvious unless you trace the actual packet flow for both approaches.&lt;/p&gt;
&lt;p&gt;Comparing QUIC to TCP for inter-node communication is not a matter of trade-offs. It is a category error. QUIC was designed for a specific environment that looks nothing like the inside of a cluster.&lt;/p&gt;
&lt;h2 id="understanding-the-protocol-layers"&gt;Understanding the protocol layers&lt;/h2&gt;
&lt;p&gt;This is where most of the confusion comes from, and where the conversation usually goes sideways. People treat TCP and QUIC as direct alternatives. Swap one for the other. But they sit differently in the protocol stack, and that difference is the entire point.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/03/image-19.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;TCP is a transport protocol that lives in the kernel. UDP is a transport protocol that lives in the kernel. They are peers.&lt;/p&gt;
&lt;p&gt;QUIC is also a transport protocol but it does not live in the kernel. It lives in userspace and uses UDP underneath as a tunneling layer. UDP is there because it&amp;rsquo;s the simplest way to get packets through internet middleboxes, NATs, and firewalls that would otherwise drop unknown protocol numbers.&lt;/p&gt;
&lt;p&gt;So when someone says &amp;ldquo;let&amp;rsquo;s use QUIC instead of TCP,&amp;rdquo; what they are actually proposing is: let&amp;rsquo;s use UDP as a dumb packet pipe, and rebuild all of TCP&amp;rsquo;s guarantees (reliability, ordering, congestion control, flow control) in our application process. Then add mandatory encryption on top.&lt;/p&gt;
&lt;p&gt;That is not a minor architectural detail. That is the entire discussion.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-environment-matters-more-than-the-protocol"&gt;The environment matters more than the protocol&lt;/h2&gt;
&lt;p&gt;QUIC was born at Google. Not for cluster communication. For the internet. Specifically, for Chrome talking to Google&amp;rsquo;s edge servers across unpredictable network paths, through NATs, over connections that break when your phone switches from WiFi to cellular.&lt;/p&gt;
&lt;p&gt;Every design decision in QUIC traces back to internet-scale problems:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/03/image-18.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Now look at a private network. None of these problems exist:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Property in a private LAN Reality
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ────────────────────────────── ──────────────────────────────
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Packet loss &amp;lt; 0.001% (basically zero)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Latency &amp;lt; 0.1ms (sub-microsecond with RDMA)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; IP changes mid-connection Never happens
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Middleboxes None. You own the network.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Trust model Trusted, or mTLS if needed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Connection count Tens. Maybe low hundreds.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Connection lifetime Hours, days, weeks
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Every problem QUIC was designed to solve does not exist inside a private LAN network. You are paying for solutions to problems you do not have.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="where-the-work-actually-happens"&gt;Where the work actually happens&lt;/h2&gt;
&lt;p&gt;The common rebuttal &amp;ldquo;gRPC is in userspace too, so QUIC being userspace doesn&amp;rsquo;t matter&amp;rdquo; falls apart once you trace what actually happens when data moves from your application to the wire. Not the conceptual model. The actual execution path.&lt;/p&gt;
&lt;p&gt;Here is the fundamental difference:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/03/image-17.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;With TCP, the application does almost nothing. The kernel and NIC hardware handle the heavy lifting. With QUIC, the application process does all the transport work itself.&lt;/p&gt;
&lt;h3 id="path-1-grpc-over-tcp"&gt;Path 1: gRPC over TCP&lt;/h3&gt;
&lt;p&gt;Your application serializes a protobuf message. Let&amp;rsquo;s say it&amp;rsquo;s 64KB. A chunk of data destined for another node.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/03/image-20.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Count the syscalls your application made: &lt;strong&gt;one&lt;/strong&gt;. A single &lt;code&gt;write()&lt;/code&gt;. Everything else happened in the kernel and NIC hardware. Your process didn&amp;rsquo;t wake up again until it had more data to send.&lt;/p&gt;
&lt;h3 id="path-2-application-protocol-over-quic-over-udp"&gt;Path 2: Application protocol over QUIC over UDP&lt;/h3&gt;
&lt;p&gt;Same scenario. 64KB of data. But now over QUIC.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/03/image-21.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Count what happened in your application process: segmentation, packet numbering, encryption (per packet), congestion control, flow control, loss detection, retransmission. All of it. Plus roughly 45 syscalls instead of 1 (or ~3-4 with aggressive GSO batching, but still more).&lt;/p&gt;
&lt;p&gt;Now look at both paths side by side and ask: where is &amp;ldquo;the work?&amp;rdquo;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;**With TCP, 90% of the transport work happens in the kernel and NIC hardware. With QUIC, 90% of the transport work happens in your application process. **&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;gRPC and HTTP being in userspace is the small box at the top: serialization and framing. QUIC being in userspace is the entire middle section: the actual transport layer. The people saying &amp;ldquo;gRPC/HTTP/WS is userspace too&amp;rdquo; are pointing at the small box and saying &amp;ldquo;see, same thing.&amp;rdquo; It is not the same thing.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-kernel-optimizations-that-quic-structurally-cannot-use"&gt;The kernel optimizations that QUIC structurally cannot use&lt;/h2&gt;
&lt;p&gt;This is not about TCP being &amp;ldquo;more mature.&amp;rdquo; These are architectural advantages that come from the transport layer living in kernel space with direct access to hardware.&lt;/p&gt;
&lt;h3 id="tcp-segmentation-offload-tso"&gt;TCP Segmentation Offload (TSO)&lt;/h3&gt;
&lt;p&gt;When your application writes 64KB to a TCP socket, the kernel does not split it into 45 packets using CPU time. It constructs a large segment descriptor and hands it to the NIC. The NIC hardware splits it into MTU-sized packets right before putting them on the wire.&lt;/p&gt;
&lt;p&gt;Your CPU does almost nothing for this. The NIC is doing the segmentation.&lt;/p&gt;
&lt;p&gt;QUIC cannot use TSO. Each QUIC packet must be individually encrypted in userspace before it crosses the syscall boundary. You cannot hand the NIC a 64KB encrypted blob and say &amp;ldquo;split this into packets.&amp;rdquo; The encryption is per-packet, so the splitting must happen before encryption, which must happen in userspace.&lt;/p&gt;
&lt;h3 id="generic-receive-offload-gro"&gt;Generic Receive Offload (GRO)&lt;/h3&gt;
&lt;p&gt;On the receive side, the NIC and kernel coalesce multiple incoming TCP segments into large buffers. Your application calls &lt;code&gt;recv()&lt;/code&gt; once and gets 64KB+ of data that physically arrived as dozens of packets.&lt;/p&gt;
&lt;p&gt;With QUIC, the kernel cannot coalesce incoming UDP datagrams because it cannot see inside the encrypted QUIC packets. Each one must be individually delivered to userspace, individually decrypted, and individually reassembled by the QUIC library.&lt;/p&gt;
&lt;h3 id="zero-copy-io-with-sendfile"&gt;Zero-copy I/O with sendfile()&lt;/h3&gt;
&lt;p&gt;This is the critical one for any data-intensive system. TCP supports &lt;code&gt;sendfile()&lt;/code&gt; and &lt;code&gt;splice()&lt;/code&gt;, which move data directly from the filesystem page cache to the NIC without ever copying it into userspace memory.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/03/image-16.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Data never enters userspace. Zero copies, zero context switches for the data path.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/03/image-15.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Two extra copies, two extra context switches. For any distributed system moving large volumes of data between nodes, this is not a small difference. It is the difference between the data touching userspace memory zero times versus two or more times per operation. Each copy burns memory bandwidth. Each context switch burns CPU cycles.&lt;/p&gt;
&lt;p&gt;Apache Kafka famously depends on &lt;code&gt;sendfile()&lt;/code&gt; for its performance, transferring log segments directly from disk to network without ever reading them into the application process. This optimization is structurally impossible with QUIC.&lt;/p&gt;
&lt;h3 id="kernel-tls-ktls"&gt;Kernel TLS (kTLS)&lt;/h3&gt;
&lt;p&gt;If you need encryption between cluster nodes for compliance or zero-trust requirements, Linux supports kernel TLS. The TLS record layer executes in kernel space, preserving the zero-copy path:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/03/image-14.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;You get encryption without giving up any of TCP&amp;rsquo;s performance advantages. QUIC&amp;rsquo;s mandatory per-packet encryption in userspace cannot match this.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="packet-level-breakdown"&gt;Packet-level breakdown&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s look at exactly what goes on the wire.&lt;/p&gt;
&lt;h3 id="tcp-packet-no-encryption"&gt;TCP packet (no encryption)&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/03/image-22.png" alt=""&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;┌─────────────────────────────────────────────────┐&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="n"&gt;IPv4&lt;/span&gt; &lt;span class="n"&gt;Header&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;├─────────────────────────────────┼───────────────┤&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="n"&gt;TCP&lt;/span&gt; &lt;span class="n"&gt;Header&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;├─────────────────────────────────┼───────────────┤&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="n"&gt;Payload&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="mi"&gt;1460&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;└─────────────────────────────────┴───────────────┘&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Total&lt;/span&gt; &lt;span class="n"&gt;overhead&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="n"&gt;per&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Payload&lt;/span&gt; &lt;span class="n"&gt;efficiency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1460&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;97.3&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;CPU&lt;/span&gt; &lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="n"&gt;per&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;near&lt;/span&gt; &lt;span class="n"&gt;zero&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checksums&lt;/span&gt; &lt;span class="n"&gt;offloaded&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;NIC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="quic-packet-short-header-post-handshake"&gt;QUIC packet (short header, post-handshake)&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/03/image-23.png" alt=""&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;┌─────────────────────────────────────────────────┐&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="n"&gt;IPv4&lt;/span&gt; &lt;span class="n"&gt;Header&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;├─────────────────────────────────┼───────────────┤&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="n"&gt;UDP&lt;/span&gt; &lt;span class="n"&gt;Header&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;├─────────────────────────────────┼───────────────┤&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="n"&gt;QUIC&lt;/span&gt; &lt;span class="n"&gt;Short&lt;/span&gt; &lt;span class="n"&gt;Header&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;├─────────────────────────────────┼───────────────┤&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="n"&gt;Encrypted&lt;/span&gt; &lt;span class="n"&gt;Payload&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="mi"&gt;1407&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;├─────────────────────────────────┼───────────────┤&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="n"&gt;AEAD&lt;/span&gt; &lt;span class="n"&gt;Authentication&lt;/span&gt; &lt;span class="n"&gt;Tag&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;└─────────────────────────────────┴───────────────┘&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Total&lt;/span&gt; &lt;span class="n"&gt;overhead&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="n"&gt;per&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Payload&lt;/span&gt; &lt;span class="n"&gt;efficiency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1407&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;93.8&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;CPU&lt;/span&gt; &lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="n"&gt;per&lt;/span&gt; &lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;AES&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;GCM&lt;/span&gt; &lt;span class="n"&gt;encrypt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;decrypt&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userspace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;24 extra bytes of overhead per packet, plus a cryptographic operation for every single packet. Let&amp;rsquo;s see what that means at scale.&lt;/p&gt;
&lt;h3 id="cost-at-scale"&gt;Cost at scale&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/03/image-24.png" alt=""&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; At 10 Gbps inter-node throughput, 1500-byte MTU:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; TCP QUIC
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ──────────────────────────────────────────────────────────
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Packets per second ~833,000 ~833,000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Header overhead/sec 33.3 MB/s 53.3 MB/s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Wasted bandwidth ── ~20 MB/s extra
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Syscalls/sec ~1 per write() ~55,000 (with GSO)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; (kernel batches) up to 833,000 (without)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Crypto operations/sec 0 ~833,000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Context switches/sec minimal ~55,000+
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At 10 Gbps, QUIC adds ~55,000 context switches per second and 833,000 cryptographic operations that TCP avoids entirely.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; With jumbo frames (9000-byte MTU, standard in clusters):
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; TCP QUIC
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ──────────────────────────────────────────────────────────
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Packets per second ~139,000 ~139,000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Crypto operations/sec 0 ~139,000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Syscalls/sec ~1 per write() ~10,000 (with GSO)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Jumbo frames reduce the packet rate for both, but QUIC still pays per-packet encryption cost. TCP&amp;rsquo;s cost is essentially constant because the NIC handles segmentation regardless of MTU.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="what-production-systems-actually-chose"&gt;What production systems actually chose&lt;/h2&gt;
&lt;p&gt;This is not a theoretical argument. Every major distributed system in production uses TCP for internal node-to-node communication. Not one uses QUIC.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/03/image-13.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;etcd&lt;/strong&gt; uses gRPC over TCP for Raft consensus and peer communication. The entire consistency model of Kubernetes depends on etcd&amp;rsquo;s Raft log replication, which relies on TCP&amp;rsquo;s reliable ordered delivery at the kernel level.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CockroachDB&lt;/strong&gt; uses gRPC over TCP for all inter-node RPC. Distributed SQL execution, Raft replication, leaseholder coordination. Heavy cross-node traffic, all on TCP.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ScyllaDB&lt;/strong&gt; uses a custom RPC protocol over raw TCP sockets through the Seastar framework. Each CPU core gets its own TCP connections in a shared-nothing architecture. When they needed to go faster than kernel TCP, they went toward DPDK (kernel bypass with a custom userspace TCP stack), not toward QUIC. They kept TCP semantics and eliminated the kernel. QUIC goes the other direction: keeps the kernel in the path via UDP while moving the expensive transport work to userspace.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Apache Kafka&lt;/strong&gt; uses a custom binary protocol over TCP. Its throughput depends on the zero-copy &lt;code&gt;sendfile()&lt;/code&gt; path described earlier is structurally impossible with QUIC.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Redis Cluster&lt;/strong&gt; uses TCP for both the data port and the cluster bus (a gossip protocol on port+10000 for failure detection and configuration).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ceph&lt;/strong&gt; supports two messenger implementations, both TCP-based: the simple messenger and the async (epoll-based) messenger. RADOS replication and recovery, which involves massive data movement during rebalancing, runs entirely over TCP.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TiKV&lt;/strong&gt; (the storage engine behind TiDB) uses gRPC over TCP for Raft communication and data transfer between nodes.&lt;/p&gt;
&lt;p&gt;The pattern is not a coincidence. These systems were built by teams who deeply understand transport layer performance. They all arrived at the same answer.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="when-quic-genuinely-makes-sense"&gt;When QUIC genuinely makes sense&lt;/h2&gt;
&lt;p&gt;QUIC is a well-engineered protocol. The goal of this article is not to dismiss it, it is to be precise about where it belongs.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/03/image-12.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Browser-to-CDN, mobile clients, multiplexed streams over lossy links, and cross-region traffic over public internet these are the environments QUIC was built for. Inside a cluster LAN with sub-millisecond latency and near-zero packet loss, none of these conditions exist.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-right-architecture-for-cluster-internals"&gt;The right architecture for cluster internals&lt;/h2&gt;
&lt;p&gt;For a multi-node cluster, the transport choice is straightforward:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/03/image-10.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;And if you ever need to go faster than kernel TCP, the direction is not QUIC. The direction is:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/03/image-11.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;All three of these either keep TCP or go below it. None of them add a layer on top of UDP and call it progress.&lt;/p&gt;
&lt;p&gt;TCP, inside a cluster, is not just the better option. It is the only option that makes engineering sense. The kernel handles your transport. The NIC accelerates it in hardware. Your application process stays free to do application work. Thirty years of optimization, hardware offload, and zero-copy I/O support this path. Inside a cluster network where you control every switch, every cable, every MTU setting, QUIC&amp;rsquo;s trade-offs buy you nothing and cost you everything.&lt;/p&gt;</content></entry><entry><title>How Does Your Database Store Millions of Records?</title><link href="https://firstfinger.io/how-does-database-store-millions-of-records/"/><id>https://firstfinger.io/how-does-database-store-millions-of-records/</id><updated>2026-01-02T05:38:36Z</updated><published>2026-01-01T17:54:09Z</published><author><name>Anurag Vishwakarma</name></author><category term="Database"/><summary>Every database write faces the same challenge: disks are 1,000x slower than memory. Your choice between B-Trees and LSM Trees can make your database 10x faster or 10x slower. Here's how they actually work and when to use each.</summary><content type="html">&lt;p&gt;Every time you save a photo, complete a purchase, or send a message, your data travels from application code to permanent storage. But how does this actually work at the physical level?&lt;/p&gt;
&lt;p&gt;During my years working with production systems, I&amp;rsquo;ve seen teams choose the wrong storage engine and suffer 10x performance penalties. The difference between B-Trees and LSM Trees isn&amp;rsquo;t academic, it&amp;rsquo;s the reason Discord&amp;rsquo;s migration to Cassandra made their writes 10x faster, and why Netflix uses different approaches for viewing history versus recommendations.&lt;/p&gt;
&lt;h2 id="the-fundamental-problem-disk-is-slow"&gt;The Fundamental Problem: Disk is Slow&lt;/h2&gt;
&lt;p&gt;Before getting into data structures, understand the constraint we&amp;rsquo;re solving for.&lt;/p&gt;
&lt;p&gt;In-memory storage is fast but expensive and volatile &amp;amp; power off, data gone. Disk storage (SSDs or HDDs) is cheap and persistent, but dramatically slower:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RAM&lt;/strong&gt;: ~100 nanoseconds&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSD&lt;/strong&gt;: ~100 microseconds (1,000x slower)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HDD&lt;/strong&gt;: ~10 milliseconds (100,000x slower)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This performance gap shapes everything. You can&amp;rsquo;t just dump a hash table to disk and expect decent performance.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Here&amp;rsquo;s the insight:&lt;/strong&gt;&lt;/em&gt;* disks hate random access but excel at sequential access. Reading 1 byte at a random location is slow. Reading 1MB of consecutive bytes is much faster per byte.*&lt;/p&gt;
&lt;p&gt;Database storage engines exist to minimize random disk access. This leads us to two fundamentally different approaches.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/01/image.png" alt=""&gt;&lt;/p&gt;
&lt;h2 id="b-trees-the-read-optimized-classic"&gt;B-Trees: The Read-Optimized Classic&lt;/h2&gt;
&lt;p&gt;PostgreSQL, MySQL, and SQLite all use B-Trees by default. They&amp;rsquo;ve been around since the 1970s for good reason.&lt;/p&gt;
&lt;h3 id="how-b-trees-work"&gt;How B-Trees Work?&lt;/h3&gt;
&lt;p&gt;Think of a B-Tree as a sorted, balanced tree structure. The root node acts as an index, directing you left or right. Each level narrows your search until you reach a leaf node containing your data.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/01/image-1.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Looking up &lt;code&gt;user_789&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Read root node: &amp;ldquo;keys 501-999 go right&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Read right child: &amp;ldquo;keys 751-999 go right&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Read that node: find &lt;code&gt;user_789&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That&amp;rsquo;s typically 3-4 disk reads for any lookup, guaranteed by the balanced tree structure.&lt;/p&gt;
&lt;h3 id="b-tree-strengths"&gt;B-Tree Strengths&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Point lookups are fast.&lt;/strong&gt; Need a specific user? 3-4 disk reads.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Range queries are efficient.&lt;/strong&gt; &amp;ldquo;Give me users 100-200&amp;rdquo; works well because data is sorted and stored contiguously.&lt;/p&gt;
&lt;p&gt;This makes B-Trees perfect for OLTP (Online Transaction Processing) systems with frequent random reads, think bank accounts, e-commerce orders, user profiles.&lt;/p&gt;
&lt;h3 id="b-tree-weaknesses"&gt;B-Tree Weaknesses&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Writes are expensive.&lt;/strong&gt; To insert data:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Read multiple nodes to find the insertion point&lt;/li&gt;
&lt;li&gt;Split nodes if full&lt;/li&gt;
&lt;li&gt;Update parent pointers&lt;/li&gt;
&lt;li&gt;Potentially rebalance the tree&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;One write can trigger dozens of disk operations. If your disk is nearly full and you&amp;rsquo;re doing random inserts, you&amp;rsquo;re constantly seeking different locations is painful for HDDs, inefficient even for SSDs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;B-Trees optimize for reads at the cost of writes.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="lsm-trees-the-write-optimized-modern-approach"&gt;LSM Trees: The Write-Optimized Modern Approach&lt;/h2&gt;
&lt;p&gt;LSM (Log-Structured Merge) Trees power Cassandra, RocksDB, LevelDB, and most NoSQL databases handling high write volumes.&lt;/p&gt;
&lt;p&gt;The philosophy is radically different: instead of maintaining sorted organization on disk, write things down as they arrive just like a journal.&lt;/p&gt;
&lt;h3 id="how-lsm-trees-work"&gt;How LSM Trees Work?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;When a write arrives:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Write to MemTable&lt;/strong&gt; (in-memory sorted buffer)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When MemTable fills&lt;/strong&gt; (~64MB), flush to disk as an immutable SSTable (Sorted String Table)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write sequentially&lt;/strong&gt; in one operation&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Sequential writes are fast: 100-500 MB/s even on HDDs, compared to 1-2 MB/s for random writes.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/01/image-2.png" alt=""&gt;&lt;/p&gt;
&lt;h3 id="the-read-trade-off"&gt;The Read Trade-off&lt;/h3&gt;
&lt;p&gt;To read &lt;code&gt;user_789&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check current MemTable&lt;/li&gt;
&lt;li&gt;Check most recent SSTable&lt;/li&gt;
&lt;li&gt;Check next SSTable&lt;/li&gt;
&lt;li&gt;Continue until found&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Unlike B-Trees, data isn&amp;rsquo;t in one organized tree, it&amp;rsquo;s across multiple sorted files.&lt;/p&gt;
&lt;h3 id="how-lsm-trees-stay-fast"&gt;How LSM Trees Stay Fast&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Bloom Filters&lt;/strong&gt;: Before checking each SSTable, ask: &amp;ldquo;Does this file contain user_789?&amp;rdquo; If no, skip entirely. This avoids unnecessary disk reads.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compaction&lt;/strong&gt;: Background process merges SSTables, removes deleted data, combines duplicates. Data ages through levels (hence &amp;ldquo;leveled compaction&amp;rdquo;).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2026/01/image-3.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: Writes stay fast (always sequential), reads are slower than B-Trees for point lookups but manageable with Bloom filters and caching.&lt;/p&gt;
&lt;p&gt;LSM Trees handle millions of writes per second because you&amp;rsquo;re appending to memory and occasionally flushing to disk.&lt;/p&gt;
&lt;h2 id="when-to-use-each-approach"&gt;When to Use Each Approach&lt;/h2&gt;
&lt;h3 id="use-b-trees-when-you-have"&gt;Use B-Trees When You Have:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Read-heavy workloads&lt;/strong&gt; (80:20 read-to-write ratio)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Need for fast point lookups&lt;/strong&gt; and range scans&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transactional workloads&lt;/strong&gt; (bank accounts, orders)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data fitting in memory&lt;/strong&gt; or fast SSDs available&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;: PostgreSQL for user accounts, MySQL for product catalogs, SQLite for mobile app databases&lt;/p&gt;
&lt;h3 id="use-lsm-trees-when-you-have"&gt;Use LSM Trees When You Have:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Write-heavy workloads&lt;/strong&gt; (tons of inserts/updates)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptable slightly slower reads&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Time-series data&lt;/strong&gt; (logs, metrics, sensors)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Need to ingest massive data volumes&lt;/strong&gt; quickly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;: Cassandra for Netflix&amp;rsquo;s viewing history (300M writes/day), RocksDB for Facebook messaging, InfluxDB for monitoring metrics&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="example-discords-migration"&gt;Example: Discord&amp;rsquo;s Migration&lt;/h2&gt;
&lt;p&gt;Discord initially used MongoDB (B-Trees) for message storage. Worked fine initially, but at scale with billions of messages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reads were acceptable&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writes became a bottleneck&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Random B-Tree inserts caused disk fragmentation&lt;/li&gt;
&lt;li&gt;Insert performance degraded&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They migrated to Cassandra (LSM Trees):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Writes became 10x faster&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Now handle millions of messages per second&lt;/li&gt;
&lt;li&gt;Sequential write pattern eliminated fragmentation&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-actual-reality"&gt;The Actual Reality&lt;/h2&gt;
&lt;p&gt;Modern databases often blend approaches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RocksDB&lt;/strong&gt;: LSM Trees with read optimizations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PostgreSQL&lt;/strong&gt;: B-Trees + WAL (Write-Ahead Log, append-only)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The best choice depends on your access patterns. In my experience running production systems, I&amp;rsquo;ve learned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start with B-Trees (PostgreSQL/MySQL) for general-purpose applications&lt;/li&gt;
&lt;li&gt;Switch to LSM Trees when write volume becomes the bottleneck&lt;/li&gt;
&lt;li&gt;Monitor disk I/O patterns if they&amp;rsquo;ll tell you when you&amp;rsquo;ve chosen wrong&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="quick-takeaways"&gt;Quick Takeaways&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;**Disks are 1,000-100,000x slower than RAM **this constraint shapes everything&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B-Trees optimize for reads&lt;/strong&gt; with logarithmic lookup but expensive writes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LSM Trees optimize for writes&lt;/strong&gt; with sequential I/O but trade-off read performance&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-world systems&lt;/strong&gt; often use hybrid approaches&lt;/li&gt;
&lt;li&gt;**Your access pattern determines the right choice **not theoretical performance&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The storage engine matters more than most developers realize.&lt;/p&gt;</content></entry><entry><title>Why Your App is Still Slow After Optimization?</title><link href="https://firstfinger.io/tcp-congestion-control-bbr-cubic-bgp-performance/"/><id>https://firstfinger.io/tcp-congestion-control-bbr-cubic-bgp-performance/</id><updated>2025-08-30T12:31:22Z</updated><published>2025-08-30T12:31:22Z</published><author><name>Anurag Vishwakarma</name></author><category term="Network"/><category term="APIs"/><category term="Cloud"/><category term="Database"/><category term="Linux"/><category term="Programming"/><summary>Even with optimized queries, fast APIs, and a CDN, your app may still be slow. Network protocols like TCP congestion control and BGP routing introduce latency beyond your code.</summary><content type="html">&lt;p&gt;You have optimized your database queries, your API responds in under 100ms, and your CDN is correctly configured. Yet users still report slow load times, and performance monitoring shows latency spikes that appear without explanation.&lt;/p&gt;
&lt;p&gt;The issue often lies outside your application or infrastructure. Two core network protocols can directly impact performance. TCP congestion control may make inefficient decisions about how data flows under varying conditions, and BGP routing can send traffic along longer, suboptimal paths across the internet.&lt;/p&gt;
&lt;p&gt;This is not the result of poor coding or misconfigured servers. It is a reminder that the behavior of foundational internet protocols can override even the best optimizations, and understanding them is critical to reducing unpredictable latency.&lt;/p&gt;
&lt;h2 id="what-is-tcp-congestion"&gt;What is TCP Congestion?&lt;/h2&gt;
&lt;p&gt;Every TCP connection needs to answer a fundamental question: &lt;em&gt;&lt;strong&gt;how fast should data be sent?&lt;/strong&gt;&lt;/em&gt; Send too slowly and you waste available bandwidth. Send too quickly and you&amp;rsquo;ll overwhelm the network, causing packet loss and retransmissions.&lt;/p&gt;
&lt;p&gt;TCP congestion control algorithms handle this decision automatically, but their choices directly impact your application&amp;rsquo;s performance in ways that can override all your code-level optimizations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There are two types of TCP congestion control algorithms, but they approach the problem very differently.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="1-cubic"&gt;1. CUBIC&lt;/h3&gt;
&lt;p&gt;Most internet servers still use CUBIC, a loss-based congestion control algorithm.&lt;/p&gt;
&lt;p&gt;CUBIC&amp;rsquo;s strategy is straightforward: increase the data transmission rate until packet loss occurs, then back off and gradually increase again.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/CUBIC-TCP-Loss-Based-Congestion-Control.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;This approach works well for bulk data transfers, but it creates problems for modern applications. &lt;em&gt;&lt;strong&gt;CUBIC treats packet loss as the primary signal of network congestion, which means it needs to overfill network buffers to detect when to slow down&lt;/strong&gt;&lt;/em&gt;. Those overfilled buffers translate directly into increased latency for your application.&lt;/p&gt;
&lt;p&gt;When a user clicks on a video thumbnail, CUBIC might send the first few data packets quickly, but as it ramps up transmission speed, it begins filling intermediate network buffers. Your video data sits in these buffers, adding 100-200ms of delay before reaching the user&amp;rsquo;s device. From your monitoring perspective, the server responded quickly, but the user experiences the additional buffer delay.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;CUBIC is probably the best, most robust congestion control algorithm available. But, as internet bandwidths grow and wireless represents a larger share of network links, TCP doesn&amp;rsquo;t perform as desired.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="2-bbr-bottleneck-bandwidth-and-rtt"&gt;2. BBR (Bottleneck Bandwidth and RTT)&lt;/h3&gt;
&lt;p&gt;Google&amp;rsquo;s BBR takes a different approach. Instead of waiting for packet loss to detect congestion, BBR actively measures available bandwidth and round-trip time to calculate the optimal sending rate.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/BBR-TCP-Model-Based-Congestion-Control.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;***BBR continuously estimates two key metrics: the maximum bandwidth available on the path to the destination, and the minimum round-trip time. ***Using these measurements, it calculates the ideal transmission rate without needing to fill network buffers.&lt;/p&gt;
&lt;p&gt;Real-world use-cases show significant improvements. Companies handling large-scale video delivery report 21% performance improvements when switching from CUBIC to BBR. More importantly for interactive applications, BBR maintains much lower latency because it doesn&amp;rsquo;t rely on buffer overflow to detect congestion.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The difference becomes particularly noticeable for mobile users, where network conditions change frequently and CUBIC&amp;rsquo;s loss-based approach struggles to adapt quickly to varying bandwidth and latency conditions.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="bgp-border-gateway-protocol-routing"&gt;BGP (Border Gateway Protocol) Routing&lt;/h2&gt;
&lt;p&gt;While TCP congestion control controls how fast data moves, BGP decides the path that data takes across the internet. BGP is the backbone of the internet because it allows one network to talk to another. It is the protocol that connects thousands of independent networks such as ISPs, cloud providers, and data centers, making the internet work as a whole.&lt;/p&gt;
&lt;p&gt;BGP works at the application layer of the OSI model but runs on top of TCP using port 179. Its main job is to let networks advertise which IP prefixes they can reach and to choose a path for traffic between them.&lt;/p&gt;
&lt;p&gt;The problem is that BGP focuses on reachability, not performance. As long as the data can reach its destination, BGP considers the task complete even if the chosen route is longer or slower than required.&lt;/p&gt;
&lt;h3 id="what-is-bgp-hijacking-"&gt;What is BGP Hijacking ?&lt;/h3&gt;
&lt;p&gt;Your application might send data to a user in London, and you&amp;rsquo;d naturally expect that data to take a direct path through European internet infrastructure. But BGP routing decisions made by various network operators along the way might send that traffic through entirely different paths.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/BGP-Hijacking-Scenario.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Data could travel from your London server to a user in London by way of internet exchanges in Frankfurt, Amsterdam, and back to London. Each additional hop adds latency, and each network transition introduces potential performance variations that your application has no control over.&lt;/p&gt;
&lt;p&gt;More concerning are &lt;a href="https://www.cloudflare.com/learning/security/glossary/bgp-hijacking/" target="_blank" rel="noopener noreferrer"&gt;BGP hijacking incidents&lt;/a&gt;
, where malicious or misconfigured network operators advertise routes for IP address ranges they don&amp;rsquo;t actually control. When this happens, traffic intended for your servers gets redirected through unintended networks which leads to unexpcted results.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="what-this-means-for-application-performance-"&gt;What This Means for Application Performance ?&lt;/h2&gt;
&lt;p&gt;TCP congestion control and BGP routing can amplify each other’s weaknesses. When BGP shifts traffic to a new path, the latency and bandwidth may differ significantly from what the TCP algorithm has been tuned for.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/Latency-Impact-of-BGP-and-TCP.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;CUBIC, which relies on packet loss and recovery cycles, struggles in this situation. It interprets the sudden change as congestion and cuts transmission speed, even if the new path has sufficient capacity. Performance remains poor until CUBIC slowly recalibrates.&lt;/p&gt;
&lt;p&gt;BBR adapts more effectively. Instead of relying on past behavior, it continuously measures bandwidth and round-trip time. When BGP reroutes traffic, BBR quickly adjusts its sending rate to the new path’s conditions.&lt;/p&gt;
&lt;p&gt;These interactions explain why users may see latency spikes even when your servers and APIs are healthy. Geographic variations often stem from BGP routing choices rather than application issues, and mobile users are especially affected since variable bandwidth and latency expose CUBIC’s limitations. BBR’s active measurement approach tends to handle such conditions more gracefully.&lt;/p&gt;
&lt;h3 id="summary"&gt;Summary&lt;/h3&gt;
&lt;p&gt;You can’t control BGP routing choices, but understanding them helps with architecture and troubleshooting. Enabling BBR at the server level often improves performance, especially for mobile and real-time applications, since it’s built into modern &lt;a href="/kernel-tls-offload-ktls-nic/" target="_blank" rel="noopener"&gt;Linux kernels&lt;/a&gt;
and requires no code changes.&lt;/p&gt;
&lt;p&gt;For routing resilience, diversify across multiple CDNs or cloud regions so that a single BGP issue doesn’t affect all users. Geographic redundancy ensures alternative paths are available when routing problems occur.&lt;/p&gt;
&lt;p&gt;Monitoring should go beyond application response times. Metrics like TCP retransmissions, round-trip latency, and regional performance differences reveal when protocol-level issues are degrading user experience.&lt;/p&gt;
&lt;p&gt;The takeaway is that network protocols can override even the best application optimizations. The internet’s core protocols were never designed for today’s performance demands, yet they still decide how data flows. Recognizing their influence helps you build more resilient systems and debug issues that aren’t in your code.&lt;/p&gt;</content></entry><entry><title>Layer 4 vs Layer 7 Load Balancing Explained</title><link href="https://firstfinger.io/layer-4-vs-layer-7-load-balancing/"/><id>https://firstfinger.io/layer-4-vs-layer-7-load-balancing/</id><updated>2025-08-28T09:37:04Z</updated><published>2025-08-28T09:37:04Z</published><author><name>firstfinger</name></author><category term="Network"/><category term="Cloud"/><category term="APIs"/><summary>Layer 4 uses TCP/IP for simple, fast routing offering speed and efficiency, while Layer 7 enables smart routing with HTTP content inspection, providing intelligent routing and caching capabilities.</summary><content type="html">&lt;p&gt;When you browse Instagram, stream Netflix, or shop on Amazon, robust load balancing technology works silently in the background, handling millions of simultaneous requests across multiple server. This critical infrastructure component prevents system overloads and ensures consistent user experiences even during traffic spikes.&lt;/p&gt;
&lt;h2 id="load-balancing-fundamentals"&gt;Load Balancing Fundamentals&lt;/h2&gt;
&lt;p&gt;Load balancing distributes incoming network traffic across multiple servers to ensure no single server becomes overwhelmed. This improves application responsiveness and availability while preventing server failures. The choice between Layer 4 and Layer 7 load balancing represents a crucial architectural decision with significant implications for performance, security, and functionality.&lt;/p&gt;
&lt;h2 id="the-network-layer-context"&gt;The Network Layer Context&lt;/h2&gt;
&lt;p&gt;To understand these approaches, we need to reference the OSI model that categorizes network functions:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/osi-model.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;The OSI model provides a framework for understanding network communications. For load balancing, we focus primarily on Layer 4 (Transport) and Layer 7 (Application).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="layer-4-load-balancing-transport-layer"&gt;Layer 4 Load Balancing: Transport Layer&lt;/h2&gt;
&lt;p&gt;Layer 4 load balancers operate at the transport protocol level, making routing decisions based solely on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Source and destination IP addresses&lt;/li&gt;
&lt;li&gt;TCP/UDP port information&lt;/li&gt;
&lt;li&gt;Network-level client information&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These load balancers maintain a single TCP connection from client to server, using Network Address Translation (NAT) to route packets without inspecting their contents.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/Layer-4-Load-Balancing.png" alt=""&gt;&lt;/p&gt;
&lt;h3 id="advantages"&gt;Advantages&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Performance Efficiency&lt;/strong&gt;: Minimal packet inspection results in lower processing overhead&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protocol Agnosticism&lt;/strong&gt;: Works with any TCP/UDP traffic, not just HTTP&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security Isolation&lt;/strong&gt;: Cannot decrypt encrypted traffic, maintaining end-to-end encryption&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connection Efficiency&lt;/strong&gt;: Maintains a single TCP connection throughout the request lifecycle&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lower Latency&lt;/strong&gt;: Fewer processing steps means faster packet forwarding&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="limitations"&gt;Limitations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Content Blindness&lt;/strong&gt;: Cannot make decisions based on request content or headers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limited Routing Logic&lt;/strong&gt;: Unable to route based on URLs, cookies, or application-specific data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No Content Manipulation&lt;/strong&gt;: Cannot modify headers or rewrite request content&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Microservice Limitations&lt;/strong&gt;: Difficult to implement path-based routing needed for microservices&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No Application-Level Features&lt;/strong&gt;: Cannot implement caching or application-aware health checks&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="nginx-layer-4-load-balancing-example"&gt;NGINX Layer 4 Load Balancing Example&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-nginx" data-lang="nginx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Layer 4 TCP load balancing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;stream&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Web server group
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;upstream&lt;/span&gt; &lt;span class="s"&gt;web_servers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="n"&gt;backend1.example.com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="n"&gt;backend2.example.com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Database server group
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;upstream&lt;/span&gt; &lt;span class="s"&gt;db_servers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="n"&gt;db1.example.com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5432&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="n"&gt;db2.example.com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5432&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# HTTP traffic forwarding
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;web_servers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# PostgreSQL traffic forwarding
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;db_servers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;**This above configuration shows: **&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Creates two upstream server groups: web servers and database servers&lt;/li&gt;
&lt;li&gt;Listens on port 80 and forwards web traffic to the web servers&lt;/li&gt;
&lt;li&gt;Listens on port 5432 and forwards database traffic to the database servers&lt;/li&gt;
&lt;li&gt;Makes decisions based solely on IP addresses and ports&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="layer-7-load-balancing-application-layer"&gt;Layer 7 Load Balancing: Application Layer&lt;/h2&gt;
&lt;h3 id="technical-operation"&gt;Technical Operation&lt;/h3&gt;
&lt;p&gt;Layer 7 load balancers operate at the application layer, which means they:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Terminate client connections at the load balancer&lt;/li&gt;
&lt;li&gt;Inspect and potentially modify request content&lt;/li&gt;
&lt;li&gt;Establish new connections to appropriate backend servers&lt;/li&gt;
&lt;li&gt;Create two distinct TCP connections (client-to-LB and LB-to-server)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/Layer-7-Load-Balancing.png" alt=""&gt;&lt;/p&gt;
&lt;h3 id="advantages-1"&gt;Advantages&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Content-Based Routing&lt;/strong&gt;: Can route based on URL paths, headers, cookies, or message content&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Microservice Architecture Support&lt;/strong&gt;: Enables routing different API endpoints to specialized services&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advanced Health Checking&lt;/strong&gt;: Can verify application functionality, not just server availability&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content Manipulation&lt;/strong&gt;: Ability to add/modify headers or transform request/response content&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Caching Implementation&lt;/strong&gt;: Can cache responses for improved performance&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TLS Termination&lt;/strong&gt;: Can offload SSL/TLS processing from backend servers&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="limitations-1"&gt;Limitations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Computational Overhead&lt;/strong&gt;: Content inspection requires more processing power&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TLS Processing&lt;/strong&gt;: Must decrypt and re-encrypt secure traffic&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Increased Latency&lt;/strong&gt;: Additional processing steps add some latency&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security Considerations&lt;/strong&gt;: Decrypted traffic visibility at the load balancer level&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Certificate Management&lt;/strong&gt;: Requires TLS certificates to be installed on the load balancer&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="nginx-layer-7-load-balancing-example"&gt;NGINX Layer 7 Load Balancing Example&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-nginx" data-lang="nginx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Layer 7 HTTP load balancing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# API server group
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;upstream&lt;/span&gt; &lt;span class="s"&gt;api_servers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="n"&gt;api1.example.com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="n"&gt;api2.example.com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Media server group
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;upstream&lt;/span&gt; &lt;span class="s"&gt;media_servers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="n"&gt;media1.example.com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="n"&gt;media2.example.com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Auth server group
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;upstream&lt;/span&gt; &lt;span class="s"&gt;auth_servers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="n"&gt;auth1.example.com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8081&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="n"&gt;auth2.example.com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8081&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Main server configuration
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;example.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Route API requests
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="s"&gt;/api/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://api_servers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Route media requests
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="s"&gt;/media/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://media_servers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Route authentication requests
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="s"&gt;/auth/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://auth_servers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This above configuration shows Layer 7&amp;rsquo;s capabilities:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Creates three upstream server groups for different services&lt;/li&gt;
&lt;li&gt;Routes requests based on URL paths (/api/, /media/, /auth/)&lt;/li&gt;
&lt;li&gt;Forwards requests to the appropriate backend servers&lt;/li&gt;
&lt;li&gt;Adds headers to provide original client information to backend servers&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="hybrid-implementation-with-nginx"&gt;Hybrid Implementation with NGINX&lt;/h2&gt;
&lt;p&gt;For environments that need both Layer 4 and Layer 7 capabilities, NGINX supports a hybrid approach:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-nginx" data-lang="nginx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Combined Layer 4 and Layer 7 load balancing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Layer 4 for database traffic
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;stream&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;upstream&lt;/span&gt; &lt;span class="s"&gt;database&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="n"&gt;db1.example.com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5432&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="n"&gt;db2.example.com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5432&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;5432&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;database&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Layer 7 for HTTP traffic
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;upstream&lt;/span&gt; &lt;span class="s"&gt;web_servers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="n"&gt;web1.example.com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="n"&gt;web2.example.com&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;example.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://web_servers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This simple hybrid configuration:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Uses Layer 4 load balancing for database connections&lt;/li&gt;
&lt;li&gt;Uses Layer 7 load balancing for web traffic&lt;/li&gt;
&lt;li&gt;Leverages the strengths of both approaches in a single NGINX instance&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="making-the-right-choice"&gt;Making the Right Choice&lt;/h2&gt;
&lt;p&gt;When deciding which approach to go with, consider these factors:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Performance Requirements&lt;/strong&gt;: Layer 4 offers lower overhead for high-throughput scenarios&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protocol Diversity&lt;/strong&gt;: Layer 4 handles any TCP/UDP protocol; Layer 7 is typically HTTP-focused&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Routing Complexity&lt;/strong&gt;: Layer 7 enables path/content-based routing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security Model&lt;/strong&gt;: Layer 4 maintains end-to-end encryption; Layer 7 requires TLS termination&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Architecture&lt;/strong&gt;: Microservices typically require Layer 7&amp;rsquo;s path-based routing capabilities&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;For most modern web applications, a hybrid approach often provides the best balance, using Layer 4 for raw performance where needed and Layer 7 for intelligent content routing. This combination delivers both the efficiency and the flexibility required by complex distributed systems.&lt;/p&gt;</content></entry><entry><title>What is Kernel TLS (kTLS) and Why Offload TLS to the Kernel or NIC?</title><link href="https://firstfinger.io/kernel-tls-offload-ktls-nic/"/><id>https://firstfinger.io/kernel-tls-offload-ktls-nic/</id><updated>2025-08-27T18:55:56Z</updated><published>2025-08-27T18:34:19Z</published><author><name>Anurag Vishwakarma</name></author><category term="Linux"/><category term="Network"/><summary>Kernel TLS (KTLS) moves TLS encryption from user space into the Linux kernel or even the NIC. Offloading reduces CPU overhead, enables zero-copy I/O, and boosts performance for high-throughput applications.</summary><content type="html">&lt;p&gt;Most applications today handle TLS encryption in userspace, which creates performance bottlenecks that many developers don&amp;rsquo;t realize exist. When your web server processes HTTPS requests or your API handles secure connections, every byte of encrypted data requires CPU-intensive cryptographic operations performed by your application process.&lt;/p&gt;
&lt;p&gt;This approach works, but it leaves performance on the table. Linux Kernel TLS (kTLS) offers a better way by moving TLS operations closer to the hardware, potentially freeing up significant CPU resources for your actual application logic.&lt;/p&gt;
&lt;h2 id="whats-the-difference-between-kernel-space-and-user-space-in-linux"&gt;What’s the Difference Between Kernel Space and User Space in Linux?&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/image-3.png"
alt="Linux User Space vs Kernel Space"&gt;&lt;figcaption&gt;
&lt;p&gt;Image Source : Redhat&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In Linux, the &lt;strong&gt;kernel&lt;/strong&gt; is the core of the operating system. It manages hardware like the CPU, memory, and network devices, and provides the low-level services everything else relies on. &lt;strong&gt;User space&lt;/strong&gt; is where normal applications run something like web servers, browsers, databases but they can’t touch hardware directly. Instead, they must go through the kernel using system calls.&lt;/p&gt;
&lt;a class="bookmark" href="https://www.redhat.com/en/blog/architecting-containers-part-1-why-understanding-user-space-vs-kernel-space-matters"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/thumbnail/red-hat-social-share.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Architecting Containers Part 1: Why Understanding User Space vs. Kernel Space Matters&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Before diving head-first into a discussion about the architecture and deployment of containers in a production environment, there are some important things that developers, architects, and systems administrators, need to know. While containers are sometimes treated like virtual machines, it is important to note, unlike virtual machines, the kernel is the only layer of abstraction between programs and the resources they need access to. Let’s see why.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;Red Hat · Scott McCarty (fatherlinux)&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="how-tls-currently-works-in-most-applications-"&gt;How TLS Currently Works in Most Applications ?&lt;/h2&gt;
&lt;p&gt;Before we start with understanding kernel TLS, let&amp;rsquo;s understand the traditional TLS handshake flow. When your application handles a secure connection:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;TCP connection establishes normally&lt;/li&gt;
&lt;li&gt;Your application performs the TLS handshake using libraries like OpenSSL&lt;/li&gt;
&lt;li&gt;For every request/response, your application encrypts outgoing data and decrypts incoming data&lt;/li&gt;
&lt;li&gt;Data gets copied between kernel space and userspace multiple times&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/TLS-Packet-Data-Flow.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This creates two main performance issues:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CPU overhead&lt;/strong&gt;: Your application spends cycles on cryptography instead of business logic&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory copies&lt;/strong&gt;: Data moves between &lt;strong&gt;kernel&lt;/strong&gt; and &lt;strong&gt;user space&lt;/strong&gt; multiple times&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="understanding-kernel-tls-options"&gt;Understanding Kernel TLS Options&lt;/h2&gt;
&lt;p&gt;Linux Kernel TLS provides three different approaches to handle TLS operations more efficiently. Each mode addresses different performance requirements and hardware capabilities.&lt;/p&gt;
&lt;h3 id="1-software-crypto-mode-tls_sw"&gt;1. Software Crypto Mode (TLS_SW)&lt;/h3&gt;
&lt;p&gt;In software mode, the kernel takes over TLS encryption and decryption instead of your application doing it, but still uses the host CPU for cryptographic operations.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/KTLS-SW.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your application performs the TLS handshake (for certificate validation and key exchange)&lt;/li&gt;
&lt;li&gt;Once established, you provide the encryption keys to the kernel&lt;/li&gt;
&lt;li&gt;The kernel handles all subsequent encryption/decryption automatically&lt;/li&gt;
&lt;li&gt;All crypto operations happen in kernel space using the host CPU&lt;/li&gt;
&lt;/ul&gt;
&lt;details class="toggle-block"&gt;
&lt;summary&gt;What changes for your application ?&lt;/summary&gt;
&lt;ul&gt;&lt;li value="1"&gt;&lt;code&gt;&lt;span&gt;write()&lt;/span&gt;&lt;/code&gt;&amp;nbsp;calls: You write plain text, kernel encrypts it&lt;/li&gt;&lt;li value="2"&gt;&lt;code&gt;&lt;span&gt;read()&lt;/span&gt;&lt;/code&gt;&amp;nbsp;calls: Kernel decrypts data before giving it to you&lt;/li&gt;&lt;li value="3"&gt;&lt;b&gt;&lt;strong&gt;Performance impact:&lt;/strong&gt;&lt;/b&gt;&amp;nbsp;You still use CPU for crypto, but kernel-level operations are more efficient than userspace libraries&lt;/li&gt;&lt;/ul&gt;
&lt;/details&gt;
&lt;h3 id="2-packet-based-nic-offload-mode-tls_hw"&gt;2. Packet-based NIC Offload Mode (TLS_HW)&lt;/h3&gt;
&lt;p&gt;Hardware mode moves TLS operations to your network interface card (NIC). Modern enterprise NICs include processors specifically designed for cryptographic operations.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/KTLS-HW.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CPU freedom&lt;/strong&gt;: Your main CPU never touches cryptographic operations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Faster reads&lt;/strong&gt;: Data arrives already decrypted&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better scaling&lt;/strong&gt;: Handle more connections with the same CPU resources&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Requirements:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NIC must support TLS offload capabilities&lt;/li&gt;
&lt;li&gt;Hardware checksum offload must be enabled&lt;/li&gt;
&lt;li&gt;Packets must arrive in order for proper crypto state management&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-full-tcp-nic-offload-mode-tls_hw_record"&gt;3. Full TCP NIC Offload Mode (TLS_HW_RECORD)&lt;/h3&gt;
&lt;p&gt;The most aggressive option lets your NIC handle both TCP connection management and TLS operations entirely. The NIC firmware completely replaces the kernel networking stack for offloaded connections.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Benefits:&lt;/strong&gt; Maximum throughput for pure data transfer scenarios&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limitations:&lt;/strong&gt; You lose Linux networking features like iptables, traffic shaping, and packet filtering&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This mode works best for dedicated high-throughput applications where you don&amp;rsquo;t need advanced networking features. It&amp;rsquo;s essentially creating a hardware-accelerated bypass of the entire Linux networking stack.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="zero-copy-operations-a-practical-example"&gt;Zero-Copy Operations: A Practical Example&lt;/h2&gt;
&lt;p&gt;One of the most significant advantages of kernel TLS is enabling zero-copy operations, which can dramatically improve performance for data-intensive applications.&lt;/p&gt;
&lt;p&gt;To understand the impact, let&amp;rsquo;s examine a real-world scenario: a file upload service handling large files.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/TLS-vs.-KTLS.png" alt=""&gt;&lt;/p&gt;
&lt;h3 id="the-problem-with-traditional-tls"&gt;The Problem with Traditional TLS&lt;/h3&gt;
&lt;p&gt;In traditional userspace TLS implementations, every byte of data must pass through multiple layers and memory copies. When a client uploads a 1GB file to your server:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Network Reception&lt;/strong&gt;: Encrypted data arrives at your network interface&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kernel Copy&lt;/strong&gt;: Data gets copied from network buffers to socket buffers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Userspace Copy #1&lt;/strong&gt;: Your application reads the encrypted data (copy from kernel to userspace)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPU Decryption&lt;/strong&gt;: Your application&amp;rsquo;s TLS library decrypts the data using CPU cycles&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Userspace Copy #2&lt;/strong&gt;: Your application writes the decrypted data back to kernel for file operations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File Write&lt;/strong&gt;: Kernel writes the data to disk&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;This process results in:&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;2+ memory copies&lt;/strong&gt; between kernel and userspace&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High CPU utilization&lt;/strong&gt; for cryptographic operations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory bandwidth waste&lt;/strong&gt; (processing ~2GB of data to store 1GB)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context switching overhead&lt;/strong&gt; between kernel and userspace&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="the-ktls-zero-copy-advantage"&gt;The kTLS Zero-Copy Advantage&lt;/h3&gt;
&lt;p&gt;With kernel TLS hardware offload, the entire data flow changes fundamentally:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Hardware Decryption&lt;/strong&gt;: Your NIC&amp;rsquo;s crypto processor decrypts data as it arrives&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Direct DMA&lt;/strong&gt;: Decrypted data goes directly to kernel memory via DMA&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero-Copy Transfer&lt;/strong&gt;: Application uses &lt;code&gt;sendfile()&lt;/code&gt; or &lt;code&gt;splice()&lt;/code&gt; system calls&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Direct File Write&lt;/strong&gt;: Kernel writes directly from socket buffer to disk&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;The result:&lt;/strong&gt; Your application never touches the actual file data, and your CPU never performs cryptographic operations.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="some-real-world-performance-impact"&gt;Some Real-World Performance Impact&lt;/h2&gt;
&lt;h3 id="1-web-servers"&gt;1. Web Servers&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Before kTLS:&lt;/strong&gt; Each HTTPS connection consumes CPU cycles for every encrypted byte processed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;With kTLS:&lt;/strong&gt; CPU focuses entirely on application logic, handling more concurrent connections&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-file-transfer-services"&gt;2. File Transfer Services&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Before kTLS:&lt;/strong&gt; Large file uploads bottlenecked by encryption overhead and memory copies&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;With kTLS:&lt;/strong&gt; Near-native file transfer speeds with full encryption&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-api-gateways"&gt;3. API Gateways&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Before kTLS:&lt;/strong&gt; TLS termination creates CPU hotspots under heavy load&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;With kTLS:&lt;/strong&gt; Linear scaling with hardware-accelerated crypto operations&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="checking-if-hardwarenic-support-ktls"&gt;Checking if Hardware/NIC Support kTLS&lt;/h2&gt;
&lt;p&gt;You need to verify that your network interface card (NIC) has the necessary hardware capabilities for TLS offload. Not all network cards support hardware TLS acceleration, and the level of support varies significantly between vendors and models.&lt;/p&gt;
&lt;h3 id="nic-tls-offload-capabilities"&gt;NIC TLS Offload Capabilities&lt;/h3&gt;
&lt;p&gt;Modern enterprise network cards include dedicated processors and crypto engines that can handle TLS operations independently of your host CPU. However, support varies across three levels:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No TLS Support&lt;/strong&gt;: Basic NICs without any TLS acceleration&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partial TLS Support&lt;/strong&gt;: NICs that support some TLS operations (TX only, or specific cipher suites)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Full TLS Support&lt;/strong&gt;: Enterprise NICs with complete hardware TLS offload capabilities&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="step-1-identify-your-network-hardware"&gt;Step 1: Identify Your Network Hardware&lt;/h2&gt;
&lt;p&gt;Start by identifying your network interface hardware and current capabilities:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# List all network interfaces&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ip link show
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Get detailed information about your ethernet controller&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lspci &lt;span class="p"&gt;|&lt;/span&gt; grep -i ethernet
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Example output: 02:00.0 Ethernet controller: Intel Corporation X710 for 10GbE SFP+ (rev 02)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Get comprehensive PCI device information&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lspci -vv &lt;span class="p"&gt;|&lt;/span&gt; grep -A &lt;span class="m"&gt;25&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Ethernet controller&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check current driver information&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ethtool -i eth0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Look for driver name, version, and firmware version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-2-check-current-tls-offload-status"&gt;Step 2: Check Current TLS Offload Status&lt;/h2&gt;
&lt;p&gt;Verify what TLS features your NIC currently supports and their status:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check TLS-specific offload features&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ethtool -k eth0 &lt;span class="p"&gt;|&lt;/span&gt; grep tls
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Expected output shows three key features:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# tls-hw-tx-offload: off [fixed] or on/off&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# tls-hw-rx-offload: off [fixed] or on/off &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# tls-hw-record: off [fixed] or on/off&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# View all available offload features&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ethtool --show-offload eth0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check hardware features in detail&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ethtool --show-features eth0 &lt;span class="p"&gt;|&lt;/span&gt; grep -E &lt;span class="s2"&gt;&amp;#34;(tls|csum|gso|gro)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Understanding the output:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;on&lt;/code&gt;&lt;/strong&gt;: Feature is enabled and working&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;off&lt;/code&gt;&lt;/strong&gt;: Feature is disabled but can be enabled&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;[fixed]&lt;/code&gt;&lt;/strong&gt;: Feature cannot be changed (usually means not supported by hardware)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;[requested on]&lt;/code&gt;&lt;/strong&gt;: Feature was requested but couldn&amp;rsquo;t be enabled&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="step-3-hardware-compatibility-database"&gt;Step 3: Hardware Compatibility Database&lt;/h2&gt;
&lt;p&gt;Check if your specific NIC model supports TLS offload:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Get exact NIC model and vendor information&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lspci -nn &lt;span class="p"&gt;|&lt;/span&gt; grep -i ethernet
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Example: 02:00.0 Ethernet controller [0200]: Intel Corporation X710 for 10GbE SFP+ [8086:1572]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check driver module information for TLS support&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;modinfo &lt;span class="k"&gt;$(&lt;/span&gt;ethtool -i eth0 &lt;span class="p"&gt;|&lt;/span&gt; grep driver &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -i tls
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Verify driver version supports TLS features&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ethtool -i eth0 &lt;span class="p"&gt;|&lt;/span&gt; grep -E &lt;span class="s2"&gt;&amp;#34;(driver|version|firmware)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="known-tls-capable-hardware"&gt;Known TLS-Capable Hardware&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;** Intel Network Cards:**&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Intel X700 series (X710, X722) - i40e driver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check for Intel X710/X722 support:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lspci &lt;span class="p"&gt;|&lt;/span&gt; grep -E &lt;span class="s2"&gt;&amp;#34;(X710|X722|82599)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Intel E800 series (E810) - ice driver &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check for Intel E810 support:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lspci &lt;span class="p"&gt;|&lt;/span&gt; grep E810
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Mellanox/NVIDIA ConnectX Series:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ConnectX-5, ConnectX-6 series - mlx5_core driver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check for Mellanox cards:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lspci &lt;span class="p"&gt;|&lt;/span&gt; grep -i mellanox
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Verify ConnectX model:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lspci -vv &lt;span class="p"&gt;|&lt;/span&gt; grep -A &lt;span class="m"&gt;10&lt;/span&gt; -i mellanox &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s2"&gt;&amp;#34;Part number&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Broadcom NetXtreme Series:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# NetXtreme-E series - bnxt_en driver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check for Broadcom cards:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lspci &lt;span class="p"&gt;|&lt;/span&gt; grep -i broadcom
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-4-test-hardware-tls-capabilities"&gt;Step 4: Test Hardware TLS Capabilities&lt;/h2&gt;
&lt;p&gt;Attempt to enable TLS offload features to verify hardware support:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Test if TLS TX offload can be enabled&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ethtool -K eth0 tls-hw-tx-offload on
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;TX Offload test: &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Test if TLS RX offload can be enabled &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ethtool -K eth0 tls-hw-rx-offload on
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;RX Offload test: &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check the results&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ethtool -k eth0 &lt;span class="p"&gt;|&lt;/span&gt; grep tls
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Look for any error messages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dmesg &lt;span class="p"&gt;|&lt;/span&gt; tail -5
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Interpreting results:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Success (return code 0)&lt;/strong&gt;: Hardware supports the feature&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Failure (return code ≠ 0)&lt;/strong&gt;: Hardware doesn&amp;rsquo;t support this feature&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No change in status&lt;/strong&gt;: Feature may be already enabled or hardware doesn&amp;rsquo;t support it&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="step-5-verify-prerequisites"&gt;Step 5: Verify Prerequisites&lt;/h2&gt;
&lt;p&gt;Some NICs require specific prerequisites before TLS offload can work:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check if checksum offload is enabled (required for TLS offload)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ethtool -k eth0 &lt;span class="p"&gt;|&lt;/span&gt; grep -E &lt;span class="s2"&gt;&amp;#34;(rx-checksumming|tx-checksumming)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Enable checksum offload if disabled&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ethtool -K eth0 rx-checksumming on tx-checksumming on
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check for other required features&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ethtool -k eth0 &lt;span class="p"&gt;|&lt;/span&gt; grep -E &lt;span class="s2"&gt;&amp;#34;(scatter-gather|tcp-segmentation-offload)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Some drivers require specific firmware versions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ethtool -i eth0 &lt;span class="p"&gt;|&lt;/span&gt; grep firmware
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-6-advanced-hardware-detection"&gt;Step 6: Advanced Hardware Detection&lt;/h2&gt;
&lt;p&gt;For more detailed hardware analysis:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check NIC&amp;#39;s crypto capabilities at kernel level&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /sys/class/net/eth0/device/vendor
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /sys/class/net/eth0/device/device
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Look for hardware crypto engines&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lspci -vv &lt;span class="p"&gt;|&lt;/span&gt; grep -A &lt;span class="m"&gt;50&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Ethernet controller&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -i crypto
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check interrupt vectors (more vectors often indicate more features)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /proc/interrupts &lt;span class="p"&gt;|&lt;/span&gt; grep eth0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Examine network device features at kernel level&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /sys/class/net/eth0/features
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-7-validate-with-kernel-tls-support"&gt;Step 7: Validate with Kernel TLS Support&lt;/h2&gt;
&lt;p&gt;Verify that your kernel can work with your hardware:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Ensure kernel TLS module is available&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsmod &lt;span class="p"&gt;|&lt;/span&gt; grep tls &lt;span class="o"&gt;||&lt;/span&gt; sudo modprobe tls
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check kernel version compatibility&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;uname -r
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Minimum versions:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# - 4.13+ for basic kTLS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# - 4.17+ for RX offload &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# - 5.2+ for improved hardware support&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Test TLS ULP availability&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /proc/sys/net/ipv4/tcp_available_ulp &lt;span class="p"&gt;|&lt;/span&gt; grep tls
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once you&amp;rsquo;ve verified hardware support, you can proceed with confidence that your system can take full advantage of kernel TLS performance benefits. If your hardware doesn&amp;rsquo;t support TLS offload, you can still benefit from kTLS software mode, which provides kernel-level TLS processing advantages over userspace implementations.&lt;/p&gt;
&lt;p&gt;kTLS makes TLS faster and simpler by moving encryption into the kernel and hardware instead of relying on complex userspace libraries. It reduces CPU load, streamlines operations, and gives high-performance secure apps a clear advantage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;References:&lt;/strong&gt;&lt;/p&gt;
&lt;a class="bookmark" href="https://docs.kernel.org/networking/tls-offload.html"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/thumbnail/logo.svg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Kernel TLS offload — The Linux Kernel documentation&lt;/strong&gt;
&lt;span class="bookmark-host"&gt;The Linux Kernel&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://docs.nvidia.com/networking/display/mlnxofedv24100700/kernel+transport+layer+security+(ktls)+offloads"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/thumbnail/nvidia-logo.svg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Kernel Transport Layer Security (kTLS) Offloads - NVIDIA Docs&lt;/strong&gt;
&lt;span class="bookmark-host"&gt;NVIDIA Docs&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://docs.kernel.org/networking/tls.html"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/thumbnail/logo-1.svg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Kernel TLS — The Linux Kernel documentation&lt;/strong&gt;
&lt;span class="bookmark-host"&gt;The Linux Kernel&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://github.com/oracle/ktls-utils"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/thumbnail/ktls-utils" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;GitHub - oracle/ktls-utils: TLS handshake utilities for in-kernel TLS consumers&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;TLS handshake utilities for in-kernel TLS consumers - oracle/ktls-utils&lt;/p&gt;
&lt;span class="bookmark-host"&gt;GitHub · oracle&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;</content></entry><entry><title>What Makes Bootable Containers Different from Traditional Containers?</title><link href="https://firstfinger.io/what-makes-bootable-containers-different/"/><id>https://firstfinger.io/what-makes-bootable-containers-different/</id><updated>2025-08-17T10:20:47Z</updated><published>2025-08-17T10:20:20Z</published><author><name>Anurag Vishwakarma</name></author><summary>We all know containers run on top of an operating system. But what if the container itself could be the operating system?</summary><content type="html">&lt;p&gt;If you’ve used containers before, you already know how much they’ve changed the way we build and run apps. Tools like Docker and Kubernetes made packaging and deploying software simpler than ever. But there’s another step forward you might not have seen yet: &lt;em&gt;bootable containers&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="the-container-recap"&gt;The Container Recap&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/image.png"
alt="Image Source: Docker"&gt;&lt;figcaption&gt;
&lt;p&gt;Image Source: Docker&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Traditional containers work by sharing the host&amp;rsquo;s kernel while providing isolated userspace environments for applications. When you run a Docker container, you&amp;rsquo;re essentially starting a segregated process on your host OS with its own filesystem, network interfaces, and process tree. The container runtime manages these containers on top of your existing operating system.&lt;/p&gt;
&lt;h2 id="what-makes-bootable-containers-different"&gt;What Makes Bootable Containers Different?&lt;/h2&gt;
&lt;p&gt;Bootable containers flip this model on its head. Instead of running on top of an existing OS, they &lt;strong&gt;become&lt;/strong&gt; the OS. A bootable container is packaged using container technologies but is designed to boot directly on bare metal or in a virtual machine.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/linux-os-vs-containers-vs-bootbale-containers.png"
alt="Architecture comparison of Linux OS, regular containers, and bootable containers."&gt;&lt;figcaption&gt;
&lt;p&gt;Architecture comparison of Linux OS, regular containers, and bootable containers.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id="bootable-containers-vs-traditional-linux-os"&gt;Bootable Containers vs. Traditional Linux OS&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Traditional Linux OS&lt;/th&gt;
&lt;th&gt;Bootable Containers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Update Mechanism&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Package-by-package with package manager&lt;/td&gt;
&lt;td&gt;Atomic, image-based updates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Configuration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Often diverges between systems&lt;/td&gt;
&lt;td&gt;Consistent across fleet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Filesystem&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mutable, changes in place&lt;/td&gt;
&lt;td&gt;Immutable root filesystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Unique per machine&lt;/td&gt;
&lt;td&gt;Identical images across all systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Customization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ad-hoc changes on running system&lt;/td&gt;
&lt;td&gt;Image rebuilding with version control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rollbacks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Complex, often manual&lt;/td&gt;
&lt;td&gt;Simple, atomic image rollback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Footprint&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Often includes unnecessary packages&lt;/td&gt;
&lt;td&gt;Minimal, purposefully designed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security Profile&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Larger attack surface&lt;/td&gt;
&lt;td&gt;Reduced attack surface&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/image-1.png"
alt="Image Source: Redhat"&gt;&lt;figcaption&gt;
&lt;p&gt;Image Source: Redhat&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;With traditional OS, you typically install a base system and then modify it over time with package managers. Each system tends to evolve independently, leading to &amp;ldquo;&lt;strong&gt;configuration drift&lt;/strong&gt;&amp;rdquo; where supposedly identical systems have subtle differences that cause problems.&lt;/p&gt;
&lt;aside class="callout callout-info"&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Traditional Linux&lt;/th&gt;
&lt;th&gt;Regular Containers&lt;/th&gt;
&lt;th&gt;Bootable Containers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Execution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Direct on hardware&lt;/td&gt;
&lt;td&gt;On host OS&lt;/td&gt;
&lt;td&gt;Direct on hardware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kernel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Own kernel&lt;/td&gt;
&lt;td&gt;Shared host kernel&lt;/td&gt;
&lt;td&gt;Own kernel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Updates&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Package manager&lt;/td&gt;
&lt;td&gt;Image replacement&lt;/td&gt;
&lt;td&gt;OS image replacement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Isolation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None (full system)&lt;/td&gt;
&lt;td&gt;Process/filesystem isolation&lt;/td&gt;
&lt;td&gt;None (full system)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stored on local disk&lt;/td&gt;
&lt;td&gt;Ephemeral or volumes&lt;/td&gt;
&lt;td&gt;Separate data volumes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Packaging&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;RPM/DEB packages&lt;/td&gt;
&lt;td&gt;Container images&lt;/td&gt;
&lt;td&gt;Container images&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Boot Process&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Traditional boot loader&lt;/td&gt;
&lt;td&gt;Container runtime&lt;/td&gt;
&lt;td&gt;Boot loader to container&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ideal For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;General purpose&lt;/td&gt;
&lt;td&gt;Application deployment&lt;/td&gt;
&lt;td&gt;Infrastructure as code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Configuration management&lt;/td&gt;
&lt;td&gt;Container orchestration&lt;/td&gt;
&lt;td&gt;Image-based orchestration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/image-2.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Bootable containers, on the other hand, treat the operating system as an immutable artifact. Rather than updating packages in place, you replace the entire OS image when updates are needed, ensuring consistency across your infrastructure.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="open-source-projects"&gt;Open Source Projects&lt;/h2&gt;
&lt;p&gt;Several projects are making bootable containers accessible:&lt;/p&gt;
&lt;h3 id="1-bootc"&gt;1. bootc&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://developers.redhat.com/articles/2024/09/24/bootc-getting-started-bootable-containers" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;bootc&lt;/strong&gt;&lt;/a&gt;
is Red Hat&amp;rsquo;s initiative for creating bootable containers. It enables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Direct booting of OCI container images as the host OS&lt;/li&gt;
&lt;li&gt;Integration with Fedora and RHEL ecosystems&lt;/li&gt;
&lt;li&gt;Standardized approach to bootable containers&lt;/li&gt;
&lt;li&gt;Simple transactional updates and rollbacks&lt;/li&gt;
&lt;/ul&gt;
&lt;a class="bookmark" href="https://developers.redhat.com/articles/2024/09/24/bootc-getting-started-bootable-containers"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;bootc: Getting started with bootable containers | Red Hat Developer&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;With bootc (bootable containers), you can use the same container technology for building and managing immutable operating systems. Check out these two video demos and learn how to get started&lt;/p&gt;
&lt;span class="bookmark-host"&gt;Red Hat Developer · Valentin Rothberg&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://github.com/bootc-dev/bootc"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/thumbnail/bootc" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;GitHub - bootc-dev/bootc: Boot and upgrade via container images&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Boot and upgrade via container images. Contribute to bootc-dev/bootc development by creating an account on GitHub.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;GitHub · bootc-dev&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://bootc-dev.github.io/bootc/"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Introduction - bootc&lt;/strong&gt;
&lt;span class="bookmark-host"&gt;bootc&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h3 id="2-linuxkit"&gt;2. LinuxKit&lt;/h3&gt;
&lt;p&gt;Created by Docker, &lt;a href="https://www.docker.com/blog/introducing-linuxkit-container-os-toolkit/" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;LinuxKit&lt;/strong&gt;&lt;/a&gt;
is a toolkit for building custom operating systems that run containers. It offers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modular approach to OS building with containers&lt;/li&gt;
&lt;li&gt;Security-first design philosophy&lt;/li&gt;
&lt;li&gt;Minimal base with just what you need&lt;/li&gt;
&lt;li&gt;Ability to target multiple platforms including cloud and IoT&lt;/li&gt;
&lt;/ul&gt;
&lt;a class="bookmark" href="https://www.docker.com/blog/introducing-linuxkit-container-os-toolkit/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/thumbnail/docker-default-meta-image-1110x583.png" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Announcing LinuxKit: A Toolkit for building Secure, Lean and Portable Linux Subsystems | Docker&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Learn from Docker experts to simplify and advance your app development and management with Docker. Stay up to date on Docker events and new version&lt;/p&gt;
&lt;span class="bookmark-host"&gt;Docker · Justin Cormack&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://github.com/linuxkit/linuxkit"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/thumbnail/linuxkit" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;GitHub - linuxkit/linuxkit: A toolkit for building secure, portable and lean operating systems for containers&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;A toolkit for building secure, portable and lean operating systems for containers - linuxkit/linuxkit&lt;/p&gt;
&lt;span class="bookmark-host"&gt;GitHub · linuxkit&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h3 id="3-other-notable-projects"&gt;3. Other Notable Projects&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.flatcar.org/" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;Flatcar Container Linux&lt;/strong&gt;&lt;/a&gt;
: A community-driven immutable Linux distribution forked from CoreOS&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bottlerocket-os/bottlerocket#bottlerocket-os" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;AWS Bottlerocket&lt;/strong&gt;&lt;/a&gt;
: AWS&amp;rsquo;s minimal OS designed specifically for running containers&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fedoraproject.org/coreos/" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;Fedora CoreOS&lt;/strong&gt;&lt;/a&gt;
: Red Hat&amp;rsquo;s immutable OS combining the best of CoreOS and Project Atomic&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.talos.dev/" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;Talos Linux:&lt;/strong&gt;&lt;/a&gt;
** **Kubernetes-focused OS built from container images.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-are-the-use-cases"&gt;What are the Use Cases?&lt;/h2&gt;
&lt;h3 id="1-edge-computing-at-scale"&gt;1. Edge Computing at Scale&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: A telecommunications company managing thousands of edge computing nodes across multiple countries.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Using bootable containers allows them to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deploy identical OS environments to all edge nodes&lt;/li&gt;
&lt;li&gt;Update the entire fleet with a single tested image&lt;/li&gt;
&lt;li&gt;Rollback problematic updates with a simple reboot&lt;/li&gt;
&lt;li&gt;Reduce edge device management overhead&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="2-hybrid-cloud-consistency"&gt;2. Hybrid Cloud Consistency&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: An enterprise running workloads across on-premises data centers, AWS, and Azure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Bootable containers provide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The same base OS across all environments&lt;/li&gt;
&lt;li&gt;Consistent behavior regardless of underlying infrastructure&lt;/li&gt;
&lt;li&gt;Simplified compliance and security auditing&lt;/li&gt;
&lt;li&gt;Reduced &amp;ldquo;works in my environment&amp;rdquo; issues&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="3-iot-fleet-management"&gt;3. IoT Fleet Management&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: Smart manufacturing deployment with hundreds of specialized devices on the factory floor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Bootable containers deliver:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reliable, atomic updates to all devices&lt;/li&gt;
&lt;li&gt;Minimal OS footprint for resource-constrained devices&lt;/li&gt;
&lt;li&gt;Automatic rollback if devices fail to come online after update&lt;/li&gt;
&lt;li&gt;Unified management plane for the entire fleet&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="4-security-focused-operations"&gt;4. Security-Focused Operations&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: Financial services company with strict security requirements.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Bootable containers enhance security through:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reduced attack surface with minimal OS components&lt;/li&gt;
&lt;li&gt;Immutable infrastructure preventing runtime modifications&lt;/li&gt;
&lt;li&gt;Cryptographically verified OS images&lt;/li&gt;
&lt;li&gt;Consistent security controls across all systems&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;Bootable containers reduce configuration drift, shrink the attack surface, and let you manage OS updates much like application releases. They’re especially useful for edge fleets, IoT, cloud-native node images, and security-sensitive environments.&lt;/p&gt;
&lt;p&gt;Bootable containers package an entire operating system as an immutable, container-style image that can boot directly on hardware or in a VM. Unlike regular containers that depend on a host OS and share its kernel, bootable images become the OS: they provide a minimal, consistent runtime, atomic updates, and simple rollbacks.&lt;/p&gt;</content></entry><entry><title>What's Inside My Home Lab?</title><link href="https://firstfinger.io/my-home-lab/"/><id>https://firstfinger.io/my-home-lab/</id><updated>2025-08-07T08:50:48Z</updated><published>2025-08-06T08:45:00Z</published><author><name>Anurag Vishwakarma</name></author><category term="Self Host"/><category term="Network"/><category term="Storage"/><category term="Processor"/><category term="Linux"/><category term="Container"/><summary>What's actually running in my home lab and how I built it all for under $70. From K3s clusters on VMs to self-hosted services with proper HTTPS - a complete walkthrough of my personal infrastructure.</summary><content type="html">&lt;p&gt;&lt;strong&gt;Picture this:&lt;/strong&gt; It&amp;rsquo;s 2 AM, and I&amp;rsquo;m staring at my AWS bill with a mix of horror and fascination. Another $100 gone, just for experimenting with some Kubernetes deployments and testing a few CI/CD pipelines. As a DevOps engineer, I live and breathe infrastructure, but those cloud costs were eating into my wallet faster than I could learn.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s when it hit me – why not bring the cloud home?&lt;/p&gt;
&lt;h2 id="why-i-built-a-home-lab-"&gt;Why I Built a Home Lab ?&lt;/h2&gt;
&lt;p&gt;Let me be honest with you. Home labbing isn&amp;rsquo;t just a hobby; it&amp;rsquo;s an addiction. It&amp;rsquo;s that irresistible urge to understand how things &lt;em&gt;really&lt;/em&gt; work beneath the abstractions of managed services and cloud platforms. When you&amp;rsquo;re in DevOps, SRE, or any infrastructure role, you quickly realize that reading documentation only gets you so far. You need to feel the pain of a failed deployment, experience the satisfaction of a perfectly configured load balancer, and yes, even troubleshoot why your DNS is acting up at 3 AM.&lt;/p&gt;
&lt;p&gt;A home lab gives you something precious: a consequence-free environment where breaking things is not just acceptable, it&amp;rsquo;s encouraged. No angry Slack messages, no incident reports, just pure learning through experimentation.&lt;/p&gt;
&lt;p&gt;But here&amp;rsquo;s the real kicker, it&amp;rsquo;s addictive. Once you taste the freedom of having your own infrastructure, you&amp;rsquo;ll find yourself constantly thinking: &amp;ldquo;What if I add another node?&amp;rdquo; or &amp;ldquo;Maybe I should try that new monitoring stack.&amp;rdquo; Before you know it, you&amp;rsquo;re explaining to your family why the internet cabinet now sounds like a small data center.&lt;/p&gt;
&lt;h2 id="the-hardware-setup"&gt;The Hardware Setup&lt;/h2&gt;
&lt;p&gt;My journey started with a simple principle: maximum learning for minimum cost. After getting burned by those cloud bills, I was determined to build something sustainable.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/Homelab-front.webp"
alt="Dell OptiPlex 7050 with a Raspberry Pi 4B on the left side and a TP-Link Gigabit router placed on top"&gt;&lt;figcaption&gt;
&lt;p&gt;Dell OptiPlex 7040 with a Raspberry Pi 4B on the left side and a TP-Link Gigabit Fibre Router placed on top&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;One of the most cost-effective parts of my setup is a second-hand Dell OptiPlex 7040 Small Form factor (SFF) PC I found for just ₹4,000 (around $50). To complement it, I added two Raspberry Pis, each costing about $10, complete with a 3-month replacement warranty, 4GB of RAM, and a 32GB SanDisk memory card and all for ₹1,600 ($20).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This little machine packs some serious punch&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Intel i5 6th generation processor with Intel® HD Graphics 630&lt;/li&gt;
&lt;li&gt;32GB DDR4 RAM (I upgraded this myself)&lt;/li&gt;
&lt;li&gt;512GB Samsung 980 NVMe SSD for the OS and using as root drive&lt;/li&gt;
&lt;li&gt;2TB SATA SSD for data and VM storage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then there are my two Raspberry Pi 4B companions. One sits at home with a 32GB SanDisk SD card, while its sibling lives at my relative&amp;rsquo;s house with 64GB storage. Why the geographic distribution? Well, what&amp;rsquo;s the fun in a home lab without some multi-site complexity?&lt;/p&gt;
&lt;p&gt;The total hardware investment? Around $70 USD. Compare that to a few months of serious cloud experimentation, and you&amp;rsquo;ll see why this made sense.&lt;/p&gt;
&lt;h2 id="networking-and-connectivity"&gt;Networking and Connectivity&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s where things get interesting. My home setup runs on a TP-Link router with gigabit connections throughout. I invested in a dedicated public IP from my ISP, about 1,800 rupees ($20) annually. This gives me the flexibility to expose services properly and experiment with different networking configurations.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/homelab-side.webp"
alt="Dell OptiPlex 7040 PC with a TP-Link Gigabit router placed on top, connected with Ethernet and power cables."&gt;&lt;figcaption&gt;
&lt;p&gt;Dell OptiPlex 7040 PC with a TP-Link Gigabit router placed on top, connected with Ethernet and power cables.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The real magic happens with Tailscale. Initially, I planned to use WireGuard for connecting my distributed nodes. But after considering the config management overhead like generating keys, distributing configs, maintaining connections this is headache for me so I opted for Tailscale instead.&lt;/p&gt;
&lt;p&gt;Tailscale creates a mesh network between all my devices. My home setup uses Tailscale&amp;rsquo;s subnet router feature to expose my entire LAN network, while the remote Raspberry Pi connects seamlessly from across the city. The beauty? No exposed ports, no complex firewall rules, just secure, encrypted communication between all nodes.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/CleanShot-2025-08-07-at-13.36.44@2x.webp"
alt="Tailscale dashboard showing all connected devices in my homelab and personal network."&gt;&lt;figcaption&gt;
&lt;p&gt;Tailscale dashboard showing all connected devices in my homelab and personal network.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The ease of management sold me completely. Instead of juggling WireGuard configs across multiple devices, I just setup Tailscale on each machine with pre auth tokens, and they instantly see each other. It&amp;rsquo;s like having a private cloud network that spans locations.&lt;/p&gt;
&lt;h2 id="running-vms-with-qemu"&gt;Running VMs with QEMU&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s where my home lab really comes alive. With only two physical nodes, I needed a way to create a realistic multi-node environment for learning.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/CleanShot-2025-08-07-at-13.46.36@2x.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;I use QEMU-KVM as the hypervisor to run virtual machines with Ubuntu cloud-based images, and I leverage cloud-init for automated setup. For the initial configuration, such as creating users, adding SSH keys, and setting up the network with a static IP, I use Cockpit. Cockpit is a great tool for managing servers.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/CleanShot-2025-08-07-at-13.46.56@2x.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;As you can see in the screenshots, I can easily manage virtual machines, monitor system resources, create or delete users, add SSH keys, and check the overall health of the system.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;I run five virtual machines on the Dell OptiPlex each with 2 CPU cores, 4GB RAM, 100GB of storage.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/CleanShot-2025-08-07-at-13.54.14@2x.png" alt=""&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;3 Master nodes&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2 Worker nodes&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This configuration gives me a proper mini Kubernetes cluster with realistic resource constraints. Each VM runs Ubuntu Server, and the resource allocation ensures I can simulate real-world scenarios without overwhelming my physical hardware.&lt;/p&gt;
&lt;p&gt;Why this specific setup? In production, you want odd numbers of master nodes for etcd quorum, and having separate workers lets me experiment with node affinity, taints, tolerations, and all those Kubernetes concepts that only make sense when you have multiple nodes to work with.&lt;/p&gt;
&lt;h2 id="my-kubernetes-setup"&gt;My Kubernetes Setup&lt;/h2&gt;
&lt;p&gt;Running full Kubernetes on resource-constrained hardware is like trying to fit an elephant in a Mini Cooper. That&amp;rsquo;s why I chose K3s, Rancher&amp;rsquo;s lightweight Kubernetes distribution. It gives me the complete Kubernetes API and functionality while being designed exactly for setups like mine.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/CleanShot-2025-08-07-at-13.51.35@2x.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;K3s strips out the bloat while keeping everything you need for learning and development. It uses SQLite instead of etcd for single-node setups (though my cluster uses etcd), includes Traefik as the default ingress controller but i&amp;rsquo;m not using that, and comes with a built-in service load balancer.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/CleanShot-2025-08-07-at-13.57.00@2x.webp" alt=""&gt;&lt;/p&gt;
&lt;p&gt;This is where my setup gets really exciting. I practice GitOps using ArgoCD connected to my private GitHub repository.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;My ArgoCD repo structure looks like this:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;argocd/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── Project-1/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── deployment.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── svc.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── Project-2/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── Project-3/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/CleanShot-2025-08-07-at-14.05.03@2x.webp" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Each project folder contains Kubernetes manifests – deployments, services, ingress rules, config maps. When I push changes to GitHub, I sync Argo CD (though I&amp;rsquo;m planning to automate this with webhooks), and my cluster updates accordingly.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/CleanShot-2025-08-07-at-14.05.42@2x.webp" alt=""&gt;&lt;/p&gt;
&lt;p&gt;This workflow mirrors what I use professionally, giving me hands-on experience with modern deployment practices. I can experiment with blue-green deployments, canary releases, and rollback strategies in a safe environment.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/CleanShot-2025-08-07-at-14.05.30@2x.webp" alt=""&gt;&lt;/p&gt;
&lt;p&gt;My Kubernetes networking uses Flannel for pod-to-pod communication across nodes. For exposing services, I primarily use NodePort, though I&amp;rsquo;m planning to implement MetalLB as a load balancer to get closer to production-like service exposure.&lt;/p&gt;
&lt;aside class="callout callout-info"&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;h2 id="docker-and-container-management"&gt;Docker and Container Management&lt;/h2&gt;
&lt;p&gt;While Kubernetes handles orchestration, I also run standalone Docker containers for services that don&amp;rsquo;t need the full Kubernetes treatment.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/CleanShot-2025-08-07-at-14.08.03@2x.webp" alt=""&gt;&lt;/p&gt;
&lt;p&gt;I use Portainer Business (free for individual users for one year) as my Docker management interface. It provides a web UI for managing containers, images, networks, and volumes. Through Portainer, I can quickly deploy new containers, monitor resource usage, check logs, and manage container lifecycles without dropping to the command line.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/CleanShot-2025-08-07-at-14.08.10@2x.webp" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2025/08/CleanShot-2025-08-07-at-14.09.05@2x.webp" alt=""&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve configured custom Docker bridge networks instead of using the default bridge. This gives me DNS resolution between containers – they can communicate using container names instead of IP addresses. It also provides network isolation and makes my reverse proxy configs much cleaner.&lt;/p&gt;
&lt;p&gt;This setup makes my configurations much simpler – instead of hardcoding IP addresses, I reference containers by name, making everything more maintainable.&lt;/p&gt;
&lt;h2 id="exposing-services-to-the-internet"&gt;Exposing Services to the Internet&lt;/h2&gt;
&lt;p&gt;Getting my services accessible from the internet involves several layers. My TP-Link router handles port forwarding, directing incoming HTTP (80) and HTTPS (443) traffic to my Dell OptiPlex server. Having a dedicated public IP really helps here – no double NAT complications.&lt;/p&gt;
&lt;p&gt;This is where Caddy comes in. I compiled Caddy with the Cloudflare DNS plugin to handle automatic SSL certificate provisioning and renewal through Let&amp;rsquo;s Encrypt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Here&amp;rsquo;s how it works:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Caddy uses my Cloudflare DNS API token to create TXT records for domain validation&lt;/li&gt;
&lt;li&gt;Let&amp;rsquo;s Encrypt validates domain ownership and issues certificates&lt;/li&gt;
&lt;li&gt;Caddy handles certificate renewals automatically before expiration&lt;/li&gt;
&lt;li&gt;Based on the domain/subdomain, Caddy routes traffic to appropriate backends&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Final Caddyfile looks something like this:&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EMAIL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# acme_ca https://acme-staging-v02.api.letsencrypt.org/directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;acme_ca&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;acme&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;v02&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;letsencrypt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;servers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;protocols&lt;/span&gt; &lt;span class="n"&gt;h1&lt;/span&gt; &lt;span class="n"&gt;h2&lt;/span&gt; &lt;span class="n"&gt;h3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;admin&lt;/span&gt; &lt;span class="n"&gt;off&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;storage&lt;/span&gt; &lt;span class="n"&gt;file_system&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;log&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="n"&gt;DEBUG&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tls_config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dns&lt;/span&gt; &lt;span class="n"&gt;cloudflare&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CLOUDFLARE_API_TOKEN&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Strict&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Transport&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Security&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;max-age=31536000;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;nosniff&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Frame&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;DENY&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Referrer&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Policy&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;strict-origin-when-cross-origin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;cvscore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;cvscore&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;header_up&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Forwarded&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;For&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;remote_host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;header_up&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Real&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ne"&gt;IP&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;remote_host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;share&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;anyshare&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mf"&gt;10.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;1.15&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;30010&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;falcon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mf"&gt;10.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;1.20&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;header_up&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Forwarded&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;For&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;remote_host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;header_up&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Real&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ne"&gt;IP&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;remote_host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;handle_path&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;/*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="mf"&gt;10.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;1.20&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="mf"&gt;10.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;1.20&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ghost&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mf"&gt;10.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;1.20&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2368&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;my&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Frame&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Frame&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;SAMEORIGIN&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mf"&gt;10.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;1.10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9090&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;transport&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tls_insecure_skip_verify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;header_up&lt;/span&gt; &lt;span class="n"&gt;Host&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;header_up&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Forwarded&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Proto&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;header_up&lt;/span&gt; &lt;span class="n"&gt;Upgrade&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Upgrade&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;header_up&lt;/span&gt; &lt;span class="n"&gt;Connection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;flush_interval&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Frame&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Frame&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;SAMEORIGIN&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mf"&gt;10.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;1.100&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9090&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;transport&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tls_insecure_skip_verify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;header_up&lt;/span&gt; &lt;span class="n"&gt;Host&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;header_up&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Forwarded&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Proto&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;header_up&lt;/span&gt; &lt;span class="n"&gt;Upgrade&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Upgrade&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;header_up&lt;/span&gt; &lt;span class="n"&gt;Connection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;flush_interval&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;monitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="mf"&gt;10.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;1.100&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8090&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;argo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mf"&gt;10.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;1.11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;30443&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;transport&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tls_insecure_skip_verify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;drive&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;nextcloud&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;transport&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tls_insecure_skip_verify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;launch&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;launchstack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;jdownloader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5800&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;n8n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;n8n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5678&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;minio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;minio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;minio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;karakeep&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8443&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dns&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="mf"&gt;10.1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;1.100&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;photos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;immich&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2283&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;media&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;jellyfin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8096&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;portainer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;portainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9443&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;transport&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tls_insecure_skip_verify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Dynamic Proxy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;*.&lt;/span&gt;&lt;span class="n"&gt;srvr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5678&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#Simp Today&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tls_config_simp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;issuer&lt;/span&gt; &lt;span class="n"&gt;acme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EMAIL_SIMP&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dns&lt;/span&gt; &lt;span class="n"&gt;cloudflare&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CLOUDFLARE_API_TOKEN_SIMP&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Strict&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Transport&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Security&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;max-age=31536000;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;nosniff&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Frame&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;DENY&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Referrer&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Policy&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;strict-origin-when-cross-origin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;simp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config_simp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;simp&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;frontend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;simp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tls_config_simp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="n"&gt;simp&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For Kubernetes services, I use NodePort exposures and route to the appropriate node and port combination. This gives me production-like HTTPS endpoints for all my services without manual certificate management.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;When someone accesses my services, the request flows like this: DNS resolves to my public IP, hits my router on port 443, router forwards to Caddy, Caddy terminates SSL and routes to the appropriate container or Kubernetes service.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="what-im-actually-running"&gt;What I&amp;rsquo;m Actually Running&lt;/h2&gt;
&lt;p&gt;My home lab runs real services that I use daily, making the investment worthwhile beyond just learning.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AdGuard Home&lt;/strong&gt; runs on my Raspberry Pi as both my home DNS server and network-wide ad blocker. I&amp;rsquo;ve configured multiple blocklists that filter ads, trackers, and malicious domains for every device on my network. Sometimes it blocks 30-40% of DNS queries!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jellyfin&lt;/strong&gt; is my personal media server – think Netflix, but completely under my control. I can stream my media collection to any device, anywhere (thanks to Tailscale), with transcoding capabilities.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Immich&lt;/strong&gt; provides AI-powered photo organization and face recognition, like Google Photos but self-hosted. It&amp;rsquo;s connected to my MinIO storage backend for a complete photo management pipeline.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MinIO&lt;/strong&gt; serves as S3-compatible object storage. This gives me backend storage for applications like Immich and a testing ground for any projects that need S3 integration, all without AWS costs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Beszel&lt;/strong&gt; is my lightweight monitoring solution that keeps tabs on all my nodes – both local and remote. It provides system metrics and dashboards without the complexity of a full monitoring stack.&lt;/p&gt;
&lt;h2 id="what-this-has-taught-me"&gt;What This Has Taught Me&lt;/h2&gt;
&lt;p&gt;Every component of this setup has taught me something valuable. I&amp;rsquo;ve learned about networking, from subnetting to DNS to reverse proxies. Security concepts like certificate management and network segmentation. Automation through GitOps workflows and infrastructure as code. Monitoring and observability. And lots of troubleshooting, because something always breaks at 2 AM.&lt;/p&gt;
&lt;p&gt;The best part? These skills directly translate to my professional work. Concepts I experiment with at home often help me solve complex problems at work.&lt;/p&gt;
&lt;h2 id="whats-next"&gt;What&amp;rsquo;s Next&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m already planning the next phase of my setup like adding more Raspberry Pi nodes for edge computing experiments, implementing a proper monitoring stack with Prometheus and Grafana, setting up a CI/CD pipeline, and experimenting with service mesh technologies.&lt;/p&gt;
&lt;p&gt;The beauty of a home lab is that it&amp;rsquo;s never truly finished. There&amp;rsquo;s always another technology to explore, another problem to solve, another optimization to implement. And unlike those scary cloud bills, the only limit is your imagination (and maybe your electricity bill).&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re considering building your own home lab, my advice is simple: start small, start now, and prepare to be obsessed.&lt;/p&gt;</content></entry><entry><title>Ubuntu Server 24.04 LTS vs 22.04 LTS</title><link href="https://firstfinger.io/ubuntu-24-04-vs-22-04/"/><id>https://firstfinger.io/ubuntu-24-04-vs-22-04/</id><updated>2024-05-25T07:22:38Z</updated><published>2024-05-25T06:27:00Z</published><author><name>Anurag Vishwakarma</name></author><category term="Linux"/><category term="Cloud"/><category term="Self Host"/><summary>Explore the major upgrades, exciting new features, and enhancements in Ubuntu Server 24.04 LTS, including performance improvements, security updates, and extended support.</summary><content type="html">&lt;p&gt;Ubuntu has long been a favourite among developers and system administrators for its stability, security, and ease of use. With the release of Ubuntu Server Core 24.04 LTS (Noble Numbat), there are several exciting updates and improvements over its predecessor, Ubuntu Server Core 22.04 LTS (Jammy Jellyfish).&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see what exciting changes this latest release brings to the table.&lt;/p&gt;
&lt;h2 id="linux-kernel-and-system-updates"&gt;Linux Kernel and System Updates&lt;/h2&gt;
&lt;p&gt;First things first, Ubuntu 24.04 LTS comes with Linux kernel 6.8, which is a major upgrade over the 5.15 kernel used in 22.04 LTS. This new kernel promises better performance, improved hardware support, and stronger security measures.&lt;/p&gt;
&lt;aside class="callout callout-info"&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Ubuntu 22.04 LTS&lt;/th&gt;
&lt;th&gt;Ubuntu 24.04 LTS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Kernel Version&lt;/td&gt;
&lt;td&gt;5.15&lt;/td&gt;
&lt;td&gt;6.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance&lt;/td&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;td&gt;Enhanced&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hardware Support&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Improved&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="performance-engineering"&gt;Performance Engineering&lt;/h2&gt;
&lt;p&gt;Ubuntu 24.04 LTS brings several improvements to performance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Performance tools&lt;/strong&gt; are now pre-enabled and pre-loaded, allowing you to use them right away.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Low-latency kernel features&lt;/strong&gt; have been merged into the default kernel, reducing task scheduling delays.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frame pointers&lt;/strong&gt; are enabled by default on 64-bit architectures, enabling accurate and complete flame graphs for performance engineers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;bpftrace&lt;/strong&gt; is now a standard tool alongside existing profiling utilities.&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Ubuntu 22.04 LTS&lt;/th&gt;
&lt;th&gt;Ubuntu 24.04 LTS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Performance Tools&lt;/td&gt;
&lt;td&gt;Basic&lt;/td&gt;
&lt;td&gt;Pre-enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Low-latency Kernel Features&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frame Pointers&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bpftrace&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="security-enhancements"&gt;Security Enhancements&lt;/h2&gt;
&lt;p&gt;Ubuntu 24.04 LTS takes security very seriously, and you&amp;rsquo;ll find significant improvements in this area:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Free security maintenance for the main repository has been extended to 5 years, with an option to add 5 more years and include the universe repository via Ubuntu Pro.&lt;/li&gt;
&lt;li&gt;A legacy support add-on is now available for organizations that require long-term stability beyond 10 years.&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Security Feature&lt;/th&gt;
&lt;th&gt;Ubuntu 22.04 LTS&lt;/th&gt;
&lt;th&gt;Ubuntu 24.04 LTS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free Security Maintenance&lt;/td&gt;
&lt;td&gt;5 years&lt;/td&gt;
&lt;td&gt;5 years + 5 optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legacy Support&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="support-lifespan-and-upgrades"&gt;Support Lifespan and Upgrades&lt;/h2&gt;
&lt;p&gt;Ubuntu 24.04 LTS comes with an extended support lifespan and improved upgrade options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Support duration has been increased to 5 years, with the option to extend it further.&lt;/li&gt;
&lt;li&gt;Automatic upgrades will be offered to users of Ubuntu 23.10 and 22.04 LTS when 24.04.1 LTS is released.&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature/Support&lt;/th&gt;
&lt;th&gt;Ubuntu 22.04 LTS&lt;/th&gt;
&lt;th&gt;Ubuntu 24.04 LTS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Support Duration&lt;/td&gt;
&lt;td&gt;5 years (specific editions)&lt;/td&gt;
&lt;td&gt;5 years + optional extension&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automatic Upgrades&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (for 23.10 and 22.04)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="new-features-and-package-updates"&gt;New Features and Package Updates&lt;/h2&gt;
&lt;p&gt;Ubuntu 24.04 LTS brings a few exciting new features and package updates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Year 2038 support has been added for the armhf architecture.&lt;/li&gt;
&lt;li&gt;Linux kernel 6.8 and systemd v255.4 are the latest versions included.&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;New Feature&lt;/th&gt;
&lt;th&gt;Ubuntu 22.04 LTS&lt;/th&gt;
&lt;th&gt;Ubuntu 24.04 LTS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Year 2038 Support&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux Kernel Version&lt;/td&gt;
&lt;td&gt;5.15&lt;/td&gt;
&lt;td&gt;6.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Systemd Version&lt;/td&gt;
&lt;td&gt;249&lt;/td&gt;
&lt;td&gt;255.4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="application-and-service-improvements"&gt;Application and Service Improvements&lt;/h2&gt;
&lt;p&gt;Several key applications and services have received updates in Ubuntu 24.04 LTS:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nginx has been updated to version 1.24, offering better support for modern web protocols and improved performance.&lt;/li&gt;
&lt;li&gt;OpenLDAP has been upgraded to version 2.6.7, bringing bug fixes and enhancements.&lt;/li&gt;
&lt;li&gt;LXD is no longer pre-installed, reducing the initial footprint, but will be installed upon first use.&lt;/li&gt;
&lt;li&gt;Monitoring plugins have been updated to version 2.3.5, including multiple enhancements and new features for better system monitoring.&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service/Feature&lt;/th&gt;
&lt;th&gt;Ubuntu 22.04 LTS&lt;/th&gt;
&lt;th&gt;Ubuntu 24.04 LTS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Nginx&lt;/td&gt;
&lt;td&gt;1.20&lt;/td&gt;
&lt;td&gt;1.24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenLDAP&lt;/td&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;td&gt;2.6.7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LXD&lt;/td&gt;
&lt;td&gt;Pre-installed&lt;/td&gt;
&lt;td&gt;Installed on use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitoring Plugins&lt;/td&gt;
&lt;td&gt;2.3.2&lt;/td&gt;
&lt;td&gt;2.3.5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="infrastructure-and-deployment"&gt;Infrastructure and Deployment&lt;/h2&gt;
&lt;p&gt;Ubuntu 24.04 LTS also brings improvements to infrastructure and deployment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The new Landscape web portal is built with Canonical&amp;rsquo;s Vanilla Framework, providing an improved API, better accessibility, and a new repository snapshot service.&lt;/li&gt;
&lt;li&gt;Enhanced management capabilities for snaps, supporting on-premises, mixed, and hybrid cloud environments.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="should-you-upgrade-from-ubuntu-server-2204-lts-to-2404-lts"&gt;Should You Upgrade from Ubuntu Server 22.04 LTS to 24.04 LTS?&lt;/h2&gt;
&lt;h2 id="currently-ubuntu-server-2404-lts-offers"&gt;Currently Ubuntu Server 24.04 LTS offers:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Improved hardware support and compatibility with linux kernel 6.8&lt;/li&gt;
&lt;li&gt;Performance enhancements and faster boot times&lt;/li&gt;
&lt;li&gt;Extended 5-year support lifespan until June 2029&lt;/li&gt;
&lt;li&gt;Stronger security with 5+5 years of maintenance, legacy support add-on&lt;/li&gt;
&lt;li&gt;Seamless upgrade path from 23.10 and 22.04 LTS&lt;/li&gt;
&lt;li&gt;Updated packages like NGINX, OpenLDAP, and monitoring plugins&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="the-decision-to-upgrade-from-2204-lts-should-consider"&gt;The decision to upgrade from 22.04 LTS should consider:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;New hardware/peripheral compatibility needs&lt;/li&gt;
&lt;li&gt;Performance requirements for workloads&lt;/li&gt;
&lt;li&gt;Security and compliance priorities&lt;/li&gt;
&lt;li&gt;Support window and maintenance needs&lt;/li&gt;
&lt;li&gt;Ease of upgrade and potential downtime&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, Testing for stability and compatibility is crucial, especially for critical applications.&lt;/p&gt;
&lt;h4 id="ubuntu-release-notes"&gt;Ubuntu Release Notes:&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://discourse.ubuntu.com/t/ubuntu-24-04-lts-noble-numbat-release-notes/39890" target="_blank" rel="noopener noreferrer"&gt;Ubuntu 24.04 LTS (Noble Numbat)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://discourse.ubuntu.com/t/jammy-jellyfish-release-notes/24668" target="_blank" rel="noopener noreferrer"&gt;Ubuntu 22.04 LTS (Jammy Jellyfish)&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;a class="bookmark" href="/faas-vs-serverless/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/FaaS-vs-Serverless.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Is FaaS the Same as Serverless?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Are you confused about the difference between FaaS and serverless computing? All FaaS is serverless, but not all serverless is FaaS.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="/migrating-aws-cloud-bare-metal-servers/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/12/Migrating-Away-from-AWS-to-Bare-Metal-Servers.png" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;How Companies Are Saving Millions by Migrating Away from AWS to Bare Metal Servers?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Many startups initially launch on AWS or other public clouds because it allows rapid scaling without upfront investments. But as these companies grow, the operating costs steadily rise.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;</content></entry><entry><title>Is FaaS the Same as Serverless?</title><link href="https://firstfinger.io/faas-vs-serverless/"/><id>https://firstfinger.io/faas-vs-serverless/</id><updated>2024-04-21T10:38:24Z</updated><published>2024-04-21T10:24:46Z</published><author><name>Anurag Vishwakarma</name></author><category term="Cloud"/><category term="Programming"/><summary>Are you confused about the difference between FaaS and serverless computing? All FaaS is serverless, but not all serverless is FaaS.</summary><content type="html">&lt;p&gt;Suppose, as a small business owner, you&amp;rsquo;ve worked hard to build an e-commerce website that showcases your unique products. Your website is gaining traction, and you&amp;rsquo;re starting to see a steady increase in customer traffic. However, with this growth comes a new challenge - scalability.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.dribbble.com/userupload/10340481/file/original-19db36b6f8d63f3afc4450489a184424.png?resize=752x"
alt="Light Modern Ecommerce Product Page"&gt;&lt;figcaption&gt;
&lt;p&gt;Credit: Melody Onyeocha on Dribble&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Whenever a customer clicks your site&amp;rsquo;s &amp;ldquo;&lt;strong&gt;Buy Now&lt;/strong&gt;&amp;rdquo; button, your web application needs to process the order instantly, update the inventory, and send a confirmation email. But what happens when hundreds of customers start placing orders simultaneously? Your current server-based architecture simply can&amp;rsquo;t keep up, leading to slow response times, frustrated customers, and lost sales.&lt;/p&gt;
&lt;p&gt;So you need a more scalable solution for your web application. This is where serverless computing comes in, allowing you to focus on code rather than infrastructure.&lt;/p&gt;
&lt;h2 id="what-is-faas-functions-as-a-service"&gt;What is FaaS (Functions as a Service)?&lt;/h2&gt;
&lt;p&gt;Functions as a Service (FaaS) is a cloud computing service that allows you to run your code in response to specific events or requests, without the need to manage the underlying infrastructure. With FaaS, you simply write the individual functions (or &amp;ldquo;microservices&amp;rdquo;) that make up your application, and the cloud provider takes care of provisioning servers, scaling resources, and managing the runtime environment.&lt;/p&gt;
&lt;h3 id="the-benefits-of-faas"&gt;The benefits of FaaS:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Pay-per-use&lt;/strong&gt;: You only pay for the compute time when your functions are executed, rather than paying for always-on server capacity.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automatic scaling&lt;/strong&gt;: The cloud provider automatically scales your functions up or down based on incoming traffic, ensuring your application can handle sudden spikes in demand.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Focus on code&lt;/strong&gt;: With the infrastructure management handled by the cloud provider, you can focus solely on writing the business logic for your application.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;FaaS is specifically focused on building and running applications as a set of independent functions or microservices. Major cloud providers like &lt;a href="https://aws.amazon.com/lambda/" target="_blank" rel="noopener noreferrer"&gt;AWS (Lambda)&lt;/a&gt;
, &lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-overview?pivots=programming-language-csharp" target="_blank" rel="noopener noreferrer"&gt;Microsoft Azure (Functions)&lt;/a&gt;
, and &lt;a href="https://cloud.google.com/functions?hl=en" target="_blank" rel="noopener noreferrer"&gt;Google Cloud (Cloud Functions)&lt;/a&gt;
offer FaaS platforms that allow developers to write and deploy individual functions without managing the underlying infrastructure.&lt;/p&gt;
&lt;a class="bookmark" href="/migrating-aws-cloud-bare-metal-servers/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/12/Migrating-Away-from-AWS-to-Bare-Metal-Servers.png" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;How Companies Are Saving Millions by Migrating Away from AWS to Bare Metal Servers?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Many startups initially launch on AWS or other public clouds because it allows rapid scaling without upfront investments. But as these companies grow, the operating costs steadily rise.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="what-is-serverless"&gt;What is Serverless?&lt;/h2&gt;
&lt;p&gt;Serverless is a broader cloud computing model that involves FaaS but also includes other &lt;a href="/types-of-databases/" target="_blank" rel="noopener"&gt;fully managed services like databases&lt;/a&gt;
(e.g., AWS DynamoDB, Azure Cosmos DB, Google Cloud Datastore), message queues (e.g., AWS SQS, Azure Service Bus, Google Cloud Pub/Sub), and storage (e.g., AWS S3, Azure Blob Storage, Google Cloud Storage).&lt;/p&gt;
&lt;p&gt;In a serverless architecture, the cloud provider is responsible for provisioning, scaling, and managing the entire backend infrastructure required to run your application.&lt;/p&gt;
&lt;aside class="callout callout-info"&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;h3 id="the-benefits-of-serverless-computing"&gt;The benefits of Serverless Computing:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Reduced operational overhead&lt;/strong&gt;: With no servers to manage, you can focus entirely on building your application without worrying about infrastructure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Event-driven architecture&lt;/strong&gt;: Serverless applications are designed around event triggers, allowing you to react to user actions, data changes, or scheduled events in real time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Seamless scalability&lt;/strong&gt;: Serverless platforms automatically scale your application&amp;rsquo;s resources up and down based on demand, with no additional configuration required on your part.&lt;/li&gt;
&lt;/ol&gt;
&lt;a class="bookmark" href="/monolithic-vs-microservices/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/11/Monolithic-vs-Microservices.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Monolithic vs Microservices Architecture&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Monolithic architectures accelerate time-to-market, while Microservices are more suited for longer-term flexibility and maintainability at a substantial scale.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="faas-vs-serverless"&gt;FaaS vs Serverless&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/04/Traditional-IT-Infrastructure.png" alt="IT Infrastructure - IaaS, PaaS, FaaS"&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;FaaS&lt;/th&gt;
&lt;th&gt;Serverless&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Infrastructure Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Handles provisioning and scaling of servers/containers for your functions&lt;/td&gt;
&lt;td&gt;Handles provisioning and scaling of the entire backend infrastructure, including servers, databases, message queues, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pricing Model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pay-per-execution (cost per function invocation)&lt;/td&gt;
&lt;td&gt;Pay-per-use (cost per resource consumption, e.g., CPU, memory, data transfer)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scalability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automatically scales functions up and down based on demand&lt;/td&gt;
&lt;td&gt;Automatically scales the entire application infrastructure up and down based on demand&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stateful vs. Stateless&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Functions are typically stateless&lt;/td&gt;
&lt;td&gt;Supports both stateful and stateless services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Event-Driven Architecture&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supports event-driven execution of functions&lt;/td&gt;
&lt;td&gt;Natively supports event-driven architecture with managed event services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Third-Party Service Integration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Integrates with other cloud services through API calls&lt;/td&gt;
&lt;td&gt;Seamless integration with a rich ecosystem of managed cloud services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Development Focus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Concentrate on writing the application logic in the form of functions&lt;/td&gt;
&lt;td&gt;Concentrate on building the overall application structure and leveraging managed services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vendor Lock-in&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Some vendor lock-in, as functions are typically tied to a specific FaaS platform&lt;/td&gt;
&lt;td&gt;Potential for vendor lock-in, as Serverless often relies on a broader set of managed services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Examples&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS Lambda, Azure Functions, Google Cloud Functions, IBM Cloud Functions&lt;/td&gt;
&lt;td&gt;AWS (Lambda, API Gateway, DynamoDB), Azure (Functions, Cosmos DB, Event Grid), Google Cloud (Functions, Datastore, Pub/Sub), IBM Cloud (Functions, Object Storage, Databases)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Infrastructure Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Handles provisioning and scaling of servers/containers for your functions&lt;/td&gt;
&lt;td&gt;Handles provisioning and scaling of the entire backend infrastructure, including servers, databases, message queues, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="1-scope"&gt;1. Scope&lt;/h3&gt;
&lt;p&gt;FaaS is a specific type of serverless architecture that is focused on building and running applications as a set of independent functions. Serverless computing, on the other hand, is a broader term that encompasses a range of cloud computing models, including FaaS, BaaS, and others.&lt;/p&gt;
&lt;h3 id="2-granularity"&gt;2. Granularity&lt;/h3&gt;
&lt;p&gt;FaaS is a more fine-grained approach to building and running applications, as it allows developers to break down applications into smaller, independent functions. Serverless computing, on the other hand, can be used to build and run entire applications, not just individual functions.&lt;/p&gt;
&lt;h3 id="3-pricing"&gt;3. Pricing&lt;/h3&gt;
&lt;p&gt;FaaS providers typically charge based on the number of function executions and the duration of those executions. Serverless computing providers, on the other hand, may charge based on a variety of factors, such as the number of API requests, the amount of data stored, and the number of users.&lt;/p&gt;
&lt;a class="bookmark" href="/monorepos-vs-microrepos/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/08/Monorepos-vs-Microrepos.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Monorepos vs Microrepos: Which is better?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Find out why companies choose Monorepos over Microrepos strategies and how they impact scalability, governance, and code quality.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="major-cloud-providers-that-offer-faas-and-serverless-computing-services"&gt;Major cloud providers that offer FaaS and serverless computing services:&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;AWS Lambda&lt;/strong&gt; - AWS Lambda is a FaaS platform that allows developers to run code without provisioning or managing servers. Lambda supports a variety of programming languages, including Python, Node.js, Java, and C#.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure Functions&lt;/strong&gt; - Azure Functions is a serverless computing service that allows developers to build event-driven applications using a variety of programming languages, including C#, Java, JavaScript, and Python.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Google Cloud Functions&lt;/strong&gt; - Google Cloud Functions is a FaaS platform that allows developers to run code in response to specific events, such as changes to a Cloud Storage bucket or the creation of a Pub/Sub message.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IBM Cloud Functions&lt;/strong&gt; - IBM Cloud Functions is a serverless computing platform that allows developers to build and run event-driven applications using a variety of programming languages, including Node.js, Swift, and Java.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Oracle Cloud Functions&lt;/strong&gt; - Oracle Cloud Functions is a FaaS platform that allows developers to build and run serverless applications using a variety of programming languages, including Python, Node.js, and Java.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="choosing-between-faas-and-serverless"&gt;Choosing Between FaaS and Serverless&lt;/h2&gt;
&lt;h3 id="use-faas-for"&gt;Use FaaS for:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/monolithic-vs-microservices/" target="_blank" rel="noopener"&gt;Microservices-based applications&lt;/a&gt;
where you need flexibility and the ability to scale individual functions.&lt;/li&gt;
&lt;li&gt;&lt;a href="/what-is-apache-kafka-fast/" target="_blank" rel="noopener"&gt;Real-time data processing and event-driven architectures&lt;/a&gt;
.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="opt-for-serverless-computing-when"&gt;Opt for serverless computing when:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You&amp;rsquo;re deploying complex applications that require a unified environment for all components.&lt;/li&gt;
&lt;li&gt;You want to reduce the operational overhead of managing servers while maintaining control over application configurations.&lt;/li&gt;
&lt;/ul&gt;
&lt;a class="bookmark" href="/aws-lambda-vs-lambda-edge/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/09/AWS-Lambda-vs-Lambda@Edge.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;AWS Lambda vs. Lambda@Edge: Which Serverless Service Should You Use?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Lambda is regional while Lambda@Edge runs globally at edge locations. Lambda integrates with more AWS services. Lambda@Edge works with CloudFront.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="understand-with-an-example"&gt;Understand with an Example&lt;/h2&gt;
&lt;p&gt;Suppose you want to build a simple web application that allows users to upload images and apply filters to them. With a traditional server-based architecture, you would need to provision and manage servers, install and configure software, and handle scaling and availability. This can be time-consuming and expensive, especially if you&amp;rsquo;re just starting out.&lt;/p&gt;
&lt;p&gt;***With a serverless architecture, on the other hand, you can focus on writing the code for the application logic, and let the cloud provider handle the rest. ***&lt;/p&gt;
&lt;p&gt;For instance, you could use &lt;a href="/aws-lambda-vs-lambda-edge/" target="_blank" rel="noopener"&gt;AWS Lambda (FaaS) to run the code that processes the uploaded images, AWS S3 for storage, and other AWS services&lt;/a&gt;
like API Gateway and DynamoDB as part of the overall serverless architecture. The cloud provider would automatically scale the resources up or down based on demand, and you would only pay for the resources you actually use.&lt;/p&gt;
&lt;aside class="callout callout-info"&gt;
&lt;div class="callout-body"&gt;&lt;strong&gt;All FaaS is serverless, but not all serverless is FaaS.&lt;/strong&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;FaaS is a type of serverless architecture, but the two terms are not the same.&lt;/strong&gt;&lt;/em&gt; FaaS is all about creating and running applications as separate functions, while serverless computing is a wider term that covers different cloud computing models. In other words, FaaS is a specific way of doing serverless computing that involves breaking down an application into small, independent functions that can be run separately. Serverless computing, on the other hand, is a more general approach that can involve using different cloud services to build and run an application without having to manage servers.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="development-tooling-and-community-support"&gt;Development Tooling and Community Support&lt;/h2&gt;
&lt;p&gt;The major cloud providers offer varying levels of tooling and community support for their FaaS and serverless offerings. AWS has the largest community and a mature set of tools like AWS SAM for local development and testing of serverless applications.&lt;/p&gt;
&lt;p&gt;Microsoft Azure has good tooling integration with Visual Studio Code, while Google Cloud&amp;rsquo;s tooling is still catching up. A strong developer ecosystem and community support can be crucial when building and maintaining serverless applications.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="aws-vs-azure-vs-google-cloud-in-serverless-computing"&gt;AWS vs Azure vs Google Cloud in Serverless Computing&lt;/h2&gt;
&lt;h2 id="faas-platform"&gt;FaaS Platform&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Lambda&lt;/th&gt;
&lt;th&gt;Azure Functions&lt;/th&gt;
&lt;th&gt;Cloud Functions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Arm64 architecture&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compiled binary deployment&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wildcard SSL certificate free&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serverless KV store&lt;/td&gt;
&lt;td&gt;DynamoDB&lt;/td&gt;
&lt;td&gt;CosmosDB&lt;/td&gt;
&lt;td&gt;Datastore&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serverless SQL&lt;/td&gt;
&lt;td&gt;Aurora Serverless&lt;/td&gt;
&lt;td&gt;Azure SQL&lt;/td&gt;
&lt;td&gt;BigQuery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IaC deployment templates&lt;/td&gt;
&lt;td&gt;SAM, CloudFormation&lt;/td&gt;
&lt;td&gt;ARM, Bicep&lt;/td&gt;
&lt;td&gt;GDM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IaC drift detection&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Single shot stack deployment&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="developement"&gt;Developement&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Lambda&lt;/th&gt;
&lt;th&gt;Azure Functions&lt;/th&gt;
&lt;th&gt;Cloud Functions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Virtualized local execution&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FaaS dev tools native for arm64&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go SDK support&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHP SDK support&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VSCode tooling&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dev tools native for Apple Silicon&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="community"&gt;Community&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Lambda&lt;/th&gt;
&lt;th&gt;Azure Functions&lt;/th&gt;
&lt;th&gt;Cloud Functions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reddit community members&lt;/td&gt;
&lt;td&gt;278,455&lt;/td&gt;
&lt;td&gt;141,924&lt;/td&gt;
&lt;td&gt;46,415&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stack Overflow members&lt;/td&gt;
&lt;td&gt;256,700&lt;/td&gt;
&lt;td&gt;216,100&lt;/td&gt;
&lt;td&gt;54,300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Videos on YouTube channel&lt;/td&gt;
&lt;td&gt;16,308&lt;/td&gt;
&lt;td&gt;1,475&lt;/td&gt;
&lt;td&gt;4,750&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Twitter/X followers&lt;/td&gt;
&lt;td&gt;2.2 M&lt;/td&gt;
&lt;td&gt;1 M&lt;/td&gt;
&lt;td&gt;533 K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub stars for JS SDK&lt;/td&gt;
&lt;td&gt;7.5 K&lt;/td&gt;
&lt;td&gt;1.9 K&lt;/td&gt;
&lt;td&gt;2.8 K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub stars for .NET SDK&lt;/td&gt;
&lt;td&gt;2 K&lt;/td&gt;
&lt;td&gt;5 K&lt;/td&gt;
&lt;td&gt;908&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub stars for Python SDK&lt;/td&gt;
&lt;td&gt;8.7 K&lt;/td&gt;
&lt;td&gt;2.7 K&lt;/td&gt;
&lt;td&gt;4.6 K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub stars for Go SDK&lt;/td&gt;
&lt;td&gt;8.5 K&lt;/td&gt;
&lt;td&gt;1.5 K&lt;/td&gt;
&lt;td&gt;3.6 K&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="runtimes"&gt;Runtimes&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Runtime&lt;/th&gt;
&lt;th&gt;Lambda&lt;/th&gt;
&lt;th&gt;Azure Functions&lt;/th&gt;
&lt;th&gt;Cloud Functions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Custom (Linux)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom (Windows)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHP&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ruby&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C/C++&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="serverless-ai"&gt;Serverless AI&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Lambda&lt;/th&gt;
&lt;th&gt;Azure Functions&lt;/th&gt;
&lt;th&gt;Cloud Functions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Open AI&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Meta Llama2&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cohere&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI21&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon Titan&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mistral&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stability (SDXL)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Computer Vision&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;a class="bookmark" href="/bare-metal-vs-dedicated-host/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2024/04/Bare-Metal-Servers-vs.-Dedicated-Host.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Bare Metal Servers vs. Dedicated Host&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Bare metal gives you total control over the hypervisor for maximum flexibility and resource optimization. Dedicated hosts keep things simple with the cloud provider managing the VMs for you.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="/ansible-vs-terraform/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2024/04/Ansible-vs-Terraform.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Ansible vs Terraform&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Infrastructure automation and configuration management are two essential practices in modern IT operations, particularly in the DevOps &amp;amp; Cloud.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;</content></entry><entry><title>Bare Metal Servers vs. Dedicated Host</title><link href="https://firstfinger.io/bare-metal-vs-dedicated-host/"/><id>https://firstfinger.io/bare-metal-vs-dedicated-host/</id><updated>2024-04-04T05:13:14Z</updated><published>2024-04-04T05:00:42Z</published><author><name>Anurag Vishwakarma</name></author><category term="Cloud"/><category term="Container"/><category term="Linux"/><summary>Bare metal gives you total control over the hypervisor for maximum flexibility and resource optimization. Dedicated hosts keep things simple with the cloud provider managing the VMs for you.</summary><content type="html">&lt;p&gt;Let&amp;rsquo;s imagine you&amp;rsquo;re the owner of a fastest-growing e-commerce business. Your online store is getting more and more traffic every day, and you need to scale up your server infrastructure to handle the increased load. You&amp;rsquo;ve decided to move your operations to the cloud, but you&amp;rsquo;re unsure whether to go with bare metal servers or dedicated hosts. How does it impact your growth of business?&lt;/p&gt;
&lt;h2 id="what-are-bare-metal-servers--dedicated-hosts-and-what-is-the-main-difference"&gt;What are Bare Metal Servers &amp;amp; Dedicated Hosts, and what is the main difference?&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/04/Bare-Metal-Servers-vs.-Dedicated-Host.png"
alt="Bare Metal vs. Dedicated Host"&gt;&lt;figcaption&gt;
&lt;p&gt;Bare Metal vs. Dedicated Host&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href="/bare-metal-vs-virtual-machines-vs-containers/" target="_blank" rel="noopener"&gt;Both bare metal servers and dedicated hosts are physical machines&lt;/a&gt;
located in a cloud provider&amp;rsquo;s data center. The main difference lies in who manages the hypervisor layer – the software that allows you to run multiple virtual machines (VMs) on a single physical server.&lt;/p&gt;
&lt;h2 id="what-is-a-hypervisor-and-what-does-it-do"&gt;What is a Hypervisor and What Does It Do?&lt;/h2&gt;
&lt;p&gt;A hypervisor is a software layer that creates and runs virtual machines (VMs) on a physical host machine. It allows multiple &lt;a href="/in-memory-caching-vs-in-memory-data-store/" target="_blank" rel="noopener"&gt;operating systems to share the same hardware resources, such as CPU, memory, and storage.&lt;/a&gt;
Each VM runs its own operating system and applications, isolated from the others, providing a secure and efficient way to run multiple workloads on a single physical server.&lt;/p&gt;
&lt;h3 id="types-of-hypervisors-used-in-cloud-data-centers"&gt;Types of Hypervisors Used in Cloud Data Centers&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Type 1 (Bare-Metal)&lt;/li&gt;
&lt;li&gt;Type 2 (Hosted)&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/04/hypervisor-layer-diagram.png"
alt="Type 1 Hypervisor vs Type 2 Hypervisor Layer"&gt;&lt;figcaption&gt;
&lt;p&gt;Type 1 Hypervisor vs Type 2 Hypervisor&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Type 1 (Bare-Metal) Hypervisors&lt;/strong&gt; run directly on the host&amp;rsquo;s hardware, providing better performance and efficiency. Examples include VMware ESXi, Microsoft Hyper-V, and Citrix Hypervisor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Type 2 (Hosted) Hypervisors&lt;/strong&gt; run on top of a host operating system, like Windows or Linux. Examples include &lt;a href="/top-virtual-machine-software/" target="_blank" rel="noopener"&gt;VMware Workstation, Oracle VirtualBox, and Parallels Desktop&lt;/a&gt;
.&lt;/p&gt;
&lt;aside class="callout callout-info"&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;a class="bookmark" href="/bare-metal-vs-virtual-machines-vs-containers/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/04/A-Comparison-of-Bare-Metal--VMs--and-Containers---ThumbnailCompress.png" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Bare Metal vs Virtual Machines vs Containers: The Differences&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;When deploying a modern application stack, how do we decide which one to use? Bare Metal, VMs or Containers?&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="bare-metal-servers-full-control-but-more-complexity"&gt;Bare Metal Servers: Full Control but More Complexity&lt;/h2&gt;
&lt;p&gt;With a bare metal server, you&amp;rsquo;re essentially renting the entire physical machine from the cloud provider. However, &lt;strong&gt;you&amp;rsquo;re also responsible for installing and managing the hypervisor software&lt;/strong&gt; yourself. This gives you a lot of control and flexibility. &lt;strong&gt;You can tweak the hypervisor settings to optimize performance, overcommit resources (like CPU and RAM) to squeeze more virtual machines onto the physical server&lt;/strong&gt;, and have direct access to the hypervisor for monitoring, logging, and backing up your VMs.&lt;/p&gt;
&lt;aside class="callout callout-success"&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Bare Metal Server&lt;/th&gt;
&lt;th&gt;Dedicated Host&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hardware&lt;/td&gt;
&lt;td&gt;Physical server rented from cloud provider&lt;/td&gt;
&lt;td&gt;Physical server rented from cloud provider&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hypervisor Management&lt;/td&gt;
&lt;td&gt;Customer installs and manages the hypervisor software&lt;/td&gt;
&lt;td&gt;Cloud provider installs and manages the hypervisor software&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hypervisor Control&lt;/td&gt;
&lt;td&gt;Full control over hypervisor configuration settings&lt;/td&gt;
&lt;td&gt;Limited or no control over hypervisor settings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resource Allocation&lt;/td&gt;
&lt;td&gt;Can overcommit CPU, RAM across VMs for efficiency&lt;/td&gt;
&lt;td&gt;Limited ability to overcommit resources across VMs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitoring&lt;/td&gt;
&lt;td&gt;Direct access to hypervisor for monitoring and logging&lt;/td&gt;
&lt;td&gt;Rely on cloud provider&amp;rsquo;s monitoring tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backup/Recovery&lt;/td&gt;
&lt;td&gt;Can backup VMs directly through hypervisor&lt;/td&gt;
&lt;td&gt;Must use cloud provider&amp;rsquo;s backup/recovery services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalability&lt;/td&gt;
&lt;td&gt;Scale VMs up/down based on available server resources&lt;/td&gt;
&lt;td&gt;Request cloud provider to scale VMs up/down&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;Responsible for securing the hypervisor layer&lt;/td&gt;
&lt;td&gt;Cloud provider secures the hypervisor layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Management Complexity&lt;/td&gt;
&lt;td&gt;High, requires hypervisor expertise&lt;/td&gt;
&lt;td&gt;Low, cloud provider handles hypervisor management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pricing Model&lt;/td&gt;
&lt;td&gt;Pay for entire physical server capacity&lt;/td&gt;
&lt;td&gt;Pay for VM instances based on usage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use Cases&lt;/td&gt;
&lt;td&gt;High performance, legacy apps, regulatory compliance&lt;/td&gt;
&lt;td&gt;General-purpose applications, simplified operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Examples&lt;/td&gt;
&lt;td&gt;IBM Cloud Bare Metal, AWS EC2 Bare Metal&lt;/td&gt;
&lt;td&gt;IBM Cloud Dedicated Hosts, AWS Dedicated Hosts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="dedicated-hosts-simplicity-but-less-control"&gt;Dedicated Hosts: Simplicity but Less Control&lt;/h2&gt;
&lt;p&gt;On the other hand, a dedicated host is like renting an apartment in a managed building. &lt;strong&gt;The cloud provider takes care of the hypervisor layer for you&lt;/strong&gt;. All you have to do is tell them how many virtual machines you want, and they&amp;rsquo;ll set them up on the dedicated host for you. You don&amp;rsquo;t have to worry about managing the hypervisor or any of the underlying infrastructure.&lt;/p&gt;
&lt;p&gt;The trade-off, of course, is that &lt;strong&gt;you have less control over the specifics.&lt;/strong&gt; You can&amp;rsquo;t overcommit resources or tinker with the hypervisor settings. But for many businesses, the simplicity and convenience of a dedicated host are worth it.&lt;/p&gt;
&lt;a class="bookmark" href="/migrating-aws-cloud-bare-metal-servers/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/12/Migrating-Away-from-AWS-to-Bare-Metal-Servers.png" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;How Companies Are Saving Millions by Migrating Away from AWS to Bare Metal Servers?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Many startups initially launch on AWS or other public clouds because it allows rapid scaling without upfront investments. But as these companies grow, the operating costs steadily rise.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="open-source-hypervisor-alternatives"&gt;Open-Source Hypervisor Alternatives&lt;/h2&gt;
&lt;p&gt;While cloud providers typically use proprietary hypervisors like VMware ESXi or Hyper-V, there are also free and open-source alternatives available, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Proxmox Virtual Environment (Proxmox VE)&lt;/strong&gt;: A complete open-source server virtualization management solution that includes a KVM hypervisor and a web-based management interface.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kernel-based Virtual Machine (KVM)&lt;/strong&gt;: A type 1 hypervisor that&amp;rsquo;s part of the Linux kernel, providing virtualization capabilities without requiring proprietary software.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Xen Project Hypervisor&lt;/strong&gt;: An open-source type 1 hypervisor that supports a wide range of guest operating systems and virtualization use cases.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="which-option-is-right-for-your-e-commerce-business"&gt;Which Option is Right for Your E-commerce Business?&lt;/h2&gt;
&lt;p&gt;If you have a team of skilled system administrators who love getting their hands dirty with server configurations, and you need the flexibility to fine-tune your infrastructure for optimal performance, a bare metal server might be the way to go.&lt;/p&gt;
&lt;p&gt;However, if you&amp;rsquo;d rather focus on your core business and leave the nitty-gritty server management to the experts, a dedicated host could be a better fit. It&amp;rsquo;s a more hands-off approach, allowing you to concentrate on building and scaling your e-commerce platform without worrying about the underlying infrastructure.&lt;/p&gt;
&lt;a class="bookmark" href="/open-source-large-language-models/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/12/Open-Source-Large-Language-Models.png" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Should You Use Open Source Large Language Models?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;The benefits, risks, and considerations associated with using open-source LLMs, as well as the comparison with proprietary models.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="/devops-vs-sre-vs-platform-engineering/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/11/DevOps-vs-SRE-vs-Platform-Engineering.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;DevOps vs SRE vs Platform Engineering - Explained&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;At small companies, engineers often wear multiple hats, juggling a mix of responsibilities. Large companies have specialized teams with clearly defined roles in DevOps, SRE, and Platform Engineering.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;</content></entry><entry><title>Ansible vs Terraform</title><link href="https://firstfinger.io/ansible-vs-terraform/"/><id>https://firstfinger.io/ansible-vs-terraform/</id><updated>2024-04-02T20:15:01Z</updated><published>2024-04-02T20:00:50Z</published><author><name>Anurag Vishwakarma</name></author><category term="Cloud"/><category term="Container"/><category term="Database"/><category term="APIs"/><category term="AI ML"/><category term="Linux"/><category term="Network"/><category term="Self Host"/><summary>Infrastructure automation and configuration management are two essential practices in modern IT operations, particularly in the DevOps &amp; Cloud.</summary><content type="html">&lt;p&gt;Imagine, As your business grows bigger, setting up and configuring things like servers, databases, and networks becomes a real pain if you do it by hand. Spinning up new servers one by one, copying and pasting commands, and keeping track of everything is super time-consuming and mistakes happen easily. Keeping all your servers configured the same way, installing updates, and deploying new code versions is a nightmare without help.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s where tools like Terraform and Ansible come to the rescue. Terraform is awesome at setting up your infrastructure like servers, networks, and databases. Instead of doing everything manually, you write code that describes what you want, and Terraform handles it for you. Need 10 new servers? Terraform gets it done with just a few commands.&lt;/p&gt;
&lt;p&gt;Ansible is the superhero for configuring those servers. You create instructions called playbooks that tell Ansible how to set up each server. Install software? Check. Deploy your code? Check. Update everything? Easy peasy. Ansible makes sure all your servers are configured consistently.&lt;/p&gt;
&lt;p&gt;But it gets even better! With Terraform and Ansible, you have your entire infrastructure and configurations defined as code. This makes it super easy to see what changed, roll back to an earlier version if needed, and prove you&amp;rsquo;re following regulations.&lt;/p&gt;
&lt;aside class="callout callout-info"&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;h2 id="6-reasons-why-do-we-need-infrastructure-automation-and-configuration-management-iac-tools"&gt;6 Reasons: Why Do We Need Infrastructure Automation and Configuration Management (IaC) Tools?&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Eliminating Manual Errors&lt;/li&gt;
&lt;li&gt;Increasing Speed and Efficiency&lt;/li&gt;
&lt;li&gt;Ensuring Consistency and Standardization&lt;/li&gt;
&lt;li&gt;Improving Security and Compliance&lt;/li&gt;
&lt;li&gt;Facilitating Collaboration and Version Control&lt;/li&gt;
&lt;li&gt;Simplifying Disaster Recovery and Rollbacks&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Infrastructure automation refers to the process of using software tools and scripts to automate the provisioning, configuration, and management of &lt;a href="/bare-metal-vs-virtual-machines-vs-containers/" target="_blank" rel="noopener"&gt;IT infrastructure resources, such as virtual machines&lt;/a&gt;
, &lt;a href="/tag/network/" target="_blank" rel="noopener"&gt;networks&lt;/a&gt;
, &lt;a href="/load-balancer-vs-api-gateway-use-cases/" target="_blank" rel="noopener"&gt;load balancers&lt;/a&gt;
, and &lt;a href="/in-memory-caching-vs-in-memory-data-store/" target="_blank" rel="noopener"&gt;storage systems&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Configuration management is the practice of maintaining the desired state and configuration of IT systems and services throughout their lifecycle. It involves tracking, managing, and updating the configuration items (CIs) that make up an IT system, such as software, hardware, and network devices.&lt;/p&gt;
&lt;a class="bookmark" href="/migrating-aws-cloud-bare-metal-servers/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/12/Migrating-Away-from-AWS-to-Bare-Metal-Servers.png" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;How Companies Are Saving Millions by Migrating Away from AWS to Bare Metal Servers?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Many startups initially launch on AWS or other public clouds because it allows rapid scaling without upfront investments. But as these companies grow, the operating costs steadily rise.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="terraform-the-infrastructure-provisioning-tool"&gt;Terraform: The Infrastructure Provisioning Tool&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.terraform.io/use-cases/infrastructure-as-code" target="_blank" rel="noopener noreferrer"&gt;Terraform is a declarative infrastructure provisioning&lt;/a&gt;
tool that shines when it comes to spinning up resources across multiple cloud providers.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Terraform&amp;rsquo;s strengths lie in:&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="1-declarative-approach"&gt;1. Declarative Approach&lt;/h3&gt;
&lt;p&gt;Terraform&amp;rsquo;s declarative nature means you define your desired infrastructure state, and it figures out the necessary steps to achieve that state. This approach simplifies complex provisioning scenarios and ensures consistent, repeatable deployments.&lt;/p&gt;
&lt;h3 id="2-state-management-and-lifecycle-management"&gt;2. State Management and Lifecycle Management&lt;/h3&gt;
&lt;p&gt;Terraform maintains a state file that tracks the resources it has provisioned. This state file enables seamless lifecycle management, allowing you to modify or delete resources without manual intervention. If you remove a resource from your configuration, Terraform will automatically delete it during the next application.&lt;/p&gt;
&lt;h3 id="3-idempotency"&gt;3. Idempotency&lt;/h3&gt;
&lt;p&gt;Terraform is idempotent, meaning you can run it multiple times without unintended changes to your infrastructure. If no changes are required, Terraform won&amp;rsquo;t perform any actions, saving you time and effort.&lt;/p&gt;
&lt;a class="bookmark" href="/devops-vs-sre-vs-platform-engineering/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/11/DevOps-vs-SRE-vs-Platform-Engineering.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;DevOps vs SRE vs Platform Engineering - Explained&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;At small companies, engineers often wear multiple hats, juggling a mix of responsibilities. Large companies have specialized teams with clearly defined roles in DevOps, SRE, and Platform Engineering.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="ansible-the-configuration-management-tool"&gt;Ansible: The Configuration Management Tool&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.ansible.com/how-ansible-works/" target="_blank" rel="noopener noreferrer"&gt;Ansible is a powerful configuration management tool&lt;/a&gt;
that excels at automating application deployments, system configurations, and ongoing maintenance tasks.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ansible strengths are:&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="1-hybrid-approach"&gt;1. Hybrid Approach&lt;/h3&gt;
&lt;p&gt;Ansible combines declarative resources with procedural execution, providing a flexible approach to configuration management. While resources are defined in a declarative manner, they are executed procedurally.&lt;/p&gt;
&lt;h3 id="2-application-deployment"&gt;2. Application Deployment&lt;/h3&gt;
&lt;p&gt;Ansible simplifies the process of deploying applications by automating tasks like installing dependencies, copying files, and starting services.&lt;/p&gt;
&lt;h3 id="3-agentless"&gt;3. Agentless&lt;/h3&gt;
&lt;p&gt;Unlike some other configuration management tools, Ansible doesn&amp;rsquo;t require an agent to be installed on the managed nodes. This agentless architecture makes it easy to manage diverse environments without additional overhead.&lt;/p&gt;
&lt;a class="bookmark" href="/system-design-vs-software-architecture/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/07/System-Design-vs-Software-Architecture.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;System Design vs Software Architecture : What You Need to Know&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;System design and software architecture are two sides of same coin, both integral to the process of creating a software system. But, they’re not the same thing.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="ansible-vs-terraform"&gt;Ansible vs Terraform&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/04/mermaid-diagram-2024-04-02-192952.png" alt="Ansible vs Terraform"&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Category&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Ansible&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Terraform&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary Focus&lt;/td&gt;
&lt;td&gt;Configuration management, application deployment, orchestration&lt;/td&gt;
&lt;td&gt;Infrastructure as Code (IaC)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Language&lt;/td&gt;
&lt;td&gt;YAML (Playbooks)&lt;/td&gt;
&lt;td&gt;HCL (Configuration files)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent&lt;/td&gt;
&lt;td&gt;Agentless (connects via SSH)&lt;/td&gt;
&lt;td&gt;Agent-based (Terraform agent)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resource Management&lt;/td&gt;
&lt;td&gt;Manages existing resources&lt;/td&gt;
&lt;td&gt;Creates and manages resources&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change Handling&lt;/td&gt;
&lt;td&gt;Idempotent; handles changes in config&lt;/td&gt;
&lt;td&gt;Versioning and drift detection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Providers&lt;/td&gt;
&lt;td&gt;Limited to supported modules&lt;/td&gt;
&lt;td&gt;Extensive list of providers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud Support&lt;/td&gt;
&lt;td&gt;Good cloud support&lt;/td&gt;
&lt;td&gt;Excellent cloud support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use Cases&lt;/td&gt;
&lt;td&gt;Application Deployment, Configuration Management, Orchestration&lt;/td&gt;
&lt;td&gt;Infrastructure Provisioning, Resource Management&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;a class="bookmark" href="/difference-between-snapshot-image-ec2/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/04/What-is-the-Difference-Between-Snapshot---Image-in-AWS-EC2----Thumbnail.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;What is the Difference Between Snapshot &amp;amp; Image in AWS EC2?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Differentiating between ‘Snapshot’ and ‘Image’: their purposes for backups and launching instances on AWS EC2.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="using-terraform-and-ansible-together"&gt;Using Terraform and Ansible Together&lt;/h2&gt;
&lt;p&gt;While Terraform and Ansible have distinct strengths, they can work together seamlessly to provide a complete infrastructure automation solution.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/04/mermaid-diagram-2024-04-02-194424.png" alt="Terraform and Ansible Working Flowchart"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Here are two common approaches:&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="first-approach-start-with-terraform-for-provisioning-then-use-ansible-for-configuration-management"&gt;First Approach: Start with Terraform for Provisioning, then Use Ansible for Configuration Management&lt;/h3&gt;
&lt;p&gt;In this approach, you begin by defining your infrastructure resources using Terraform. Once the provisioning is complete, you can invoke Ansible from within your Terraform configuration to handle configuration management tasks on the newly created resources.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Terraform configuration
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;resource &amp;#34;aws_instance&amp;#34; &amp;#34;web_server&amp;#34; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; # ... instance details ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; provisioner &amp;#34;local-exec&amp;#34; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; command = &amp;#34;ansible-playbook -i &amp;#39;${aws_instance.web_server.public_ip},&amp;#39; playbook.yml&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="second-approach-start-with-ansible-and-call-terraform-for-initial-provisioning"&gt;Second Approach: Start with Ansible and Call Terraform for Initial Provisioning&lt;/h3&gt;
&lt;p&gt;Alternatively, you can start with an Ansible playbook and call Terraform from within it to handle the initial infrastructure provisioning. Once the resources are ready, Ansible can take over and manage their configuration.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Ansible playbook&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &lt;span class="nt"&gt;hosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;localhost&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Provision infrastructure with Terraform&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;terraform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;project_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/path/to/terraform/project&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;present&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Configure provisioned resources&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# ... configuration management tasks ...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;a class="bookmark" href="/load-balancer-vs-api-gateway-use-cases/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/06/Load-Balancer-vs.-API-Gateway---Blog-Post-Thumbnail-1.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;What Makes Load Balancer vs. API Gateway Different and Use Cases ?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Discover the key distinctions between Load Balancer and API Gateway, along with their unique use cases like efficient traffic distribution &amp;amp; integration.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="example-setting-up-a-jenkins-environment-using-terraform-and-ansible"&gt;Example: Setting up a Jenkins Environment Using Terraform and Ansible&lt;/h2&gt;
&lt;p&gt;Now, let&amp;rsquo;s put our knowledge into action by setting up a &lt;a href="/kubernetes-vs-docker-vs-jenkins/" target="_blank" rel="noopener"&gt;Jenkins environment&lt;/a&gt;
using Terraform and Ansible.&lt;/p&gt;
&lt;h3 id="1-terraform-for-provisioning-an-ec2-instance-on-aws"&gt;1. Terraform for Provisioning an EC2 Instance on AWS&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;aws&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;aws_vpc&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;main&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# ... VPC configuration ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;aws_instance&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;jenkins&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ami&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;aws_ami&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ubuntu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instance_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instance_type&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# ... other instance details ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;region&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;us-east-1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;instance_type&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;t2.micro&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;a href="/deploy-create-ec2-instance-using-terraform/" target="_blank" rel="noopener"&gt;&lt;strong&gt;How to Create &amp;amp; Deploy EC2 Instance Using Terraform?&lt;/strong&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="2-ansible-for-deploying-docker-and-running-jenkins-container"&gt;2. Ansible for Deploying Docker and Running Jenkins Container&lt;/h3&gt;
&lt;p&gt;Once the EC2 instance is provisioned, Ansible takes over to deploy &lt;a href="/kubernetes-vs-docker-swarm/" target="_blank" rel="noopener"&gt;Docker and run the Jenkins container&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what the Ansible playbook looks like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &lt;span class="nt"&gt;hosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jenkins_hosts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;become&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;yes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Install prerequisites&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;apt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;apt-transport-https&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;ca-certificates&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;curl&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;software-properties-common&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Add Docker GPG key&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;apt_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;https://download.docker.com/linux/ubuntu/gpg&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;present&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# ... additional tasks to install Docker ...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Pull Jenkins Docker image&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;docker_image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jenkins/jenkins:lts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pull&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Run Jenkins container&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;docker_container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jenkins&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jenkins/jenkins:lts&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;8080:8080&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We start by defining our infrastructure resources using Terraform. Then, we run &lt;code&gt;terraform apply&lt;/code&gt; to provision the required resources. Once the infrastructure is provisioned, we invoke an Ansible playbook to configure and manage the resources as needed.&lt;/p&gt;
&lt;p&gt;Terraform and Ansible are not competitors; they are complementary tools that, when used together, can unlock the full potential of infrastructure automation.&lt;/p&gt;
&lt;a class="bookmark" href="/deploy-create-ec2-instance-using-terraform/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/06/Create---Deploy-EC2-Instance-Using-Terraform.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;How to Create &amp;amp; Deploy EC2 Instance Using Terraform?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Learn how to create and deploy AWS EC2 instances using Terraform for efficient cloud infrastructure management.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;</content></entry><entry><title>Self-Host Open-Source Slash Link Shortener on Docker</title><link href="https://firstfinger.io/slash-link-shortener-docker/"/><id>https://firstfinger.io/slash-link-shortener-docker/</id><updated>2024-04-02T06:33:50Z</updated><published>2024-04-02T06:17:50Z</published><author><name>Anurag Vishwakarma</name></author><category term="Self Host"/><category term="Cloud"/><category term="Container"/><category term="How to"/><summary>Slash, the open-source link shortener. Create custom short links, organize them with tags, share them with your team, and track analytics while maintaining data privacy.</summary><content type="html">&lt;p&gt;Sharing links is an integral part of our daily online communication. However, dealing with long, complex URLs can be a hassle, making remembering and sharing links efficiently difficult.&lt;/p&gt;
&lt;h2 id="what-is-slash"&gt;What is Slash?&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://github.com/yourselfhosted/slash/blob/main/docs/assets/demo.png?raw=true"
alt="Slash Link Shortener Dashboard"&gt;&lt;figcaption&gt;
&lt;p&gt;Slash Link Shortener Dashboard&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href="https://github.com/yourselfhosted/slash" target="_blank" rel="noopener noreferrer"&gt;Slash is an open-source, self-hosted link shortener&lt;/a&gt;
that simplifies the managing and sharing of links. Slash allows you to create customizable, shortened URLs (called &amp;ldquo;shortcuts&amp;rdquo;) for any website or online resource. With Slash, you can say goodbye to the chaos of managing lengthy links and embrace a more organized and streamlined approach to sharing information online.&lt;/p&gt;
&lt;p&gt;One of the great things about Slash is that it can be self-hosted using Docker. By self-hosting Slash, you have complete control over your data.&lt;/p&gt;
&lt;h3 id="features-of-slash"&gt;Features of Slash:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Custom Shortcuts&lt;/strong&gt;: Transform any URL into a concise, memorable shortcut for easy sharing and access.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tag Organization&lt;/strong&gt;: Categorize your shortcuts using tags for efficient sorting and retrieval.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Team Sharing&lt;/strong&gt;: Collaborate by sharing shortcuts with your team members.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Link Analytics&lt;/strong&gt;: Track link traffic and sources to understand usage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Browser Extension&lt;/strong&gt;: Access shortcuts directly from your browser&amp;rsquo;s address bar on Chrome &amp;amp; Firefox.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collections&lt;/strong&gt;: Group related shortcuts into collections for better organization.&lt;/li&gt;
&lt;/ol&gt;
&lt;aside class="callout callout-info"&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;a class="bookmark" href="/wordpress-mysql-redis-nginx/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2024/03/WordPress-with-MySQL--Redis--and-NGINX-on-Docker.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Deploying WordPress with MySQL, Redis, and NGINX on Docker&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Set up WordPress with a MySQL database and Redis as an object cache on Docker with an NGINX Reverse Proxy for blazing-fast performance.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h2 id="setup-slash-link-shortner-with-docker"&gt;Setup Slash Link Shortner with Docker&lt;/h2&gt;
&lt;p&gt;Follow the simple steps to get Slash up and running on your server or local machine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/kubernetes-vs-docker-swarm/" target="_blank" rel="noopener"&gt;Basic knowledge of Docker&lt;/a&gt;
and Docker Compose&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/engine/install/" target="_blank" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;
&amp;amp; &lt;a href="https://docs.docker.com/compose/install/linux/" target="_blank" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt;
installed on your machine&lt;/li&gt;
&lt;li&gt;A domain name or IP address pointing to your server&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="method-1-docker-run-cli"&gt;Method 1: Docker Run CLI&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;docker run&lt;/code&gt; command is used to create and start a new Docker container. To deploy Slash, run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run -d --name slash -p 5231:5231 -v ~/.slash/:/var/opt/slash yourselfhosted/slash:latest
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s break down what this command does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker run&lt;/code&gt; tells Docker to create and start a new container&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; runs the container in detached mode (in the background)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--name slash&lt;/code&gt; gives the container the name &amp;ldquo;slash&amp;rdquo; for easy reference&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p 5231:5231&lt;/code&gt; maps the container&amp;rsquo;s port 5231 to the host&amp;rsquo;s port 5231, allowing access to Slash from your browser&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v ~/.slash/:/var/opt/slash&lt;/code&gt; creates a volume to store Slash&amp;rsquo;s persistent data on your host machine&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yourselfhosted/slash:latest&lt;/code&gt; specifies the Docker image to use (the latest version of Slash)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After running this command, your Slash instance will be accessible at &lt;code&gt;http://your-server-ip:5231&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="method-2-docker-compose"&gt;Method 2: Docker Compose&lt;/h2&gt;
&lt;p&gt;Docker Compose is a tool that simplifies defining and running multi-container Docker applications. It uses a YAML file to configure the application&amp;rsquo;s services.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a new file named &lt;code&gt;docker-compose.yml&lt;/code&gt; and paste the contents of the Docker Compose file provided below.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;3&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;slash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;yourselfhosted/slash:latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;slash&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="m"&gt;5231&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;5231&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;slash:/var/opt/slash&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;slash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Start Slash using the Docker Compose command:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This command will pull the required Docker images and start the Slash container in the background.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;After running this command, your Slash container will be accessible at &lt;code&gt;http://your-server-ip:5231&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Slash is ready &amp;amp; allows you to create, manage, and share shortened URLs without relying on third-party services or compromising your data privacy.&lt;/p&gt;
&lt;a class="bookmark" href="/memos-mysql-s3/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2024/03/Memos-Note-Taking-App-1.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Setup Memos Note-Taking App with MySQL on Docker &amp;amp; S3 Storage&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Self-host the open-source, privacy-focused note-taking app Memos using Docker with a MySQL database and integrate with S3 or Cloudflare R2 object storage.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h2 id="benefits-of-self-hosting-slash-link-shortener"&gt;Benefits of Self-Hosting Slash Link Shortener&lt;/h2&gt;
&lt;p&gt;By self-hosting you gain several advantages:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Data Privacy&lt;/strong&gt;: Keep your data and links secure within your infrastructure, ensuring complete control over your information.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Customization&lt;/strong&gt;: Tailor Slash to your specific needs, such as branding, integrations, or additional features.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost-Effective&lt;/strong&gt;: Eliminate recurring subscription fees associated with third-party link-shortening services.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: Scale your Slash instance according to your requirements, ensuring optimal performance as your link management needs to grow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Slash offers a seamless solution for managing and sharing links, empowering individuals and teams to streamline their digital workflows.&lt;/p&gt;
&lt;a class="bookmark" href="/reduce-energy-costs-homelab-server/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/11/5-Ways-to-Reduce-Costs-on-Your-HomeLab-Server.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;13 Tips to Reduce Energy Costs on Your HomeLab Server&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;HomeLabs can be expensive when it comes to energy costs. It’s easy to accumulate multiple power-hungry servers, networking equipment, and computers.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="other-open-source-link-shorteners"&gt;Other Open-Source Link Shorteners&lt;/h2&gt;
&lt;a class="bookmark" href="https://shlink.io/"&gt;
&lt;img class="bookmark-thumb" src="https://shlink.io/images/shlink-logo-blue.svg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Shlink — The URL shortener&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;The self-hosted and PHP-based URL shortener application with CLI and REST interfaces&lt;/p&gt;
&lt;span class="bookmark-host"&gt;Shlink&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://docs.blink.rest/"&gt;
&lt;img class="bookmark-thumb" src="https://circleci.com/gh/JaneJeon/blink.svg?style=shield" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;1.1 About | Blink&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;CircleCI&lt;/p&gt;
&lt;span class="bookmark-host"&gt;Blink&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://github.com/SinTan1729/chhoto-url"&gt;
&lt;img class="bookmark-thumb" src="https://opengraph.githubassets.com/8049d473cc7ce235a59fee998af647ec801bd32de55a20ffaf79c061f11ed584/SinTan1729/chhoto-url" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;GitHub - SinTan1729/chhoto-url: A simple, lightning-fast, selfhosted URL shortener with no unnecessary features; written in Rust.&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;A simple, lightning-fast, selfhosted URL shortener with no unnecessary features; written in Rust. - SinTan1729/chhoto-url&lt;/p&gt;
&lt;span class="bookmark-host"&gt;GitHub · SinTan1729&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://github.com/easypanel-community/easyshortener"&gt;
&lt;img class="bookmark-thumb" src="https://opengraph.githubassets.com/4ed01eebfd4256f00e3488c6a1a629a59b618a28db8fbe016c135212be9fca72/Easypanel-Community/easyshortener" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;GitHub - Easypanel-Community/easyshortener: A simple URL shortener created with Laravel 10&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;A simple URL shortener created with Laravel 10. Contribute to Easypanel-Community/easyshortener development by creating an account on GitHub.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;GitHub · Easypanel-Community&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://github.com/miawinter98/just-short-it"&gt;
&lt;img class="bookmark-thumb" src="https://opengraph.githubassets.com/d4e97d12ffbc20512d30309c3732a98bf0c6dd766df2742107edeeba785bedbc/miawinter98/just-short-it" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;GitHub - miawinter98/just-short-it: Just Short It (damnit)! The most KISS single-user URL shortener there is.&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Just Short It (damnit)! The most KISS single-user URL shortener there is. - GitHub - miawinter98/just-short-it: Just Short It (damnit)! The most KISS single-user URL shortener there is.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;GitHub · miawinter98&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://git.ikl.sh/132ikl/liteshort"&gt;
&lt;img class="bookmark-thumb" src="https://git.ikl.sh/avatars/36707e48a3d1bfd6b664b5c530cee607" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;liteshort&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;User-friendly, actually lightweight, and configurable URL shortener&lt;/p&gt;
&lt;span class="bookmark-host"&gt;cool repos · 132ikl&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://github.com/ldidry/lstu"&gt;
&lt;img class="bookmark-thumb" src="https://opengraph.githubassets.com/ed4c07cfcefe1fb181f995bd37863d680359c638517c917e266d62282e82cd1c/ldidry/lstu" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;GitHub - ldidry/lstu: Lightweight URL shortener. Read-only mirror of https://framagit.org/fiat-tux/hat-softwares/lstu&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Lightweight URL shortener. Read-only mirror of https://framagit.org/fiat-tux/hat-softwares/lstu - ldidry/lstu&lt;/p&gt;
&lt;span class="bookmark-host"&gt;GitHub · ldidry&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://getlynx.dev/"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Lynx&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;The sleek, powerful URL shortener you’ve been looking for.&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://github.com/hossainalhaidari/pastr"&gt;
&lt;img class="bookmark-thumb" src="https://opengraph.githubassets.com/e462c5b33b11471953251de969016c9fdab2e1f105065d4c82c93bb1dd6a0a8c/hossainalhaidari/pastr" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;GitHub - hossainalhaidari/pastr: Minimal URL shortener and paste tool&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Minimal URL shortener and paste tool. Contribute to hossainalhaidari/pastr development by creating an account on GitHub.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;GitHub · hossainalhaidari&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://github.com/azlux/Simple-URL-Shortener"&gt;
&lt;img class="bookmark-thumb" src="https://opengraph.githubassets.com/78d124f920f4ffa6f68c30ccd01835c789248a99171cc59ac193f0c50529c189/azlux/Simple-URL-Shortener" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;GitHub - azlux/Simple-URL-Shortener: url shortener written in php (with MySQL or SQLite) with history by users&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;url shortener written in php (with MySQL or SQLite) with history by users - azlux/Simple-URL-Shortener&lt;/p&gt;
&lt;span class="bookmark-host"&gt;GitHub · azlux&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://gitlab.com/draganczukp/simply-shorten"&gt;
&lt;img class="bookmark-thumb" src="https://gitlab.com/assets/twitter_card-570ddb06edf56a2312253c5872489847a0f385112ddbcd71ccfa1570febab5d2.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Przemek Dragańczuk / simply-shorten · GitLab&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;GitLab.com&lt;/p&gt;
&lt;span class="bookmark-host"&gt;GitLab&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="https://yourls.org/"&gt;
&lt;img class="bookmark-thumb" src="https://yourls.org/assets/images/splash.png" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;YOURLS | YOURLS&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Your Own URL Shortener&lt;/p&gt;
&lt;span class="bookmark-host"&gt;YOURLS&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;</content></entry><entry><title>Deploying WordPress with MySQL, Redis, and NGINX on Docker</title><link href="https://firstfinger.io/wordpress-mysql-redis-nginx/"/><id>https://firstfinger.io/wordpress-mysql-redis-nginx/</id><updated>2024-03-27T17:06:34Z</updated><published>2024-03-27T11:53:41Z</published><author><name>Anurag Vishwakarma</name></author><category term="Self Host"/><category term="WordPress"/><category term="Cloud"/><category term="Container"/><category term="Database"/><category term="How to"/><category term="Linux"/><summary>Set up WordPress with a MySQL database and Redis as an object cache on Docker with an NGINX Reverse Proxy for blazing-fast performance.</summary><content type="html">&lt;p&gt;WordPress is a popular content management system (CMS) that powers millions of websites worldwide. However, as your website grows, you may experience performance issues. To improve WordPress performance, you can use object caching, which stores frequently accessed data in memory, reducing the number of database queries.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/kubernetes-vs-docker-swarm/" target="_blank" rel="noopener"&gt;Basic knowledge of Docker&lt;/a&gt;
and Docker Compose&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/engine/install/" target="_blank" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;
&amp;amp; &lt;a href="https://docs.docker.com/compose/install/linux/" target="_blank" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt;
installed on your machine&lt;/li&gt;
&lt;li&gt;A domain name or IP address pointing to your server&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-do-we-need-better-performance-in-wordpress"&gt;Why do we need better performance in WordPress?&lt;/h2&gt;
&lt;p&gt;Website performance is crucial for user experience and search engine optimization (SEO). A slow website can lead to a high bounce rate, meaning visitors leave your site without interacting. Additionally, search engines like Google consider website speed as a ranking factor.&lt;/p&gt;
&lt;h2 id="what-does-object-cache-do-in-wordpress"&gt;What does Object Cache do in WordPress?&lt;/h2&gt;
&lt;p&gt;WordPress, by default, caches internal application objects like breadcrumbs and menu items in the MySQL database. This can be taxing since the database also handles queries for page requests, potentially increasing website load times.&lt;/p&gt;
&lt;p&gt;&lt;a href="/why-redis-is-fast/" target="_blank" rel="noopener"&gt;Object caching is a technique used to store frequently accessed data in memory, reducing the number of database queries.&lt;/a&gt;
In WordPress, object caching is disabled by default. When a user requests a page, if the data is already cached in Redis, it is served directly from the cache, bypassing the database. This significantly reduces response times and &lt;a href="/self-hosting-vs-managed-hosting-wordpress/" target="_blank" rel="noopener"&gt;improves the overall performance of your WordPress site&lt;/a&gt;
.&lt;/p&gt;
&lt;a class="bookmark" href="/in-memory-caching-vs-in-memory-data-store/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2024/01/In-Memory-Caching-vs.-In-Memory-Data-Store.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;In-Memory Caching vs. In-Memory Data Store&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;In-memory caching and in-memory data storage are both techniques used to improve the performance of applications by storing frequently accessed data in memory. However, they differ in their approach and purpose.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h2 id="why-use-redis-for-object-caching"&gt;Why Use Redis for Object Caching?&lt;/h2&gt;
&lt;p&gt;Redis is an open-source, &lt;a href="/in-memory-caching-vs-in-memory-data-store/" target="_blank" rel="noopener"&gt;in-memory data store that can be used as a database&lt;/a&gt;
, cache, and message broker.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compared to alternatives like Memcached, Redis offers:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Persistent data storage&lt;/li&gt;
&lt;li&gt;Data replication and high availability&lt;/li&gt;
&lt;li&gt;Richer data structures like lists, hashes, and sets&lt;/li&gt;
&lt;li&gt;Better performance for WordPress object caching&lt;/li&gt;
&lt;/ul&gt;
&lt;a class="bookmark" href="/why-redis-is-fast/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/02/Why-Redis-is-So-Fast--1.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Why Redis is So Fast It Will Blow Your Mind!&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Find out Why Redis is so fast, even after over a decade since its creation.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h2 id="wordpress-with-mysql-database-and-redis-as-object-cache-with-nginx-reverse-proxy-on-docker"&gt;WordPress with MySQL Database and Redis as Object Cache with NGINX Reverse Proxy on Docker&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ll use Docker Compose to orchestrate a multi-container setup&lt;/p&gt;
&lt;h2 id="step-1-create-a-docker-compose-file"&gt;Step 1: Create a Docker Compose file&lt;/h2&gt;
&lt;p&gt;Create a new file named &lt;code&gt;docker-compose.yml&lt;/code&gt; in your project directory and add the following code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;3&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;wordpress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;wordpress:latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;8080:80&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Change port&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;always&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;WORDPRESS_DB_HOST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;db&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;WORDPRESS_DB_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;exampleuser&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;WORDPRESS_DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;examplepassword&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;WORDPRESS_DB_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;exampledb&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;wordpress:/var/www/html&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;db&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;redis&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mysql:8.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;always&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;exampledb&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;exampleuser&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;examplepassword&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;rootpassword&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;db:/var/lib/mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;redis:alpine&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;always&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;wordpress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;This Docker Compose file creates three services: &lt;code&gt;WordPress&lt;/code&gt;, &lt;code&gt;MySQL&lt;/code&gt;, and &lt;code&gt;Redis&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The WordPress service uses the latest WordPress image and connects to the MySQL service using the environment variables defined in the file.&lt;/li&gt;
&lt;li&gt;The MySQL service uses version 8.0 of the MySQL image, and the Redis service uses the Redis Alpine image.&lt;/li&gt;
&lt;li&gt;The WordPress data is persisted in the &lt;code&gt;wordpress&lt;/code&gt; directory for easy access.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;docker-compose up -d&lt;/code&gt; to start the containers.&lt;/li&gt;
&lt;li&gt;You can access your WordPress site by visiting the URL &lt;code&gt;http://your-server-ip:8080&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;aside class="callout callout-info"&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;a class="bookmark" href="/kubernetes-vs-docker-swarm/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/08/Top-Container-Orchestration-Platforms-Compared-Kubernetes-vs.-Docker-Swarm.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Top Container Orchestration Platforms: Kubernetes vs. Docker Swarm&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Kubernetes and Docker Swarm are both open-source container orchestration platforms that automate container deployment, scaling, and management.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="step-2-accessing-the-wordpress-container-shell"&gt;Step 2: Accessing the WordPress Container Shell&lt;/h2&gt;
&lt;p&gt;To edit the changes in the WordPress config file we need to access the container shell, to do that follow:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/03/006221cd217fd6a7b7c08fe26ef51f6c.png" alt="WordPress Files Directory in Running Docker Container"&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;docker ps&lt;/code&gt; to see running container details such as name, ID, status etc, and get WordPress container ID.&lt;/li&gt;
&lt;li&gt;Use the command &lt;code&gt;docker exec -it &amp;lt;container_id&amp;gt; /bin/bash&lt;/code&gt; to access the WordPress container.&lt;/li&gt;
&lt;li&gt;Run this command in the WordPress container shell: &lt;code&gt;apt update &amp;amp;&amp;amp; apt upgrade -y &amp;amp;&amp;amp; apt install nano&lt;/code&gt;. This command will update the system packages and install the &lt;strong&gt;Nano text editor&lt;/strong&gt; in the shell.&lt;/li&gt;
&lt;/ol&gt;
&lt;a class="bookmark" href="/what-is-kubernetes/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/12/What-is-Kubernetes-4.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Kubernetes for Noobs&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Kubernetes is an open-source system that helps with deploying, scaling, and managing containerized applications.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="step-3-add-redis-configuration-to-wp-configphp"&gt;Step 3: Add Redis Configuration to wp-config.php&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Now run &lt;code&gt;nano wp-config.php&lt;/code&gt; to edit the code in the WordPress container shell &amp;amp; add the following code on top of the code in wp-config.php&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/03/a391095eaf0ce204e148c77f5670ddb4.png" alt="WordPress wp-config.php File"&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;define&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;WP_CACHE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Add the following lines to enable Redis object caching:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/03/dc9c4bc64ffde63a3873c5ce97a93595.png" alt="WordPress wp-config.php with Redis Object Cache"&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;WP_REDIS_HOST&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;redis&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;WP_REDIS_PORT&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;6379&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;WP_CACHE_KEY_SALT&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;your-domain-name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Replace &lt;code&gt;your-domain-name&lt;/code&gt; with your actual &lt;code&gt;domain name&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Confirm &amp;amp; press &lt;code&gt;Ctrl + X&lt;/code&gt; then &lt;code&gt;Shift + Y&lt;/code&gt; to save the changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="step-4-install-the-redis-object-cache-plugin"&gt;Step 4: Install the Redis Object Cache Plugin&lt;/h2&gt;
&lt;p&gt;To enable object caching in WordPress, you need to install and activate the Redis Object Cache plugin.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/03/6820c1351e5bbae87ca9232a1cb986b1.png" alt="Redis Object Cache Plugin"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/03/a2fc23ebdb35e7ce5eb0469598c6dc27.png" alt="Redis Object Cache Plugin Settings in WorePress Dashboard"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/03/c999b3a4300c8a33bbf7ffaa187c5849.png" alt="WordPress Site Health Status"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/03/d4dffb4689c2965e4ff86b6ef1427982.png" alt="Redis Object Cache Performance in WordPress"&gt;&lt;/p&gt;
&lt;h2 id="step-5--run-nginx-reverse-proxy-manager-container"&gt;Step 5: Run NGINX Reverse Proxy Manager Container&lt;/h2&gt;
&lt;p&gt;The reverse proxy acts as a gateway, routing external traffic to your Docker containers while providing additional features like SSL termination, load balancing, and caching, making it easier to manage and secure your containerized applications.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;3.8&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;jc21/nginx-proxy-manager:latest&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;80:80&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;81:81&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;443:443&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./data:/data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./letsencrypt:/etc/letsencrypt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;aside class="callout callout-info"&gt;
&lt;div class="callout-body"&gt;&lt;strong&gt;OR&lt;/strong&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;3.8&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;jc21/nginx-proxy-manager:latest&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;80:80&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;443:443&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;81:81&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;DB_MYSQL_HOST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;db&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;DB_MYSQL_PORT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3306&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;DB_MYSQL_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;npm&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;DB_MYSQL_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;npm&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;DB_MYSQL_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;npm&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./data:/data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./letsencrypt:/etc/letsencrypt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;db&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;jc21/mariadb-aria:latest&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;npm&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;npm&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;npm&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;npm&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MARIADB_AUTO_UPGRADE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./mysql:/var/lib/mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;aside class="callout callout-info"&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;ol&gt;
&lt;li&gt;Save the above content to a file named &lt;code&gt;docker-compose.yml&lt;/code&gt; in a new directory.&lt;/li&gt;
&lt;li&gt;Open a terminal, navigate to the directory with the &lt;code&gt;docker-compose.yml&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;docker-compose up -d&lt;/code&gt; to start the containers in detached mode.&lt;/li&gt;
&lt;li&gt;Let&amp;rsquo;s Encrypt SSL certificates are stored in &lt;code&gt;./letsencrypt&lt;/code&gt; the directory.&lt;/li&gt;
&lt;li&gt;Access the &lt;a href="https://nginxproxymanager.com/" target="_blank" rel="noopener noreferrer"&gt;Nginx Proxy Manager&lt;/a&gt;
GUI admin interface at &lt;code&gt;http://your_server_ip:81&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Default Admin Login :&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Email: admin@example.com
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Password: changeme
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;a class="bookmark" href="/forward-proxy-vs-reverse-proxy/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/What-is-the-difference-between-Forward-Proxy-vs-Reverse-Proxy-.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;What is the difference between Forward Proxy vs Reverse Proxy?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Understand, The role that proxies play in web architecture and consider using them to improve the performance, security, and scalability of your site.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h2 id="step-6--setting-up-wordpress-with-nginx-reverse-proxy"&gt;Step 6: Setting up WordPress with NGINX Reverse Proxy&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/03/image-6.png" alt="NGINX Proxy Manager "&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click on &amp;ldquo;Hosts&amp;rdquo; &amp;gt; &amp;ldquo;Add Proxy Host&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Enter the following details:&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Domain Names&lt;/strong&gt;: Enter your WordPress site&amp;rsquo;s domain name (e.g., example.com)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scheme&lt;/strong&gt;: Choose &amp;ldquo;http://&amp;rdquo; unless you have a valid SSL certificate for your domain&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Forward Hostname / IP&lt;/strong&gt;: Enter the IP address of your WordPress container (e.g., 172.17.0.3)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Forward Port&lt;/strong&gt;: Enter the port your WordPress container is listening on (usually 80)&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="4"&gt;
&lt;li&gt;Click on &amp;ldquo;Save&amp;rdquo; to create the proxy host&lt;/li&gt;
&lt;li&gt;If you want to &lt;strong&gt;enable SSL&lt;/strong&gt; with a Let&amp;rsquo;s Encrypt certificate:&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Click on the proxy host you just created&lt;/li&gt;
&lt;li&gt;Go to the &amp;ldquo;SSL&amp;rdquo; tab section&lt;/li&gt;
&lt;li&gt;Check the &amp;ldquo;Force SSL&amp;rdquo; &amp;amp; &amp;ldquo;HTTP/2&amp;rdquo; box&lt;/li&gt;
&lt;li&gt;Choose &amp;ldquo;Request a new SSL Certificate&amp;rdquo; by entering a valid email then save.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="7"&gt;
&lt;li&gt;Your WordPress site should now be accessible via the Nginx Proxy Manager, with a valid SSL Certificate.&lt;/li&gt;
&lt;/ol&gt;
&lt;a class="bookmark" href="/vpn-vs-zero-trust-network-remote-access/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/VPN-vs-Zero-Trust--Network.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;VPN vs. Zero Trust Network: Which is More Secure for Remote Access?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Zero trust fixes vulnerable trust models and limited visibility in VPNs by verifying all users and devices, encrypting everything, and monitoring all activity - before authorizing access.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="step-7-backing-up-wordpress-site"&gt;Step 7: Backing Up WordPress Site&lt;/h2&gt;
&lt;p&gt;To ensure data safety, it&amp;rsquo;s essential to regularly back up your WordPress site.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wordpress.org/plugins/updraftplus/" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;UpdraftPlus&lt;/strong&gt; is a popular backup plugin&lt;/a&gt;
that simplifies and automates this process. It supports backup to remote storage like Dropbox, Google Drive and affordable paid add-ons.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/03/image-7.png" alt="UpdraftPlus Backup Plugin in WordPress"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/03/image-8.png" alt="Backup WordPress Site to Cloud Storage Drives"&gt;&lt;/p&gt;
&lt;p&gt;You can take a manual backup or set automated schedules daily or after every hour.&lt;/p&gt;
&lt;p&gt;This setup provides a robust and efficient environment for your WordPress site, improving both performance and data security.&lt;/p&gt;
&lt;h2 id="10-tips-for-improving-wordpress-site-performance"&gt;10 Tips for improving WordPress site performance&lt;/h2&gt;
&lt;h3 id="1-use-a-content-delivery-network-cdn"&gt;1. Use a Content Delivery Network (CDN)&lt;/h3&gt;
&lt;p&gt;A CDN is a network of servers that delivers static content like images, videos, and CSS files from the server closest to the user&amp;rsquo;s location. By using a CDN, you can reduce the load on your server and improve website speed. Popular CDN providers include Cloudflare, Amazon CloudFront, and MaxCDN.&lt;/p&gt;
&lt;h3 id="2-enable-cloudflare-caching"&gt;2. Enable Cloudflare Caching&lt;/h3&gt;
&lt;p&gt;Cloudflare is a popular CDN and web application firewall that offers caching and performance optimization features. By enabling Cloudflare caching, you can store frequently accessed data on Cloudflare&amp;rsquo;s servers, reducing the number of requests to your server. This can significantly improve website speed and reduce server load.&lt;/p&gt;
&lt;h3 id="3-optimize-images"&gt;3. Optimize Images&lt;/h3&gt;
&lt;p&gt;Large images can slow down your website. Therefore, it&amp;rsquo;s essential to optimize images for the web by compressing them and using the correct file format. You can use image optimization plugins like WP Smush or ShortPixel to optimize images automatically. These plugins can also lazy load images, which means they only load when they&amp;rsquo;re visible on the screen.&lt;/p&gt;
&lt;h3 id="4-minimize-http-requests"&gt;4. Minimize HTTP Requests&lt;/h3&gt;
&lt;p&gt;Each file on your website, such as images, CSS, and JavaScript files, requires an HTTP request to load. By minimizing the number of HTTP requests, you can improve website speed. You can use plugins like Autoptimize to minify and combine CSS and JavaScript files, reducing the number of requests required to load your website.&lt;/p&gt;
&lt;h3 id="5-use-a-caching-plugin"&gt;5. Use a Caching Plugin&lt;/h3&gt;
&lt;p&gt;Caching plugins like W3 Total Cache or WP Super Cache can improve website speed by caching frequently accessed data and serving it from the cache instead of generating it dynamically. These plugins can also minify HTML, CSS, and JavaScript files, reducing the size of the files and improving website speed.&lt;/p&gt;
&lt;h3 id="6-enable-gzip-compression"&gt;6. Enable Gzip Compression&lt;/h3&gt;
&lt;p&gt;Gzip compression reduces the size of files sent from your server to the user&amp;rsquo;s browser, reducing the amount of data transferred and improving website speed. You can enable Gzip compression using a plugin like WP Rocket or by adding code to your .htaccess file.&lt;/p&gt;
&lt;h3 id="7-disable-unused-plugins-and-themes"&gt;7. Disable Unused Plugins and Themes&lt;/h3&gt;
&lt;p&gt;Unused plugins and themes can slow down your website and pose security risks. Therefore, it&amp;rsquo;s essential to disable and delete any plugins and themes that you&amp;rsquo;re not using. This can improve website speed and reduce security risks.&lt;/p&gt;
&lt;h3 id="8-use-a-fast-web-host"&gt;8. Use a Fast Web Host&lt;/h3&gt;
&lt;p&gt;The speed of your website depends on the speed of your web host. Therefore, it&amp;rsquo;s essential to choose a fast and reliable web host that can handle your website&amp;rsquo;s traffic. Look for a web host that offers fast load times, good uptime, and reliable customer support.&lt;/p&gt;
&lt;h3 id="9-optimize-database"&gt;9. Optimize Database&lt;/h3&gt;
&lt;p&gt;Over time, your WordPress database can become cluttered with unused data, such as post revisions, spam comments, and transient options. By optimizing your database, you can improve website speed and reduce database size. You can use plugins like WP-Optimize or WP-Sweep to optimize your database.&lt;/p&gt;
&lt;h3 id="10-use-a-lightweight-theme"&gt;10. Use a Lightweight Theme&lt;/h3&gt;
&lt;p&gt;A lightweight theme with minimal features and optimized code can improve website speed. Therefore, it&amp;rsquo;s essential to choose a lightweight theme that&amp;rsquo;s optimized for performance. Look for a theme that&amp;rsquo;s well-coded, fast-loading, and responsive.&lt;/p&gt;
&lt;p&gt;By implementing these tips, you can improve the performance of your WordPress site and provide a better user experience.&lt;/p&gt;
&lt;hr&gt;
&lt;a class="bookmark" href="/memos-mysql-s3/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2024/03/Memos-Note-Taking-App-1.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Setup Memos Note-Taking App with MySQL on Docker &amp;amp; S3 Storage&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Self-host the open-source, privacy-focused note-taking app Memos using Docker with a MySQL database and integrate with S3 or Cloudflare R2 object storage.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="/why-is-wordpress-good-for-beginners/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/02/wordpress-development-Large-2.jpeg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Why is WordPress good for beginners?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Find out why WordPress is considered one of the best options for beginners looking to build a website. Discover the benefits and limitations of this popular CMS.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;</content></entry><entry><title>Mistral 7B vs. Mixtral 8x7B</title><link href="https://firstfinger.io/mistral-7b-vs-mixtral-8x7b/"/><id>https://firstfinger.io/mistral-7b-vs-mixtral-8x7b/</id><updated>2024-03-26T07:53:03Z</updated><published>2024-03-26T07:30:46Z</published><author><name>Anurag Vishwakarma</name></author><category term="AI ML"/><summary>Two LLMs, Mistral 7B and Mixtral 8x7B from Mistral AI, outperform other models like Llama and GPT-3 across benchmarks while providing faster inference and longer context handling capabilities.</summary><content type="html">&lt;p&gt;A French startup, &lt;a href="https://mistral.ai/" target="_blank" rel="noopener noreferrer"&gt;Mistral AI has released two impressive large language models (LLMs) - Mistral 7B and Mixtral 8x7B.&lt;/a&gt;
These models push the boundaries of performance and introduce a better architectural innovation aimed at optimizing inference speed and computational efficiency.&lt;/p&gt;
&lt;h2 id="mistral-7b-small-yet-mighty"&gt;Mistral 7B: Small yet Mighty&lt;/h2&gt;
&lt;p&gt;Mistral 7B is a 7.3 billion parameter transformer model that punches above its weight class. Despite its relatively modest size,** it outperforms the 13 billion parameters Llama 2 model across all benchmarks.** It even surpasses the larger 34 billion parameter Llama 1 model on reasoning, mathematics, and code generation tasks.&lt;/p&gt;
&lt;p&gt;**Two foundations of Mistral 7B&amp;rsquo;s efficiency: **&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Grouped Query Attention (GQA)&lt;/li&gt;
&lt;li&gt;Sliding Window Attention (SWA)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;GQA&lt;/strong&gt; significantly &lt;a href="/groq-lpu/" target="_blank" rel="noopener"&gt;accelerates inference speed and reduces memory requirements during decoding&lt;/a&gt;
by sharing keys and values across multiple queries within each transformer layer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SWA&lt;/strong&gt;, on the other hand, enables the model to handle longer input sequences at a lower computational cost by introducing a configurable &amp;ldquo;&lt;strong&gt;attention window&lt;/strong&gt;&amp;rdquo; that limits the number of tokens the model attends to at any given time.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Number of parameters&lt;/th&gt;
&lt;th&gt;Number of active parameters&lt;/th&gt;
&lt;th&gt;Min. GPU RAM for inference (GB)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mistral-7B-v0.2&lt;/td&gt;
&lt;td&gt;7.3B&lt;/td&gt;
&lt;td&gt;7.3B&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mistral-8X7B-v0.1&lt;/td&gt;
&lt;td&gt;46.7B&lt;/td&gt;
&lt;td&gt;12.9B&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;a class="bookmark" href="/large-language-models-llm-explained/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/10/LLM.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;How Do (LLM) Large Language Models Work? Explained&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;A large language model (LLM) is an AI system trained on extensive text data, designed to produce human-like and intelligent responses.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="mixtral-8x7b-a-sparse-mixture-of-experts-marvel"&gt;Mixtral 8x7B: A Sparse Mixture-of-Experts Marvel&lt;/h2&gt;
&lt;p&gt;While Mistral 7B impresses with its efficiency and performance, Mistral AI took things to the next level with the release of Mixtral 8x7B, a 46.7 billion parameter sparse mixture-of-experts (MoE) model. Despite its massive size, Mixtral 8x7B leverages sparse activation, resulting in only 12.9 billion active parameters per token during inference.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/03/Mistral-Large-Bar-Plot.png"
alt="LLM Bechmark Graph"&gt;&lt;figcaption&gt;
&lt;p&gt;Image Credit: Mistral.ai&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;***The key innovation behind ***&lt;a href="https://mistral.ai/news/mixtral-of-experts/" target="_blank" rel="noopener noreferrer"&gt;&lt;em&gt;&lt;strong&gt;Mixtral 8x7B is its MoE architecture.&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt;
Within each transformer layer, the model has eight expert feed-forward networks (FFNs). For every token, a router mechanism selectively activates just two of these expert FFNs to process that token. This sparsity technique allows the model to harness a vast parameter count while controlling computational costs and latency.&lt;/p&gt;
&lt;p&gt;According to Mistral AI&amp;rsquo;s benchmarks, &lt;strong&gt;Mixtral 8x7B outperforms or matches the &lt;strong&gt;&lt;a href="/chatgpt-ai-in-linux-terminal/" target="_blank" rel="noopener"&gt;&lt;strong&gt;large language models like Llama 2 70B and GPT-3.5&lt;/strong&gt;&lt;/a&gt;
&lt;/strong&gt; across most multiple tasks,&lt;/strong&gt; including reasoning, mathematics, code generation, and multilingual benchmarks. Additionally, it provides &lt;strong&gt;6x faster inference than Llama 2 70B&lt;/strong&gt;, thanks to its sparse architecture.&lt;/p&gt;
&lt;a class="bookmark" href="/open-source-large-language-models/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/12/Open-Source-Large-Language-Models.png" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Should You Use Open Source Large Language Models?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;The benefits, risks, and considerations associated with using open-source LLMs, as well as the comparison with proprietary models.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="capabilities-and-performance"&gt;Capabilities and Performance&lt;/h2&gt;
&lt;p&gt;Mistral 7B vs. Mixtral 8x7B&lt;/p&gt;
&lt;p&gt;Both &lt;a href="/large-language-models-llm-explained/" target="_blank" rel="noopener"&gt;&lt;strong&gt;Mistral 7B and Mixtral 8x7B are good at code generation tasks&lt;/strong&gt;&lt;/a&gt;
like HumanEval and MBPP, with Mixtral 8x7B having a slight edge and it&amp;rsquo;s better. &lt;strong&gt;Mixtral 8x7B also supports multiple languages&lt;/strong&gt;, including English, French, German, Italian, and Spanish, making them valuable assets for multilingual applications.&lt;/p&gt;
&lt;p&gt;On the MMLU benchmark, which evaluates a model&amp;rsquo;s reasoning and comprehension abilities, Mistral 7B performs equivalently to a hypothetical Llama 2 model over three times its size.&lt;/p&gt;
&lt;a class="bookmark" href="/what-is-vector-database-and-how-does-it-work/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/06/What-is-Vector-Database-and-How-does-it-work_-Blog-Post-Thumbnail.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;What is Vector Database and How does it work?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Vector databases are highly intriguing and offer numerous compelling applications, especially when it comes to providing extensive memory.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h3 id="llms-benchmark-comparison-table"&gt;LLMs Benchmark Comparison Table&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Average MCQs&lt;/th&gt;
&lt;th&gt;Reasoning&lt;/th&gt;
&lt;th&gt;Python coding&lt;/th&gt;
&lt;th&gt;Future Capabilities&lt;/th&gt;
&lt;th&gt;Grade school math&lt;/th&gt;
&lt;th&gt;Math Problems&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude 3 Opus&lt;/td&gt;
&lt;td&gt;84.83%&lt;/td&gt;
&lt;td&gt;86.80%&lt;/td&gt;
&lt;td&gt;95.40%&lt;/td&gt;
&lt;td&gt;84.90%&lt;/td&gt;
&lt;td&gt;86.80%&lt;/td&gt;
&lt;td&gt;95.00%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 1.5 Pro&lt;/td&gt;
&lt;td&gt;80.08%&lt;/td&gt;
&lt;td&gt;81.90%&lt;/td&gt;
&lt;td&gt;92.50%&lt;/td&gt;
&lt;td&gt;71.90%&lt;/td&gt;
&lt;td&gt;84%&lt;/td&gt;
&lt;td&gt;91.70%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini Ultra&lt;/td&gt;
&lt;td&gt;79.52%&lt;/td&gt;
&lt;td&gt;83.70%&lt;/td&gt;
&lt;td&gt;87.80%&lt;/td&gt;
&lt;td&gt;74.40%&lt;/td&gt;
&lt;td&gt;83.60%&lt;/td&gt;
&lt;td&gt;94.40%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-4&lt;/td&gt;
&lt;td&gt;79.45%&lt;/td&gt;
&lt;td&gt;86.40%&lt;/td&gt;
&lt;td&gt;95.30%&lt;/td&gt;
&lt;td&gt;67%&lt;/td&gt;
&lt;td&gt;83.10%&lt;/td&gt;
&lt;td&gt;92%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude 3 Sonnet&lt;/td&gt;
&lt;td&gt;76.55%&lt;/td&gt;
&lt;td&gt;79.00%&lt;/td&gt;
&lt;td&gt;89.00%&lt;/td&gt;
&lt;td&gt;73.00%&lt;/td&gt;
&lt;td&gt;82.90%&lt;/td&gt;
&lt;td&gt;92.30%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude 3 Haiku&lt;/td&gt;
&lt;td&gt;73.08%&lt;/td&gt;
&lt;td&gt;75.20%&lt;/td&gt;
&lt;td&gt;85.90%&lt;/td&gt;
&lt;td&gt;75.90%&lt;/td&gt;
&lt;td&gt;73.70%&lt;/td&gt;
&lt;td&gt;88.90%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini Pro&lt;/td&gt;
&lt;td&gt;68.28%&lt;/td&gt;
&lt;td&gt;71.80%&lt;/td&gt;
&lt;td&gt;84.70%&lt;/td&gt;
&lt;td&gt;67.70%&lt;/td&gt;
&lt;td&gt;75%&lt;/td&gt;
&lt;td&gt;77.90%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Palm 2-L&lt;/td&gt;
&lt;td&gt;65.82%&lt;/td&gt;
&lt;td&gt;78.40%&lt;/td&gt;
&lt;td&gt;86.80%&lt;/td&gt;
&lt;td&gt;37.60%&lt;/td&gt;
&lt;td&gt;77.70%&lt;/td&gt;
&lt;td&gt;80%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-3.5&lt;/td&gt;
&lt;td&gt;65.46%&lt;/td&gt;
&lt;td&gt;70%&lt;/td&gt;
&lt;td&gt;85.50%&lt;/td&gt;
&lt;td&gt;48.10%&lt;/td&gt;
&lt;td&gt;66.60%&lt;/td&gt;
&lt;td&gt;57.10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mixtral 8x7B&lt;/td&gt;
&lt;td&gt;59.79%&lt;/td&gt;
&lt;td&gt;70.60%&lt;/td&gt;
&lt;td&gt;84.40%&lt;/td&gt;
&lt;td&gt;40.20%&lt;/td&gt;
&lt;td&gt;60.76%&lt;/td&gt;
&lt;td&gt;74.40%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Llama 2 - 70B&lt;/td&gt;
&lt;td&gt;51.55%&lt;/td&gt;
&lt;td&gt;69.90%&lt;/td&gt;
&lt;td&gt;87%&lt;/td&gt;
&lt;td&gt;30.50%&lt;/td&gt;
&lt;td&gt;51.20%&lt;/td&gt;
&lt;td&gt;56.80%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 7B&lt;/td&gt;
&lt;td&gt;50.60%&lt;/td&gt;
&lt;td&gt;64.30%&lt;/td&gt;
&lt;td&gt;81.2%&lt;/td&gt;
&lt;td&gt;32.3%&lt;/td&gt;
&lt;td&gt;55.10%&lt;/td&gt;
&lt;td&gt;46.40%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Falcon 180B&lt;/td&gt;
&lt;td&gt;42.62%&lt;/td&gt;
&lt;td&gt;70.60%&lt;/td&gt;
&lt;td&gt;87.50%&lt;/td&gt;
&lt;td&gt;35.40%&lt;/td&gt;
&lt;td&gt;37.10%&lt;/td&gt;
&lt;td&gt;19.60%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Llama 13B&lt;/td&gt;
&lt;td&gt;37.63%&lt;/td&gt;
&lt;td&gt;54.80%&lt;/td&gt;
&lt;td&gt;80.7%&lt;/td&gt;
&lt;td&gt;18.3%&lt;/td&gt;
&lt;td&gt;39.40%&lt;/td&gt;
&lt;td&gt;28.70%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Llama 7B&lt;/td&gt;
&lt;td&gt;30.84%&lt;/td&gt;
&lt;td&gt;45.30%&lt;/td&gt;
&lt;td&gt;77.22%&lt;/td&gt;
&lt;td&gt;12.8%&lt;/td&gt;
&lt;td&gt;32.6%&lt;/td&gt;
&lt;td&gt;14.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grok 1&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;73.00%&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;63%&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;62.90%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen 14B&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;66.30%&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;32%&lt;/td&gt;
&lt;td&gt;53.40%&lt;/td&gt;
&lt;td&gt;61.30%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mistral Large&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;81.2%&lt;/td&gt;
&lt;td&gt;89.2%&lt;/td&gt;
&lt;td&gt;45.1%&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;81%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;This model comparison table was last updated in March 2024.&lt;/em&gt; &lt;a href="https://www.vellum.ai/llm-leaderboard#model-comparison" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;Source&lt;/strong&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;When it comes to fine-tuning for specific use cases, Mistral AI provides &amp;ldquo;&lt;strong&gt;Instruct&lt;/strong&gt;&amp;rdquo; versions of both models, which have been optimized through supervised fine-tuning and direct preference optimization (DPO) for careful instruction following.&lt;/p&gt;
&lt;aside class="callout callout-info"&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;hr&gt;
&lt;h2 id="deployment-and-accessibility"&gt;Deployment and Accessibility&lt;/h2&gt;
&lt;p&gt;Mistral AI has made both &lt;a href="https://docs.mistral.ai/models/" target="_blank" rel="noopener noreferrer"&gt;Mistral 7B and Mixtral 8x7B available under the permissive Apache 2.0 license&lt;/a&gt;
, allowing developers and researchers to use these models without restrictions. The weights for these models can be downloaded from Mistral AI&amp;rsquo;s CDN, and the company provides detailed instructions for running the models locally, on &lt;a href="/tag/cloud/" target="_blank" rel="noopener"&gt;cloud platforms like AWS, GCP, and Azure&lt;/a&gt;
, or through services like HuggingFace.&lt;/p&gt;
&lt;h3 id="llms-cost-and-context-window-comparison-table"&gt;LLMs Cost and Context Window Comparison Table&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Models&lt;/th&gt;
&lt;th&gt;Context Window&lt;/th&gt;
&lt;th&gt;Input Cost / 1M tokens&lt;/th&gt;
&lt;th&gt;Output Cost / 1M tokens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 1.5 Pro&lt;/td&gt;
&lt;td&gt;128K&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mistral Medium&lt;/td&gt;
&lt;td&gt;32K&lt;/td&gt;
&lt;td&gt;$2.7&lt;/td&gt;
&lt;td&gt;$8.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude 3 Opus&lt;/td&gt;
&lt;td&gt;200K&lt;/td&gt;
&lt;td&gt;$15.00&lt;/td&gt;
&lt;td&gt;$75.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-4&lt;/td&gt;
&lt;td&gt;8K&lt;/td&gt;
&lt;td&gt;$30.00&lt;/td&gt;
&lt;td&gt;$60.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mistral Small&lt;/td&gt;
&lt;td&gt;16K&lt;/td&gt;
&lt;td&gt;$2.00&lt;/td&gt;
&lt;td&gt;$6.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-4 Turbo&lt;/td&gt;
&lt;td&gt;128K&lt;/td&gt;
&lt;td&gt;$10.00&lt;/td&gt;
&lt;td&gt;$30.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude 2.1&lt;/td&gt;
&lt;td&gt;200K&lt;/td&gt;
&lt;td&gt;$8.00&lt;/td&gt;
&lt;td&gt;$24.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude 2&lt;/td&gt;
&lt;td&gt;100K&lt;/td&gt;
&lt;td&gt;$8.00&lt;/td&gt;
&lt;td&gt;$24.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mistral Large&lt;/td&gt;
&lt;td&gt;32K&lt;/td&gt;
&lt;td&gt;$8.00&lt;/td&gt;
&lt;td&gt;$24.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Instant&lt;/td&gt;
&lt;td&gt;100K&lt;/td&gt;
&lt;td&gt;$0.80&lt;/td&gt;
&lt;td&gt;$2.40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-3.5 Turbo Instruct&lt;/td&gt;
&lt;td&gt;4K&lt;/td&gt;
&lt;td&gt;$1.50&lt;/td&gt;
&lt;td&gt;$2.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude 3 Sonnet&lt;/td&gt;
&lt;td&gt;200K&lt;/td&gt;
&lt;td&gt;$3.00&lt;/td&gt;
&lt;td&gt;$15.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-4-32k&lt;/td&gt;
&lt;td&gt;32K&lt;/td&gt;
&lt;td&gt;$60.00&lt;/td&gt;
&lt;td&gt;$120.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-3.5 Turbo&lt;/td&gt;
&lt;td&gt;16K&lt;/td&gt;
&lt;td&gt;$0.50&lt;/td&gt;
&lt;td&gt;$1.50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude 3 Haiku&lt;/td&gt;
&lt;td&gt;200K&lt;/td&gt;
&lt;td&gt;$0.25&lt;/td&gt;
&lt;td&gt;$1.25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini Pro&lt;/td&gt;
&lt;td&gt;32K&lt;/td&gt;
&lt;td&gt;$0.125&lt;/td&gt;
&lt;td&gt;$0.375&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grok 1&lt;/td&gt;
&lt;td&gt;64K&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;This cost and context window comparison table was last updated in March 2024.&lt;/em&gt; &lt;a href="https://www.vellum.ai/llm-leaderboard#model-comparison" target="_blank" rel="noopener noreferrer"&gt;&lt;strong&gt;Source&lt;/strong&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;aside class="callout callout-info"&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;aside class="callout callout-success"&gt;
&lt;div class="callout-body"&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;For those looking for a fully managed solution, Mistral AI offers access to these models through their platform, including a beta endpoint powered by Mixtral 8x7B.&lt;/p&gt;
&lt;a class="bookmark" href="/devops-vs-sre-vs-platform-engineering/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/11/DevOps-vs-SRE-vs-Platform-Engineering.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;DevOps vs SRE vs Platform Engineering - Explained&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;At small companies, engineers often wear multiple hats, juggling a mix of responsibilities. Large companies have specialized teams with clearly defined roles in DevOps, SRE, and Platform Engineering.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Mistral AI&amp;rsquo;s language models, Mistral 7B and Mixtral 8x7B, are truly innovative in terms of architectures, exceptional performance, and computational efficiency, these models are built to drive a wide range of applications, from code generation and multilingual tasks to reasoning and instruction.&lt;/p&gt;
&lt;a class="bookmark" href="/groq-lpu/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2024/03/How-does-Groq-s-LPU-work.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;How does the Groq’s LPU work?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Each year, language models double in size and capabilities. To keep up, we need new specialized hardware architectures built from the ground up for AI workloads.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;</content></entry><entry><title>Setup Memos Note-Taking App with MySQL on Docker &amp; S3 Storage</title><link href="https://firstfinger.io/memos-mysql-s3/"/><id>https://firstfinger.io/memos-mysql-s3/</id><updated>2024-06-20T17:05:24Z</updated><published>2024-03-22T20:05:09Z</published><author><name>Anurag Vishwakarma</name></author><category term="Cloud"/><category term="Container"/><category term="Database"/><category term="Linux"/><category term="Self Host"/><summary>Self-host the open-source, privacy-focused note-taking app Memos using Docker with a MySQL database and integrate with S3 or Cloudflare R2 object storage.</summary><content type="html">&lt;h2 id="what-is-memos"&gt;What is Memos?&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/03/CleanShot-2024-03-23-at-01.22.10.png" alt="Memos Note Taking App "&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.usememos.com/" target="_blank" rel="noopener noreferrer"&gt;Memos is an open-source, privacy-first, and lightweight note-taking application&lt;/a&gt;
service that allows you to easily capture and share your thoughts.&lt;/p&gt;
&lt;h3 id="memos-features"&gt;Memos features:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Open-source and free forever&lt;/li&gt;
&lt;li&gt;Self-hosting with Docker in seconds&lt;/li&gt;
&lt;li&gt;Pure text with Markdown support&lt;/li&gt;
&lt;li&gt;Customize and share notes effortlessly&lt;/li&gt;
&lt;li&gt;RESTful API for third-party integration&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="self-hosting-memos-with-docker-and-mysql-database"&gt;Self-Hosting Memos with Docker and MySQL Database&lt;/h2&gt;
&lt;p&gt;You can self-host Memos quickly using Docker Compose with a &lt;a href="/types-of-databases/" target="_blank" rel="noopener"&gt;MySQL database&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;: &lt;a href="/kubernetes-vs-docker-swarm/" target="_blank" rel="noopener"&gt;Docker and Docker Compose installed&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;You have two options to choose MySQL or MariaDB as a Database both are stable versions and MariaDB consumes less memory than MySQL.&lt;/p&gt;
&lt;h3 id="memos-with-mysql-80"&gt;Memos with MySQL 8.0&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;3.0&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mysql:8.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;TZ&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Asia/Kolkata&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;memos&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;memos-db&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;memos&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;memos&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;mysql_data:/var/lib/mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;healthcheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;CMD&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;mysqladmin&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ping&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;-h&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;localhost&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;20s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;always&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;memos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;neosmemo/memos:stable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;memos&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MEMOS_DRIVER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MEMOS_DSN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;memos:memos@tcp(mysql:3306)/memos-db&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;service_healthy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;~/.memos/:/var/opt/memos&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;5230:5230&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;always&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mysql_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;aside class="callout callout-info"&gt;
&lt;div class="callout-body"&gt;&lt;strong&gt;OR&lt;/strong&gt;&lt;/div&gt;
&lt;/aside&gt;
&lt;h3 id="memos-with-mariadb-110"&gt;Memos with MariaDB 11.0&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;3.0&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mariadb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mariadb:11.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;TZ&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Asia/Kolkata&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;memos&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;memos-db&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;memos&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;memos&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;mariadb_data:/var/lib/mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;healthcheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;CMD&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;healthcheck.sh&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;--connect&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;--innodb_initialized&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;start_period&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;10s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;10s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;5s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;always&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;memos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;neosmemo/memos:stable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;memos&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MEMOS_DRIVER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MEMOS_DSN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;memos:memos@tcp(mariadb:3306)/memos-db&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mariadb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;service_healthy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;~/.memos/:/var/opt/memos&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;5230:5230&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;always&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mariadb_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Create a new file named &lt;code&gt;docker-compose.yml&lt;/code&gt; and copy the above content.&lt;/li&gt;
&lt;li&gt;This sets up a MariaDB 11.0 database service and the Memos app linked to it.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;docker-compose up -d&lt;/code&gt; to start the services in detached mode.&lt;/li&gt;
&lt;li&gt;Memos will be available at &lt;code&gt;http://localhost:5230&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The configurations are:&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mysql&lt;/code&gt; service runs MySQL 8.0 with a database named &lt;code&gt;memos-db&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;memos&lt;/code&gt; service runs the latest Memos images, and links to the &lt;code&gt;mysql/mariadb&lt;/code&gt; service.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MEMOS_DRIVER=mysql&lt;/code&gt; tells Memos to use the MySQL database driver.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MEMOS_DSN&lt;/code&gt; contains the database connection details.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;~/.memos&lt;/code&gt; the directory is mounted for data persistence.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can customize the MySQL password, database name, and other settings by updating the environment variables.&lt;/p&gt;
&lt;a class="bookmark" href="/what-is-kubernetes/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/12/What-is-Kubernetes-4.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;Kubernetes for Noobs&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Kubernetes is an open-source system that helps with deploying, scaling, and managing containerized applications.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;hr&gt;
&lt;h2 id="configuring-s3-compatible-storage"&gt;Configuring S3 Compatible Storage&lt;/h2&gt;
&lt;p&gt;Memos support integrating with &lt;a href="/ec2-vs-s3/" target="_blank" rel="noopener"&gt;S3-compatible object storage like Amazon S3&lt;/a&gt;
, &lt;a href="https://developers.cloudflare.com/r2/" target="_blank" rel="noopener noreferrer"&gt;Cloudflare R2&lt;/a&gt;
, DigitalOcean Spaces, etc&lt;/p&gt;
&lt;h3 id="to-use-aws-s3-cloudflares-r2-as-object-storage"&gt;To use AWS S3/ Cloudflare&amp;rsquo;s R2 as object storage&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/03/image-4.png"
alt="Use memos with external object storage"&gt;&lt;figcaption&gt;
&lt;p&gt;Settings &amp;gt; Storage&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;ol&gt;
&lt;li&gt;Create a S3/Cloudflare R2 bucket&lt;/li&gt;
&lt;li&gt;Get the API token with object read/write permissions&lt;/li&gt;
&lt;li&gt;In Memos Admin &lt;code&gt;Settings &amp;gt; Storage&lt;/code&gt;, create a new storage&lt;/li&gt;
&lt;li&gt;Enter details like Name, Endpoint, Region, Access Key, Secret Key, Bucket name and Public URL (For Cloudflare R2 set &lt;code&gt;Region = auto&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Save and select this storage&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;&lt;img src="https://cdn.firstfinger.io/content/images/2024/03/CleanShot-2024-03-23-at-01.03.29.png"
alt="configure memos with external S3 Object Storage"&gt;&lt;figcaption&gt;
&lt;p&gt;For Cloudflare R2 set Region = auto&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;With this setup, you can self-host the privacy-focused Memos note app using Docker Compose with a MySQL database, while integrating scalable S3 or R2 storage for persisting data.&lt;/p&gt;
&lt;hr&gt;
&lt;a class="bookmark" href="/reduce-energy-costs-homelab-server/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/11/5-Ways-to-Reduce-Costs-on-Your-HomeLab-Server.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;13 Tips to Reduce Energy Costs on Your HomeLab Server&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;HomeLabs can be expensive when it comes to energy costs. It’s easy to accumulate multiple power-hungry servers, networking equipment, and computers.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;a class="bookmark" href="/run-linux-docker-containers-macos-orbstack/"&gt;
&lt;img class="bookmark-thumb" src="https://cdn.firstfinger.io/content/images/2023/09/Run-Linux-Based-Docker-Containers-on-Mac-1.jpg" alt="" loading="lazy"&gt;
&lt;div class="bookmark-meta"&gt;
&lt;strong class="bookmark-title"&gt;How to Run Linux Docker Containers Natively on Mac with OrbStack?&lt;/strong&gt;
&lt;p class="bookmark-desc"&gt;Run Linux-based Docker containers natively on macOS with OrbStack’s lightning-fast performance, featherlight resource usage, and simplicity. Get the best Docker experience on Mac.&lt;/p&gt;
&lt;span class="bookmark-host"&gt;firstfinger · Anurag Vishwakarma&lt;/span&gt;
&lt;/div&gt;
&lt;/a&gt;</content></entry></feed>