<?xml version="1.0" encoding="UTF-8"?>
<rss 
    version="2.0"
    xmlns:dc="http://purl.org/dc/elements/1.1/" 
    xmlns:content="http://purl.org/rss/1.0/modules/content/" 
    xmlns:atom="http://www.w3.org/2005/Atom" 
    xmlns:media="http://search.yahoo.com/mrss/" 
>
    <channel>
        <title><![CDATA[Linux Handbook]]></title>
        <description><![CDATA[An independent, reader-supported publication focusing on Linux Command Line, Server, Self-hosting, DevOps and Cloud Learning]]></description>
        <link>https://linuxhandbook.com</link>
        <image>
            <url>https://linuxhandbook.com/favicon.png</url>
            <title>Linux Handbook</title>
            <link>https://linuxhandbook.com</link>
        </image>
        <generator>Ghost 6.39</generator>
        <lastBuildDate>Sun, 31 May 2026 22:49:03 +0530</lastBuildDate>
        <atom:link href="https://linuxhandbook.com" rel="self" type="application/rss+xml"/>
        <ttl>60</ttl>

                <item>
                    <title><![CDATA[How I Set Up AI Agent to Access My Kanban Task Board]]></title>
                    <description><![CDATA[Life becomes easier when I can ask my AI assistant to create and manage my Kanban task board. Here&#x27;s the set up I use.]]></description>
                    <link>https://linuxhandbook.com/blog/zeroclaw-ai-with-fizzy-automation/</link>
                    <guid isPermaLink="false">6a1172010fd5850001a06a9f</guid>

                        <category><![CDATA[AI 🤖🧠]]></category>
                        <category><![CDATA[blog]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Fri, 29 May 2026 08:09:54 +0530</pubDate>

                        <media:content url="https://linuxhandbook.com/content/images/2026/05/ai-agent-with-kanban.webp" medium="image"/>

                    <content:encoded><![CDATA[<img src="https://linuxhandbook.com/content/images/2026/05/ai-agent-with-kanban.webp" alt="How I Set Up AI Agent to Access My Kanban Task Board"/> <p>I manage my project boards in <a href="https://www.fizzy.do/?ref=linuxhandbook.com">Fizzy</a>, Basecamp's clean, opinionated kanban tool, and I got tired of the same ritual: open the browser, navigate to the board, drag a card, close the tab, back to work,  repeat. The board lives in one app, my actual work lives somewhere else, and that context switching chips away at focus more than I'd like to admit. So I decided to fix it. Here's what I did.</p><h2 id="what-i-built">What I built</h2><p>Before going through this, I need you to know what Fizzy CLI and ZeroClaw is:</p><p>Fizzy CLI fixes half of that problem. It's an official command-line tool that lets you create cards, post comments, search your board, and manage attachments entirely from the terminal, no browser required. The other half of the problem gets solved by ZeroClaw.</p><p><a href="https://github.com/zeroclaw-labs/zeroclaw?ref=linuxhandbook.com">ZeroClaw</a> is an open-source agent runtime written in Rust, a single binary you install and configure. It connects to 30+ channels (Telegram, Discord, Matrix, email, or just your CLI), and is genuinely provider-agnostic: it talks to Anthropic, OpenAI, Gemini, Ollama, Groq, and about twenty other LLM backends, all from the same TOML config file. Everything runs on your machine, with your keys. This guide walks you through installing Fizzy CLI, authenticating it, and wiring it up to a running NanoClaw agent so you have end-to-end control of your boards from the terminal and from any messaging app.</p><p>Once you wire Fizzy into ZeroClaw as a shell tool, you can message your agent <strong><em>"add a card titled fix the auth bug to my backlog"</em></strong> and it just does it - from your phone, from Telegram, from wherever you happen to be.</p><p>I ended up installing Fizzy CLI, authenticating it, and wiring it to a ZeroClaw agent, and in this post I'm walking through exactly what I did, including the parts that didn't go smoothly.</p><h2 id="what-i-used">What I used</h2><ul>
<li>A Linux machine - I ran this on Ubuntu 22.04 LTS; Arch and Fedora should work fine too</li>
<li>An active <a href="https://fizzy.do/?ref=linuxhandbook.com">Fizzy</a> account with at least one board created</li>
<li>A Fizzy personal access token - get it from <strong>Profile → API Tokens</strong> in the Fizzy web UI</li>
<li>One of: a free <a href="https://aistudio.google.com/app/apikey?ref=linuxhandbook.com">Gemini API key from Google AI Studio</a>, or <a href="https://ollama.com/?ref=linuxhandbook.com">Ollama</a> running locally with a model pulled (e.g., <code>ollama pull qwen2.5:7b</code>)</li>
</ul>
<div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">💡</div><div class="kg-callout-text">The Gemini API has a generous free tier - 15 requests per minute and 250,000 tokens per minute on the free plan. That's more than enough for personal board management. If you already have Google One AI Premium, you get even higher limits in AI Studio.<br></div></div><h2 id="installing-fizzy-cli">Installing Fizzy CLI</h2><p>The fastest path on Linux is the official install script - it detected my architecture, pulled the right binary, and verified checksums automatically. I just ran:</p><pre><code class="language-bash">curl -fsSL https://raw.githubusercontent.com/basecamp/fizzy-cli/master/scripts/install.sh | bash</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-34.png" class="kg-image" alt="Installing fizzy-cli" loading="lazy" width="1281" height="695" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-34.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/05/image-34.png 1000w, https://linuxhandbook.com/content/images/2026/05/image-34.png 1281w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Installing fizzy-cli</span></figcaption></figure><p>Complete the installation process, it will prompt for the PAT, generate it from your personal fizzy profile and enter it when prompted. </p><p>If you're on Arch Linux or Omarchy, it's available in the AUR:</p><pre><code class="language-bash">yay -S fizzy-cli
</code></pre><p>Once the installer finishes, confirm the binary is on your PATH:</p><pre><code class="language-bash">fizzy --version
</code></pre><p>You should see the version string printed cleanly. If your shell says <code>command not found</code>, the binary likely landed in <code>~/.local/bin</code> - make sure that's in your <code>PATH</code>.</p><pre><code class="language-bash">export PATH="/home/USERNAME/.local/bin:$PATH"</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-35.png" class="kg-image" alt="fizzy working in terminal" loading="lazy" width="741" height="266" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-35.png 600w, https://linuxhandbook.com/content/images/2026/05/image-35.png 741w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">fizzy working in terminal</span></figcaption></figure><h2 id="exploring-the-basic-commands">Exploring the Basic Commands</h2><p>First I ran this to confirm my identity and grab my account slug:</p><pre><code class="language-bash">fizzy identity show</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-36.png" class="kg-image" alt="Fizzy Identity information" loading="lazy" width="866" height="117" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-36.png 600w, https://linuxhandbook.com/content/images/2026/05/image-36.png 866w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Fizzy Identity information</span></figcaption></figure><p>It will show all the identity information along with your <code>slug id</code> , use that id and run the following command:</p><pre><code class="language-bash">fizzy board list --account "slug id"</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-37.png" class="kg-image" alt="Fizzt listing boards " loading="lazy" width="962" height="99" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-37.png 600w, https://linuxhandbook.com/content/images/2026/05/image-37.png 962w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Fizzt listing boards </span></figcaption></figure><p>Here is a list of boards with their names. As I have more accounts, I need to mention the account ID for commands.</p><p>Try more commands like:</p><pre><code class="language-bash"># List cards on your default board
fizzy card list

# View details of a specific card
fizzy card show 2

# Search across your board
fizzy search "authentication bug"

# Add a comment to a card
fizzy comment create --card 42 --body "Reproduced on staging."</code></pre><p>It will display the cards, a specific card, searching across the board, etc.</p><p>Also, if you use <code>jq</code> the output will be in formatted so that you can clearly make sense of the results. </p><pre><code class="language-bash">fizzy card list --account "id" | jq</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-38.png" class="kg-image" alt="Formatted JSON output of fizzy" loading="lazy" width="1095" height="520" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-38.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/05/image-38.png 1000w, https://linuxhandbook.com/content/images/2026/05/image-38.png 1095w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Formatted JSON output of fizzy</span></figcaption></figure><h2 id="installing-zeroclaw">Installing ZeroClaw</h2><p>ZeroClaw ships as a single Rust binary. When the install script asked me whether I wanted a prebuilt binary or a source build, I went with prebuilt - it was done in seconds:</p><pre><code class="language-bash">curl -fsSL https://raw.githubusercontent.com/zeroclaw-labs/zeroclaw/master/install.sh | bash</code></pre><p>When it finishes, confirm it's available:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-39.png" class="kg-image" alt="ZeroClaw installed" loading="lazy" width="1275" height="552" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-39.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/05/image-39.png 1000w, https://linuxhandbook.com/content/images/2026/05/image-39.png 1275w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">ZeroClaw installed</span></figcaption></figure><p>When it finishes, confirm it's available:</p><pre><code class="language-bash">zeroclaw --version</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-40.png" class="kg-image" alt="ZeroClaw installed and working" loading="lazy" width="693" height="100" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-40.png 600w, https://linuxhandbook.com/content/images/2026/05/image-40.png 693w"><figcaption><span style="white-space: pre-wrap;">ZeroClaw installed and working</span></figcaption></figure><p>ZeroClaw has no runtime dependencies. No Docker, no Node.js, no Python. The binary is self-contained.</p><h2 id="running-the-onboarding-wizard">Running the Onboarding Wizard</h2><p>ZeroClaw's config lives at <code>~/.zeroclaw/config.toml</code>. Running the onboarding wizard creates it for you:  </p><pre><code class="language-bash">zeroclaw onboard</code></pre><p>The wizard walked me through four things:</p><ul>
<li>LLM provider - which model backend to use</li>
<li>API key or endpoint - your credentials for that provider</li>
<li>At least one channel - the built-in <code>cli</code> channel works for now; you can add Telegram or Discord later</li>
<li>Agent alias - a name for your agent entry in the config</li>
</ul>
<p>For the LLM provider step, enter <code>gemini</code> and paste your Google AI Studio API key when prompted. If you're using Ollama locally, choose <code>ollama</code> instead, the wizard will ask for your model name (e.g., <code>qwen2.5:7b</code>) and leave the endpoint at the default <code>http://localhost:11434</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-41.png" class="kg-image" alt="ZeroClaw onboard setup" loading="lazy" width="1041" height="718" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-41.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/05/image-41.png 1000w, https://linuxhandbook.com/content/images/2026/05/image-41.png 1041w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">ZeroClaw onboard setup</span></figcaption></figure><p>There is vast support for various channels: </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-42.png" class="kg-image" alt="Supported channel in ZeroClaw" loading="lazy" width="1041" height="718" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-42.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/05/image-42.png 1000w, https://linuxhandbook.com/content/images/2026/05/image-42.png 1041w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Supported channel in ZeroClaw</span></figcaption></figure><p>Then there will be an option to select a memory backend, select the appropriate one as per your need:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-43.png" class="kg-image" alt="Memory backend filter " loading="lazy" width="1041" height="718" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-43.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/05/image-43.png 1000w, https://linuxhandbook.com/content/images/2026/05/image-43.png 1041w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Memory backend filter </span></figcaption></figure><p><strong>the <code>model_provider</code> field on your agent is the only place you specify which LLM to use </strong>in your <code>~/.zeroclaw/config.toml</code> . Swapping from Gemini to Ollama to Groq is a one-line change.</p><h2 id="registering-fizzy-as-a-shell-tool">Registering Fizzy as a Shell Tool</h2><p>ZeroClaw's shell tool lets the agent run any command on your machine. To give it access to <code>fizzy</code>, add a tool entry to your config and give the agent permission to use it:</p><p>Add "fizzy" at commands in config, it will look like this:</p><pre><code class="language-toml">allowed_commands = [
    "git",
    "npm",
    "cargo",
    "ls",
    "cat",
    "grep",
    "find",
    "echo",
    "pwd",
    "wc",
    "head",
    "tail",
    "date",
    "df",
    "du",
    "uname",
    "uptime",
    "hostname",
    "python",
    "python3",
    "pip",
    "node",
    "free",
    "fizzy"
]</code></pre><p>One thing that caught me off guard: Fizzy has to be explicitly listed in allowed_commands or ZeroClaw's security layer blocks it, even if you've defined the tool entry. I learned this the hard way after getting a "Command not allowed by security policy" error.</p><p>Then add the new entry in the config: </p><pre><code class="language-toml">[tools.shell.fizzy]
description = "Manage Fizzy kanban boards via the Fizzy CLI"
command     = "fizzy"
allowed_args = ["board", "card", "comment", "search", "commands"]

[agents.assistant]
model_provider = "gemini-cli"
risk_profile   = "supervised"
tools          = ["shell.fizzy"]</code></pre><p>Follow the similar steps for ollama setup too.</p><p>Check once the parameters as per your model are selected. Whichever path you followed, the wizard ends with a quick live chat to confirm your agent is working. You'll see a prompt like:</p><h2 id="confirming-the-agent-responds">Confirming the Agent Responds</h2><p><br>Whichever path you followed, Gemini or Ollama, start the agent to confirm everything is working:</p><pre><code class="language-bash">zeroclaw agent
</code></pre><p>You should get a CLI chat prompt. Type a test message:</p><pre><code class="language-bash">Hello, are you there?</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-44.png" class="kg-image" alt="Agent responding to the model" loading="lazy" width="795" height="501" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-44.png 600w, https://linuxhandbook.com/content/images/2026/05/image-44.png 795w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Agent responding to the model</span></figcaption></figure><p>If it responds, you're done. If you are using a local LLM and see an error like <strong>model requires more system memory than is available</strong>, your chosen model is too large for the free RAM currently available. Fix it by pulling the 1B model instead and updating your config:</p><pre><code class="language-bash">ollama pull llama3.2:1b
# Then edit ~/.zeroclaw/config.toml and set: model = "llama3.2:1b"</code></pre><p>If it responds, your LLM backend is wired up correctly. Total setup time is about five minutes. Once the agent responds, you're ready to wire in Fizzy.</p><h2 id="verifying-the-fizzy-integration">Verifying the Fizzy Integration</h2><p> I asked the agent something simple to confirm the wiring:</p><pre><code class="language-bash">Use the fizzy shell tool to run: fizzy card list</code></pre><p>ZeroClaw called fizzy card list, parsed the JSON output, and summarized my cards in natural language. In supervised mode it asked for approval first - I pressed Y, and it worked.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-45.png" class="kg-image" alt="Fizzy cli with zeroclaw agent" loading="lazy" width="969" height="688" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-45.png 600w, https://linuxhandbook.com/content/images/2026/05/image-45.png 969w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Fizzy cli with zeroclaw agent</span></figcaption></figure><p>One tip I'd pass on: be explicit in your prompt. "List the cards on my board" can confuse the agent into doing a web search instead. Saying "use the fizzy shell tool to run..." removes the ambiguity entirely.</p><p>From there, you can do things like:</p><pre><code class="language-bash">Create a card titled "Review auth middleware" on my board.
Add a comment to first card saying I'll look at this after the release.
Search for anything related to "database migration".</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-46.png" class="kg-image" alt="Agent adding comment to respective cards" loading="lazy" width="974" height="385" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-46.png 600w, https://linuxhandbook.com/content/images/2026/05/image-46.png 974w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Agent adding comment to respective cards</span></figcaption></figure><h2 id="what-to-explore-next">What to Explore Next</h2><p>We have covered how to setup and get started with Fizzy CLI with ZeroClaw agent, but you can explore more things like: </p><p><strong>Per-repo board context</strong>: Create a <code>.fizzy.yaml</code> in any project directory with a <code>board</code> field. When you're inside that directory, <code>fizzy card list</code> will default to that project's board automatically, no flags needed.<br><br><strong>Swap the model</strong>: If Gemini starts hitting rate limits or you want to try something faster, add a second provider entry and change the <code>model_provider</code> alias on your agent. <br><br><strong>Add a second agent</strong>: ZeroClaw supports multiple <code>[agents.*]</code> entries pointing at different providers. You could run a lightweight Ollama model for quick card operations and route heavier reasoning tasks to Gemini, all from the same ZeroClaw instance.</p><h2 id="wrapping-up">Wrapping Up</h2><p>What I like most about this setup is the flexibility. ZeroClaw doesn't care which LLM I use. I started with Ollama locally, hit tool-calling limitations with smaller models, and switched to Gemini's free tier without touching anything except two lines in the config. </p><p>The context switching problem is what motivated all of this, and I think this setup genuinely solves it. Having Fizzy in the terminal is one improvement. It took me an afternoon to get everything right. The time it saves should compound from here.</p><p><strong>Do visit the repos and try it yourself!</strong></p>]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[How I Supercharged My Personal Knowledge Base with Local AI]]></title>
                    <description><![CDATA[Local notes. Local AI. Combine them and you have your own personal AI that answers based on your notes.]]></description>
                    <link>https://linuxhandbook.com/blog/personal-knowledge-base-with-local-ai/</link>
                    <guid isPermaLink="false">6a0da0870fd5850001a06639</guid>

                        <category><![CDATA[blog]]></category>
                        <category><![CDATA[AI 🤖🧠]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Fri, 22 May 2026 15:33:07 +0530</pubDate>

                        <media:content url="https://linuxhandbook.com/content/images/2026/05/knowledgebase-with-local-ai.webp" medium="image"/>

                    <content:encoded><![CDATA[<img src="https://linuxhandbook.com/content/images/2026/05/knowledgebase-with-local-ai.webp" alt="How I Supercharged My Personal Knowledge Base with Local AI"/> <p>I have thousands of notes. <a href="https://obsidian.md/?ref=linuxhandbook.com">Obsidian</a> vaults, random Markdown files, half-finished research documents, meeting notes from three years ago. And for the longest time, they just sat there, searchable by filename, searchable by keyword, but never actually <strong><em>understood</em></strong>.</p><p>Then one evening I thought, What if I could just <strong><em>ask</em></strong> my notes a question?</p><p>You might be thinking the ChatGPT already does that, but it does not have access to your local workspace. You need to upload all the files you want to discover, not a cloud service that makes me wonder what happens to my data. </p><p>Instead, I thought of using just a small AI model, completely running on my own machine. I thought that it could handle these situations, which could read my notes and answer questions about them.</p><p>I tried it. It worked. And I have not stopped using it since. No GPU required, no monthly subscription, no data leaving my machine.</p><h2 id="the-problem-with-the-huge-pile-notes-and-how-ai-fixes-it">The problem with the huge pile notes (and how AI fixes it)</h2><p>Here is the honest truth: most knowledge management systems fail not at <strong><em>storing</em></strong> information, but at <strong><em>retrieving</em></strong> it. You spend time writing the note. You tag it. You organize it. And then, three weeks later, you cannot find it because you cannot remember what you called it or which folder you put it in.<br><br>Traditional search is keyword-based. It finds notes that contain the word "containerization", but it cannot answer "how do I deploy a container in a restricted environment?" by synthesizing your notes on Docker, your notes on firewalls, and that one Markdown file you wrote during a workshop.<br><br>That synthesis is exactly what a local AI model can do.</p><p>The technique is called <strong>RAG (Retrieval-Augmented Generation)</strong>. The AI does not memorize your notes. Instead, it reads them at query time, pulls the most relevant chunks, and uses them as context to generate an answer. </p><p>Think of it as giving the AI your notes as a reference book every time you ask a question.</p><h2 id="what-i-used-in-this-setup">What I used in this setup</h2><p>A fully local setup with three components:</p><ul><li>Ollama: Runs LLM models locally on your CPU (or GPU if you have one)</li><li>A lightweight embedding model: Converts notes into searchable vectors</li><li>AnythingLLM (or Open WebUI): UI that connects your notes to the model</li></ul><p>Everything runs on the local machine. The notes never leave the computer. The model does not even need an internet connection once it is downloaded.</p><h2 id="choosing-the-right-model">Choosing the right model</h2><p>This is the part most guides get wrong. They recommend a 7B parameter model. You try to run it on your laptop, and it takes 90 seconds to answer a simple question.<br><br>For a knowledge base assistant that runs comfortably on a CPU, even a mid-range one, the sweet spot is <strong>Phi-3 Mini</strong> (3.8B parameters from Microsoft) or <strong>Gemma 2B</strong> (from Google). Both are surprisingly capable for question-answering tasks, and they run well with 8 GB of RAM.</p><p>You can also refer to this <a href="https://itsfoss.com/testing-local-llms-without-gpu/?ref=linuxhandbook.com" rel="noreferrer">article</a> for information about models running on CPU.<br><br><strong>My recommendation</strong>: <strong>phi3:mini,</strong> it is fast, accurate, and was specifically fine-tuned for instruction-following tasks like Q&amp;A. It is the model I use for my own notes.</p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">📋</div><div class="kg-callout-text">These tests were done on a machine with 16 GB RAM and no dedicated GPU. Phi3:mini took roughly 5–8 seconds to respond to most queries. I find that acceptable for a personal knowledge base.</div></div><h2 id="part-1-setting-up-ollama">Part 1: Setting up Ollama</h2><p>Ollama is the engine that lets you run LLMs locally. It is a single binary, and the installation is one command.</p><h3 id="step-1-install-ollama">Step 1: Install Ollama</h3><pre><code class="language-bash">curl -fsSL https://ollama.com/install.sh | sh</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-18.png" class="kg-image" alt="Ollama installed through curl." loading="lazy" width="798" height="498" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-18.png 600w, https://linuxhandbook.com/content/images/2026/05/image-18.png 798w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Ollama installed through curl</span></figcaption></figure><p>Once installed, verify it is running:</p><pre><code class="language-bash">ollama --version</code></pre><p>Ollama starts a background service automatically. You can check its status:</p><pre><code class="language-bash">systemctl status ollama</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-19.png" class="kg-image" alt="Ollama version and running status." loading="lazy" width="798" height="498" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-19.png 600w, https://linuxhandbook.com/content/images/2026/05/image-19.png 798w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Ollama version and running status</span></figcaption></figure><h3 id="step-2-pull-the-model">Step 2: Pull the model</h3><p>Now download the model. For the CPU-friendly, low-resource setup I recommend:</p><pre><code class="language-bash">ollama pull phi3:mini</code></pre><p>This will download about 2.3 GB. Grab a coffee. If you have more RAM available (16 GB+) and want slightly better answers, you can also try:</p><pre><code class="language-bash">ollama pull gemma2:2b</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-20.png" class="kg-image" alt="pulling phi3:mini model through ollama." loading="lazy" width="740" height="289" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-20.png 600w, https://linuxhandbook.com/content/images/2026/05/image-20.png 740w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">pulling phi3:mini model through ollama</span></figcaption></figure><p>To verify the model is installed and working, test it immediately:</p><pre><code class="language-bash">ollama run phi3:mini "Explain what the ITIM subject is all about."</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-21.png" class="kg-image" alt="model giving answer to the question." loading="lazy" width="793" height="599" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-21.png 600w, https://linuxhandbook.com/content/images/2026/05/image-21.png 793w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">model giving answer to the question</span></figcaption></figure><p>If you see a coherent response, the model is working. We can move on.</p><h2 id="part-2-setting-up-anythingllm-as-the-notes-interface">Part 2: Setting up AnythingLLM as the notes interface</h2><p><a href="https://anythingllm.com/?ref=linuxhandbook.com">AnythingLLM</a> is a self-hosted, open-source application that lets you upload documents, point it at a folder, and query them through a clean chat interface. It handles the chunking, embedding, and retrieval pipeline so you do not have to set up a vector database yourself.</p><h3 id="step-1-install-anythingllm-via-docker">Step 1: Install AnythingLLM via Docker</h3><pre><code class="language-bash">docker pull mintplexlabs/anythingllm</code></pre><p>Create a directory to store AnythingLLM's data (your note indexes will live here):</p><pre><code class="language-bash">mkdir -p ~/.anythingllm</code></pre><p>Now run it:</p><pre><code class="language-bash">docker run -d \
  --network=host \
  --cap-add SYS_ADMIN \
  -v $HOME/.anythingllm:/app/server/storage \
  -e STORAGE_DIR="/app/server/storage" \
  --name anythingllm \
  mintplexlabs/anythingllm</code></pre><p>Verify the container is running:</p><pre><code class="language-bash">docker ps | grep anythingllm</code></pre><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/05/image-25.png" class="kg-image" alt="" loading="lazy" width="822" height="246" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-25.png 600w, https://linuxhandbook.com/content/images/2026/05/image-25.png 822w" sizes="(min-width: 720px) 720px"></figure><p>Now open your browser and navigate to: <code>http://localhost:3001</code></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-23.png" class="kg-image" alt="AnythingLLM GUI interface" loading="lazy" width="1920" height="1080" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-23.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/05/image-23.png 1000w, https://linuxhandbook.com/content/images/size/w1600/2026/05/image-23.png 1600w, https://linuxhandbook.com/content/images/2026/05/image-23.png 1920w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">AnythingLLM GUI interface</span></figcaption></figure><p>You will see the AnythingLLM setup wizard.</p><h3 id="step-2-connecting-anythingllm-to-the-local-ollama-model">Step 2: Connecting AnythingLLM to the local Ollama model</h3><p>During setup, AnythingLLM will ask you to choose an LLM provider. Select <strong>Ollama</strong> from the list.</p><ul><li>Ollama Base URL: <a href="http://localhost:11434/?ref=linuxhandbook.com">http://localhost:11434</a></li><li>Model: Select <code>phi3:mini</code> from the dropdown (it will auto-detect your installed models)</li></ul><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-24.png" class="kg-image" alt="ollama setup for AnythingLLM" loading="lazy" width="1920" height="1080" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-24.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/05/image-24.png 1000w, https://linuxhandbook.com/content/images/size/w1600/2026/05/image-24.png 1600w, https://linuxhandbook.com/content/images/2026/05/image-24.png 1920w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">ollama setup for AnythingLLM</span></figcaption></figure><p>For the embedding model, which converts your notes into searchable vectors, stay within Ollama and choose:</p><pre><code class="language-bash">ollama pull nomic-embed-text</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-26.png" class="kg-image" alt="Select the model from the ollama" loading="lazy" width="928" height="931" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-26.png 600w, https://linuxhandbook.com/content/images/2026/05/image-26.png 928w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Select the model from the ollama</span></figcaption></figure><p><code>nomic-embed-text</code> is tiny (274 MB), fast, and produces excellent embeddings for English-language text. It is purpose-built for document retrieval, exactly what we need.</p><h2 id="part-3-importing-the-notes">Part 3: Importing the notes</h2><p>Let's move to connect knowledgebase with AI.</p><p>In AnythingLLM, a <strong>workspace</strong> is a scoped knowledge base. Think of it like a project folder; you can have one workspace for your work notes, one for personal research, one for a specific book you are reading.</p><ol><li>Click <strong>New Workspace</strong> and give it a name (e.g., "My Notes")</li><li>Click the <strong>Upload Documents</strong> button</li><li>Drag and drop your Markdown files, PDFs, or text files into the upload area</li></ol><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-27.png" class="kg-image" alt="Adding local notes to the workspace" loading="lazy" width="1860" height="968" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-27.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/05/image-27.png 1000w, https://linuxhandbook.com/content/images/size/w1600/2026/05/image-27.png 1600w, https://linuxhandbook.com/content/images/2026/05/image-27.png 1860w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Adding local notes to the workspace</span></figcaption></figure><p>AnythingLLM will split your notes into chunks (typically 500–1000 tokens each) then generate an embedding vector for each chunk using <code>nomic-embed-text</code>  and then store everything in a local vector database (LanceDB, stored in <code>~/.anythingllm</code>).</p><p>This process takes a minute or two, depending on how many notes you have. </p><div class="kg-card kg-callout-card kg-callout-card-green"><div class="kg-callout-emoji">💡</div><div class="kg-callout-text">AnythingLLM supports Markdown, PDF, plain text, DOCX, and even web page scraping. If your notes live in Obsidian, just point it at your vault folder. If they are in Notion, export them as Markdown first.</div></div><h2 id="part-4-querying-the-notes">Part 4: Querying the notes</h2><p>Now is the time to make the most of the notes by using AI to question it.</p><p>Now the satisfying part. Click on your workspace, type a question in the chat box, and press Enter. To truly see the power of local AI, ask something that ChatGPT could never possibly know. For example, if you uploaded your home server notes:</p><pre><code class="language- ">According to my server migration notes, why did I decide to switch from Nginx Proxy Manager to Traefik, and what IP address is my Pi-hole running on?</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-30.png" class="kg-image" alt="LLM answering form my personal notes" loading="lazy" width="1489" height="598" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-30.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/05/image-30.png 1000w, https://linuxhandbook.com/content/images/2026/05/image-30.png 1489w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">LLM answering form my personal notes</span></figcaption></figure><p>Notice that AnythingLLM shows you <strong><em>which notes it used</em></strong> to generate the answer. This is the RAG process in action; ChatGPT can tell you what <a href="https://traefik.io/traefik?ref=linuxhandbook.com">Traefik</a> is, but only <strong><em>your</em></strong> local AI knows that you switched to it because you were tired of managing SSL certificates manually, and that your Pi-hole is at <code>192.168.1.100</code>.</p><p>Try a few more highly personalized queries:</p><pre><code class="language-bash">What is the Wi-Fi password for the guest network at my parents' house, and where is the router hidden?</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-33.png" class="kg-image" alt="LLM asnwering from my home-lab notes" loading="lazy" width="1142" height="374" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-33.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/05/image-33.png 1000w, https://linuxhandbook.com/content/images/2026/05/image-33.png 1142w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">LLM asnwering from my home-lab notes</span></figcaption></figure><pre><code>When are my parents' birthdays this year, and what exactly did I decide to buy for my brother to fix his noisy keyboard?</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/image-32.png" class="kg-image" alt="LLM anwering from my family notes" loading="lazy" width="1270" height="673" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/image-32.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/05/image-32.png 1000w, https://linuxhandbook.com/content/images/2026/05/image-32.png 1270w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">LLM anwering from my family notes</span></figcaption></figure><p>Each answer is grounded in your notes. The model is not making things up from its training data; it is synthesizing from what <strong><em>you</em></strong> wrote, which means the answers are accurate to your actual knowledge and context.</p><h2 id="%F0%9F%92%A1-keeping-things-running-optional">💡 Keeping things running (optional)</h2><p>If you want AnythingLLM to start automatically with your system:</p><pre><code class="language-bash">docker update --restart unless-stopped anythingllm
</code></pre><p>And Ollama is already managed as a systemd service, so it will start on boot automatically.<br>To update the model later if a newer version is released:</p><pre><code class="language-bash">ollama pull phi3:mini
</code></pre><p>Ollama handles versioning for you.</p><h2 id="my-experience-so-far">My experience (so far)</h2><p>I have been using this setup for a few months now. Here is what changed for me:<br><br><strong>Before:</strong> I would search my notes, find five partial answers in different files, open each one, manually cross-reference them, and then write a synthesis myself.<br><strong>After:</strong> I ask a question. In 5–8 seconds, I get a synthesized answer with the source notes cited. I open the sources to verify. Done.</p><p>The model is not perfect - Phi3:mini will occasionally miss nuance or misread a technical term from a note. But for a free, offline, CPU-only setup, it is genuinely impressive.</p><p>What it is excellent at:</p><ul><li>Summarizing notes on a topic</li><li>Finding connections between notes you forgot existed</li><li>Drafting a starting point for new writing based on your existing research</li><li>Answering "what did I write about X" questions instantly</li></ul><p>What to watch out for:</p><ul><li>Very long PDFs (&gt;50 pages) may need to be split before uploading</li><li>Code blocks in Markdown sometimes confuse the chunking</li><li>Plain prose notes work best</li><li>The model will occasionally "hallucinate" if your notes are thin on a topic; always verify</li></ul><p>The entire stack is free, open-source, and runs completely offline. Once set up, it requires zero maintenance and adds nothing to your monthly cloud bill.</p><h2 id="conclusion">Conclusion</h2><p>The popular mental model of AI is "Cloud service that reads your data". This does not have to be the case and for personal notes, it arguably <strong><em>should not</em></strong> be.<br><br>A small, open model running locally on your laptop is good enough for synthesizing your own knowledge base. It will not beat GPT-4 at coding challenges or creative writing. But for the task of "help me navigate and synthesize the notes <strong><em>I</em></strong> already wrote", it does the job well.</p><p>Your notes are already doing half the work. A local AI just helps you finish the other half.</p>]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[LHB Linux Digest #26.07: New ELK Stack Course, Linux in Browser, Best YouTube Channels for DevOps and More]]></title>
                    <description><![CDATA[ELK Stack course is here.]]></description>
                    <link>https://linuxhandbook.com/newsletter/26-07/</link>
                    <guid isPermaLink="false">69e7025b918745000127fa6a</guid>

                        <category><![CDATA[Newsletter]]></category>

                        <dc:creator><![CDATA[Abhishek Prakash]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 19:00:48 +0530</pubDate>

                        <media:content url="https://linuxhandbook.com/content/images/2026/05/lhb-newsletter.png" medium="image"/>

                    <content:encoded><![CDATA[<img src="https://linuxhandbook.com/content/images/2026/05/lhb-newsletter.png" alt="LHB Linux Digest #26.07: New ELK Stack Course, Linux in Browser, Best YouTube Channels for DevOps and More"/> <p>Our 20th course is now available 🍾</p><p>This one is about log management with ELK stack. </p><p>Actually, it's not ELK. Instead of Elastic Search, we used OpenSearch. The course gives you the basics along with sample labs to follow.</p><p>This is available for Pro members only. Not a Pro member yet? <a href="https://linuxhandbook.com/#/portal/signup">Upgrade to Pro membership</a> and access all 20 courses, 6 eBooks and every other premium content.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://linuxhandbook.com/courses/opensearch/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Log Management Course (ELK Stack with OpenSearch)</div><div class="kg-bookmark-description">Stop SSH-ing into servers at 2 AM. Learn to centralize, search, and visualize logs across your entire infrastructure using fully open-source tools.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://linuxhandbook.com/content/images/icon/Linux-Handbook-New-Logo-202.png" alt=""><span class="kg-bookmark-author">Linux Handbook</span><span class="kg-bookmark-publisher">Yash Kiran Patil</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://linuxhandbook.com/content/images/thumbnail/elk-stack-course.png" alt="" onerror="this.style.display = 'none'"></div></a></figure><p>The next course in our pipeline is GitOps video course. After that, we are also thinking of creating a course around using AI assistance in typical DevOps scenarios. I'll keep you posted.</p>

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">
        <div data-sx-content-cta-blur class="absolute w-full start-0 -top-0.5 -translate-y-full bg-linear-to-b to-70% from-black/0 to-background dark:to-background-dark pointer-events-none">
            &nbsp; <br> &nbsp; <br> &nbsp;
        </div>

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                        <span class="hidden first:inline">
                        This post is for subscribers only
                    </span>                

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[13 YouTube Channels I Recommend For Learning DevOps for Free]]></title>
                    <description><![CDATA[Learning is free if you just look for the right resources. From the noise, I have filtered the best YouTube channels that will help you learn DevOps for free.]]></description>
                    <link>https://linuxhandbook.com/blog/devops-learn-youtube-channels/</link>
                    <guid isPermaLink="false">69d72638df009b000198837d</guid>

                        <category><![CDATA[blog]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 18:35:29 +0530</pubDate>

                        <media:content url="https://linuxhandbook.com/content/images/2026/05/youtube-channels-3d.webp" medium="image"/>

                    <content:encoded><![CDATA[<img src="https://linuxhandbook.com/content/images/2026/05/youtube-channels-3d.webp" alt="13 YouTube Channels I Recommend For Learning DevOps for Free"/> <p>I have been learning DevOps for a while now. The problem is not finding DevOps content on YouTube. There is plenty of it. The problem is knowing which channels are actually worth your time.</p><p>Some channels drop theory at you for 45 minutes without touching a terminal. Others teach outdated tooling. A few are genuinely excellent - structured, practical, updated, and respected by the community. I went through dozens of channels, cross-checked with what the DevOps community recommends and narrowed it down to 14 that hold up in real learning situations. </p><p>These are not ordered by subscriber count or popularity contests. They are ordered by how naturally they build on each other - from foundational to advanced, from broad to specialized.</p><p><strong>Short on time?</strong> See the quick overview table below, then jump to the channels that match your current level.</p><h2 id="at-a-glance-all-14-channels-compared">At a Glance: All 14 Channels Compared</h2><table>
<thead>
<tr>
<th>Channel</th>
<th>Best For</th>
<th>Content Style</th>
<th>Skill Level</th>
<th>Our Pick</th>
</tr>
</thead>
<tbody>
<tr>
<td>TechWorld with Nana</td>
<td>Full DevOps roadmap</td>
<td>Structured courses</td>
<td>Beginner → Mid</td>
<td>🏆 Top Pick</td>
</tr>
<tr>
<td>freeCodeCamp.org</td>
<td>Full-length free courses</td>
<td>Crash courses</td>
<td>All levels</td>
<td>Best for complete courses</td>
</tr>
<tr>
<td>NetworkChuck</td>
<td>Linux, Docker, Networking</td>
<td>Energetic explainers</td>
<td>Beginner</td>
<td>Best entry point</td>
</tr>
<tr>
<td>KodeKloud</td>
<td>Cert prep + labs</td>
<td>Hands-on lab-style</td>
<td>Beginner → Mid</td>
<td>Best for cert prep</td>
</tr>
<tr>
<td>Fireship</td>
<td>Fast concept explainers</td>
<td>100-second / short</td>
<td>All levels</td>
<td>Best quick reference</td>
</tr>
<tr>
<td>DevOps Directive</td>
<td>Docker, K8s, Terraform</td>
<td>Deep-dive tutorials</td>
<td>Mid → Advanced</td>
<td>Best for depth</td>
</tr>
<tr>
<td>Kunal Kushwaha</td>
<td>DevOps bootcamp + OSS</td>
<td>Full bootcamp series</td>
<td>Beginner → Mid</td>
<td>Best free bootcamp</td>
</tr>
<tr>
<td>TrainWithShubham</td>
<td>Real projects + roadmap</td>
<td>Project-driven</td>
<td>Beginner → Mid</td>
<td>🏆 Editor's Pick</td>
</tr>
<tr>
<td>That DevOps Guy</td>
<td>Real-world K8s + GitOps</td>
<td>Honest, production-style</td>
<td>Mid → Advanced</td>
<td>Best real-world K8s</td>
</tr>
<tr>
<td>KubeSimplify</td>
<td>Kubernetes deep dives</td>
<td>Practical demos</td>
<td>Mid → Advanced</td>
<td>Best K8s-focused</td>
</tr>
<tr>
<td>Bret Fisher</td>
<td>Docker + K8s Q&amp;A</td>
<td>Live sessions</td>
<td>Mid → Advanced</td>
<td>Best for live Q&amp;A</td>
</tr>
<tr>
<td>Anton Putra</td>
<td>AWS, Terraform, K8s</td>
<td>Production-grade</td>
<td>Advanced</td>
<td>Best production-level</td>
</tr>
<tr>
<td>Abhishek.Veeramalla</td>
<td>DevOps roadmap + interviews</td>
<td>Projects + roadmaps</td>
<td>Beginner → Mid</td>
<td>Best for interviews</td>
</tr>
<tr>
<td>Jeff Geerling</td>
<td>Ansible + homelab infra</td>
<td>Practical demos</td>
<td>Mid → Advanced</td>
<td>Best for Ansible</td>
</tr>
</tbody>
</table>
<h2 id="techworld-with-nanabest-for-a-complete-devops-learning-path">TechWorld with Nana - Best for a Complete DevOps Learning Path</h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/04/image-16.png" class="kg-image" alt="" loading="lazy" width="1231" height="440" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-16.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-16.png 1000w, https://linuxhandbook.com/content/images/2026/04/image-16.png 1231w" sizes="(min-width: 720px) 720px"></figure><p>TechWorld with Nana is the most recommended DevOps channel on communities and it earns that consistently. Nana covers the full DevOps stack - Docker, Kubernetes, CI/CD, Terraform, Ansible and monitoring - in a structured, course-style format that builds concepts before jumping into commands.</p><p>She starts with the basic concepts, builds the fundamentals and then moves towards the advanced concepts and practical approach of the concept. Especially <a href="https://youtube.com/playlist?list=PLy7NrYWoggjwPggqtFsI_zMAwvG0SqYCb&si=3JkeIMtKOMMDqMZ5&ref=linuxhandbook.com" rel="noreferrer"><strong><em>Docker and Kubernetes Tutorial for Beginners</em></strong></a> is one of the most popular and recommended playlists on YouTube.</p><p><strong>Who it's best for: </strong>Complete beginners who want a single channel that takes them from zero to job-ready on core DevOps tooling, without having to stitch together random videos.</p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">🤔</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Why follow this channel?</strong></b><br>Covers the entire DevOps toolchain in a logical sequence. One of the clearest explainers of Kubernetes architecture you'll find anywhere. Videos stay current and playlists are regularly updated as tools evolve.</div></div><p><strong>Verdict:</strong> Think of this as your DevOps course library. When you need a full course on a specific tool - Terraform, AWS, Kubernetes, this is where you look first.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://www.youtube.com/@TechWorldwithNana?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">Youtube | TechWorld with Nana</a></div><h2 id="freecodecamporgbest-for-full-length-free-courses-on-every-devops-topic">freeCodeCamp.org - Best for Full-Length Free Courses on Every DevOps Topic</h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/04/image-15.png" class="kg-image" alt="" loading="lazy" width="1231" height="440" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-15.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-15.png 1000w, https://linuxhandbook.com/content/images/2026/04/image-15.png 1231w" sizes="(min-width: 720px) 720px"></figure><p>freeCodeCamp's YouTube channel is not a DevOps-specific channel - it is a massive library of full-length, structured courses across every technical domain, and its DevOps coverage is exceptional. You will find complete, multi-hour courses on Docker, Kubernetes, Terraform, AWS, Linux, and more, all free, no sign-up required.</p><p>They usually have one-shot videos of multiple hours, which cover the whole topic in depth, like <a href="https://www.youtube.com/playlist?list=PLWKjhJtqVAbkzvvpY12KkfiIGso9A_Ixs&ref=linuxhandbook.com" rel="noreferrer">Docker Tutorial for Beginners, Kubernetes course - Full Beginner Tutorial, etc.</a> They cover a wide range of DevOps topics in full-length videos; you name it, and they have it on their channel.</p><p><strong>Who it's best for: </strong>Anyone who prefers structured, course-style learning, the kind where you sit down, follow along start to finish, and come out the other end having actually learned a tool completely.</p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">🤔</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Why follow this channel?</strong></b><br>Hosts some of the best free full-length DevOps courses on the internet. Courses are taught by respected practitioners, not generalists. Covers tools that smaller channels skip: Jenkins, Ansible, GitHub Actions in depth. Trusted by millions, the quality bar for what gets published here is high</div></div><p><strong>Verdict:</strong> Think of this as your DevOps course library. When you need a full course on a specific tool - Terraform, AWS, Kubernetes, this is where you look first.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://www.youtube.com/@freecodecamp?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">Youtube | freeCodeCamp.org</a></div><h2 id="networkchuckbest-entry-point-for-absolute-beginners">NetworkChuck - Best Entry Point for Absolute Beginners</h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/04/image-17.png" class="kg-image" alt="" loading="lazy" width="1231" height="440" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-17.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-17.png 1000w, https://linuxhandbook.com/content/images/2026/04/image-17.png 1231w" sizes="(min-width: 720px) 720px"></figure><p>NetworkChuck makes networking, Linux, Docker, and cloud concepts feel genuinely approachable. His style is upbeat, fast-paced, and deliberately beginner-friendly - built around the philosophy that the first goal is to make you comfortable enough to not quit.<br><br>He mainly makes videos related to cybersecurity, home labs, self-hosted tools and Linux, which is essential for building the prerequisites for DevOps. His storytelling abilities make you stick with the concept and follow all along.</p><p><strong>Who it's best for<em>: </em></strong>Complete beginners who feel intimidated by technical content and need a first channel that makes them feel like they can actually do this - before moving to more structured learning.</p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">🤔</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Why follow this channel?</strong></b><br>Removes the intimidation factor better than almost any other channel. Linux, networking, and Docker explanations are some of the clearest for newcomers. High-energy style genuinely makes complex topics feel approachable. Great for building foundational context before diving into tools.</div></div><p><strong>Verdict:</strong> The best channel to remove the intimidation factor before starting a structured DevOps path. Watch a few videos here, then move to a sequenced learning track.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://www.youtube.com/@NetworkChuck?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">Youtube | NetworkChuck</a></div><h2 id="kodekloudbest-channel-for-learning-by-doing-and-certification-prep">KodeKloud - Best Channel for Learning by Doing and Certification Prep</h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/04/image-18.png" class="kg-image" alt="" loading="lazy" width="1231" height="440" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-18.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-18.png 1000w, https://linuxhandbook.com/content/images/2026/04/image-18.png 1231w" sizes="(min-width: 720px) 720px"></figure><p>KodeKloud started as a training platform and its YouTube channel reflects that DNA: every video is designed around hands-on exercises with a clear learning objective. It is the most consistently recommended channel on Reddit when someone asks about CKA, CKAD, or CKS Kubernetes certification prep.</p><p>The channel focused on certification prep as well as concept videos on topics like Docker, Kubernetes, Nginx, AWS, etc. <a href="https://youtu.be/XuSQU5Grv1g?si=PWLwe6Eb-IqoPac3&ref=linuxhandbook.com" rel="noreferrer">Kubernetes Crash Course</a> is one of the most popular video which covers the Kubernetes concepts in the best possible way according to the viewers.</p><p><strong>Who it's best for: </strong>Learners who retain things by doing, not just watching - and anyone preparing for Kubernetes, Docker, or AWS certifications who wants structured prep content that matches the actual exam format.</p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">🤔</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Why follow this channel?</strong></b><br>Community consistently names it as the top cert prep resource. Bridges the gap between "watching a tutorial" and "actually doing the thing". Covers CLF-CO2, CKA, CKAD, Docker DCA, AWS certifications reliably. </div></div><p><strong>Verdict:</strong> The best structured practice resource on YouTube for DevOps certifications. Watch KodeKloud when you are preparing for CKA, CKAD, or Docker certification - it was built for exactly that.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://www.youtube.com/@KodeKloud?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">Youtube | KodeKloud</a></div><h2 id="fireshipbest-for-fast-accurate-concept-explainers">Fireship - Best for Fast, Accurate Concept Explainers</h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/04/image-19.png" class="kg-image" alt="" loading="lazy" width="1231" height="440" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-19.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-19.png 1000w, https://linuxhandbook.com/content/images/2026/04/image-19.png 1231w" sizes="(min-width: 720px) 720px"></figure><p>Fireship is not a DevOps channel - it is a technology explainer channel with a cult following, and its DevOps coverage is some of the best bite-sized technical content on the internet. The famous "X in 100 seconds" format delivers accurate, dense explanations of Docker, Kubernetes, CI/CD pipelines, Git, and cloud concepts faster than any other format.</p><p><strong>Who it's best for: </strong>Learners at any level who want a fast, accurate reference for a concept they have heard of but do not fully understand - before going deeper elsewhere. Also excellent for keeping up with new DevOps tooling without spending hours on each one.</p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">🤔</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Why follow this channel?</strong></b><br>"Docker in 100 Seconds" and "Kubernetes in 100 Seconds" are legitimately among the best short explainers on the internet. The channel has a cult following for a reason; accuracy and density per minute are extremely high. Great for understanding what something <i><b><strong class="italic" style="white-space: pre-wrap;">is</strong></b></i> before committing time to learn it. Covers new tooling rapidly as it emerges in the ecosystem</div></div><p><strong>Verdict: </strong>The fastest way to understand what something does before committing to learning it. Use Fireship to decide what to learn next, then use a hands-on channel to actually learn it.</p><h2 id="devops-directivebest-for-deep-technically-accurate-tutorials">DevOps Directive - Best for Deep, Technically Accurate Tutorials</h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/04/image-20.png" class="kg-image" alt="" loading="lazy" width="1231" height="440" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-20.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-20.png 1000w, https://linuxhandbook.com/content/images/2026/04/image-20.png 1231w" sizes="(min-width: 720px) 720px"></figure><p>DevOps Directive is the channel community recommends when someone says, "I want to actually understand Docker and Kubernetes, not just copy commands." Every tutorial is longer than average, technically precise, and built around real use cases rather than simplified toy examples.</p><p>He covers the history, installation, demo, practical, deployment, clustering and CI/CD in a complete depth. His <a href="https://youtube.com/playlist?list=PLFzuOAehUPHFxhoawwYCh8ENUsR2sxdYm&si=hWX7dFTzSlnIxBVS&ref=linuxhandbook.com" rel="noreferrer"><strong>Best of DevOps Directive YouTube Videos</strong></a> is popular for in depth knowledge of DevOps. </p><p><strong>Who it's best for:<em>  </em></strong>Intermediate learners who already have the basics and want to go deep, understanding not just how to use Docker or Terraform, but why the design decisions exist and how things work under the hood.</p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">🤔</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Why follow this channel?</strong></b><br> Consistently praised in the community for correctness - the tutorials do not cut corners. The complete Docker course is one of the most thorough free Docker resources available. Covers Terraform, GitHub Actions, and CI/CD with real production context. Rare combination of depth and clarity in a single channel</div></div><p><strong>Verdict:</strong> When you are past the basics and want tutorials that respect your technical intelligence, DevOps Directive is where you go. Fewer videos, higher quality per video.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://www.youtube.com/@DevOpsDirective?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">YouTube | DevOps Directive</a></div><h2 id="kunal-kushwahabest-free-devops-bootcamp-on-youtube">Kunal Kushwaha - Best Free DevOps Bootcamp on YouTube</h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/04/image-21.png" class="kg-image" alt="" loading="lazy" width="1131" height="424" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-21.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-21.png 1000w, https://linuxhandbook.com/content/images/2026/04/image-21.png 1131w" sizes="(min-width: 720px) 720px"></figure><p>Kunal Kushwaha's DevOps bootcamp is one of the rare examples of a complete, free, structured DevOps curriculum published entirely on YouTube. The bootcamp covers Linux, Docker, Kubernetes, networking, Git, CI/CD, and cloud from scratch, in a sequence that actually makes sense as a learning path.</p><p><a href="https://youtube.com/playlist?list=PL9gnSGHSqcnoqBXdMwUTRod4Gi3eac2Ak&si=Q817s0gzF6BmeU1P&ref=linuxhandbook.com" rel="noreferrer">DevOps Bootcamp</a> is a popular series in which he has covered the DevOps topics in depth; the teaching style is more of a conversation where you don't feel it as a scripted story.</p><p><strong>Who it's best for: </strong>Beginners and intermediate learners who want a free, structured bootcamp they can follow from start to finish - without paying for a course platform or stitching together random videos.</p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">🤔</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Why follow this channel?</strong></b><br>One of the few YouTube channels offering a genuinely comprehensive, sequenced DevOps bootcamp for free. Heavy emphasis on open source and community, with an active Discord community named WeMakeDevs. The bootcamp format means you always know what to watch next. Strong focus on building real-world projects, not toy examples.</div></div><p><strong>Verdict:</strong> If you want a free, complete, structured bootcamp that you can follow without paying anyone, Kunal Kushwaha's bootcamp series is the honest answer.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://www.youtube.com/@KunalKushwaha?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">YouTube | Kunal Kushwaha</a></div><h2 id="trainwithshubhambest-for-project-based-learning-and-roadmap-clarity">TrainWithShubham - Best for Project-Based Learning and Roadmap Clarity</h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/04/image-22.png" class="kg-image" alt="" loading="lazy" width="1109" height="419" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-22.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-22.png 1000w, https://linuxhandbook.com/content/images/2026/04/image-22.png 1109w" sizes="(min-width: 720px) 720px"></figure><p>TrainWithShubham is built around one idea: learning DevOps by building and deploying real projects. Shubham Londhe focuses on projects that you can put on a resume, CI/CD pipelines, containerized deployments and infrastructure automation and explains the roadmap clearly for learners unsure what to learn next.</p><p>The creator teaches in the native language Hindi, so it might be a con for other language users, but for users whose native language is Hindi it provides a clear understanding of the topic that he covers fully. Has one of the best one-shot videos, like <a href="https://youtu.be/e01GGTKmtpc?si=fx58pHCvEo5OJ83T&ref=linuxhandbook.com" rel="noreferrer">Linux One Shot</a>, <a href="https://youtu.be/W04brGNgxN4?si=ZF7_WIl1psAFj7AM&ref=linuxhandbook.com" rel="noreferrer">Kubernetes One Shot</a> and many more.</p><p><strong>Who it's best for: </strong>Beginners and intermediate learners who are actively job-hunting or building a portfolio, and want project-based tutorials that produce something real, not another to-do app deployed locally.</p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">💡</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Why follow this channel?</strong></b><br>A project-first approach means you always have something to show for your learning time. Roadmap content is some of the most practical advice available for DevOps job seekers in 2026. Active community with live sessions and challenges. Covers the full stack: Docker, Kubernetes, Jenkins, GitHub Actions, Terraform, AWS.</div></div><p><strong>Verdict:</strong> If building an actual DevOps portfolio is your goal, TrainWithShubham's project-based approach gives you real output for every hour you invest, especially if you are a Hindi audience.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://www.youtube.com/@TrainWithShubham?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">YouTube | TrainWithShubham</a></div><h2 id="that-devops-guybest-for-honest-real-world-kubernetes-content">That DevOps Guy - Best for Honest, Real-World Kubernetes Content</h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/04/image-23.png" class="kg-image" alt="" loading="lazy" width="1109" height="419" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-23.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-23.png 1000w, https://linuxhandbook.com/content/images/2026/04/image-23.png 1109w" sizes="(min-width: 720px) 720px"></figure><p>Marcel Dempers does not make content for clout. That DevOps Guy is built around real Kubernetes setups, actual production decisions, and content that tells you what actually happens when things go wrong, not just the happy path. The channel covers Kubernetes, Helm, GitOps, ArgoCD, and service mesh with a refreshing absence of marketing language.</p><p>What makes him truly unique is his distinctive teaching style combined with those nostalgic, retro-style animations that make even the most complex concepts feel simple and fun. His real, no-fluff talk in every video delivers deep, practical knowledge that actually sticks - turning technical topics into something you genuinely enjoy learning.</p><p><strong>Who it's best for: </strong>Intermediate to advanced learners who want Kubernetes content that reflects what real deployments actually look like - including the failure modes, tradeoffs, and operational realities that most tutorials skip.</p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">🤔</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Why follow this channel? </strong></b><br>Community consistently praises it for honesty, he says when things are hard, not just when they work. GitOps and ArgoCD content is among the best available on YouTube. Multi-cluster and production Kubernetes scenarios are covered in depth. No hype, the tone is a practical engineer talking to practical engineers.</div></div><p><strong>Verdict:</strong> One of the most trusted voices in the Kubernetes space, precisely because Marcel does not oversimplify. When you are ready for production-level content, this channel is a regular stop.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://www.youtube.com/@MarcelDempers?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">YouTube | That DevOps Guy</a></div><h2 id="kubesimplifybest-channel-focused-entirely-on-kubernetes">KubeSimplify - Best Channel Focused Entirely on Kubernetes</h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/04/image-24.png" class="kg-image" alt="" loading="lazy" width="1109" height="419" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-24.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-24.png 1000w, https://linuxhandbook.com/content/images/2026/04/image-24.png 1109w" sizes="(min-width: 720px) 720px"></figure><p>KubeSimplify does one thing: Kubernetes. Not Docker fundamentals, not cloud basics, Kubernetes concepts, tools, and ecosystem in depth. The channel covers Helm, Kustomize, GitOps, cluster management, networking, and Kubernetes tooling with a focus on making concepts clear through practical demos.</p><p><a href="https://youtu.be/EV47Oxwet6Y?si=68ghos_LQe7sbssA&ref=linuxhandbook.com" rel="noreferrer">The Kubernetes Course</a> by him is one of the suggested courses for gaining complete knowledge of Kubernetes.</p><p><strong>Who it's best for: </strong>Learners who have Docker and basic Kubernetes knowledge and want to go deep specifically into the Kubernetes ecosystem - Helm, GitOps, cluster operations, RBAC, networking policies, and more.</p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">🤔</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Why follow this channel? </strong></b><br>One of the few channels focused entirely on the Kubernetes ecosystem rather than splitting attention with other topics. Kustomize and Helm content is well-structured and goes beyond basic usage. Covers CNCF projects that most DevOps channels skip. Practical demo-first style that shows things working before explaining them.</div></div><p><strong>Verdict:</strong> The go-to channel when you are ready to move beyond <code>kubectl apply</code> and actually understand how Kubernetes production setups are built.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://www.youtube.com/@kubesimplify?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">YouTube | KubeSimplify</a></div><h2 id="bret-fisherbest-for-docker-and-kubernetes-live-qa">Bret Fisher - Best for Docker and Kubernetes Live Q&amp;A</h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/04/image-25.png" class="kg-image" alt="" loading="lazy" width="1109" height="419" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-25.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-25.png 1000w, https://linuxhandbook.com/content/images/2026/04/image-25.png 1109w" sizes="(min-width: 720px) 720px"></figure><p>Bret Fisher has been teaching Docker since before it was cool. His live sessions are a masterclass format that few channels match: real questions from real engineers, answered in real time with actual Docker and Kubernetes context - not scripted scenarios.</p><p><a href="https://youtube.com/playlist?list=PLX0bTycx8m-UhIXY2c4-7AXaEokaTdn6S&si=0dvEv9u-MDNKkjJd&ref=linuxhandbook.com" rel="noreferrer"><strong>Cloud Native DevOps and Docker Talk</strong></a> is a series popular for live shows with Q&amp;A and guests from the cloud native ecosystem.</p><p><strong>Who it's best for: </strong>Intermediate learners who have hit real-world problems they cannot find answers to in tutorials - Bret's live Q&amp;A sessions are specifically good for the gap between "tutorial worked" and "production is broken."</p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">🤔</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Why follow this channel?</strong></b><br>Docker live streams answer the questions that tutorials never cover. One of the most experienced Docker practitioners producing free content in 2026. Q&amp;A format surfaces real engineering problems, not artificial examples. Docker Swarm, Kubernetes networking, and production container issues are handled well.</div></div><p><strong>Verdict:</strong> Once you have real Docker and Kubernetes problems, not just tutorial exercises - Bret Fisher's Q&amp;A sessions are one of the most valuable resources available for free.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://www.youtube.com/@BretFisher?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">YouTube | Bret Fisher</a></div><h2 id="anton-putrabest-for-production-grade-aws-terraform-and-kubernetes-content">Anton Putra - Best for Production-Grade AWS, Terraform, and Kubernetes Content</h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/04/image-26.png" class="kg-image" alt="" loading="lazy" width="856" height="236" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-26.png 600w, https://linuxhandbook.com/content/images/2026/04/image-26.png 856w" sizes="(min-width: 720px) 720px"></figure><p>Anton Putra is the channel community calls "underrated gem" on a regular basis, and the description is accurate. The content is production-grade: real AWS architectures, Terraform modules that reflect actual engineering decisions, Kubernetes setups built the way teams actually build them, not simplified for beginners.</p><p><a href="https://youtube.com/playlist?list=PLiMWaCMwGJXnKY6XmeifEpjIfkWRo9v2l&si=BcDQce0YH4TrGjAx&ref=linuxhandbook.com" rel="noreferrer">AWS EKS Kubernetes Tutorial</a> is one of the recommended playlists for learning production-grade kubernetes learning. </p><p><strong>Who it's best for: </strong>Advanced learners and working engineers who want content that reflects production reality - AWS infrastructure, Terraform state management, Kubernetes cluster operations, observability, and CI/CD at scale.</p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">🤔</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Why follow this channel?</strong></b><br>One of the only free channels producing consistently production-accurate AWS + Terraform + K8s content. Terraform content goes beyond basics into module design and state management patterns. Real architectural decisions are explained, not just commands. Community repeatedly surfaces this channel as underappreciated relative to its quality.</div></div><p><strong>Verdict:</strong> If there is one underrated channel on this entire list, it is Anton Putra. The quality-to-subscriber-count ratio is remarkable. Subscribe before the rest of the internet catches up.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://www.youtube.com/@AntonPutra?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">YouTube | Anton Putra</a></div><h2 id="abhishekveeramallabest-for-devops-roadmap-real-projects-and-interview-preparation">Abhishek.Veeramalla - Best for DevOps Roadmap, Real Projects, and Interview Preparation</h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/04/image-27.png" class="kg-image" alt="" loading="lazy" width="1051" height="424" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-27.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-27.png 1000w, https://linuxhandbook.com/content/images/2026/04/image-27.png 1051w" sizes="(min-width: 720px) 720px"></figure><p>Abhishek Veeramalla has built one of the fastest-growing DevOps channels by doing something most channels avoid: being explicit about what you need to learn, in what order, and why - from the perspective of someone actively placing engineers into DevOps roles. The channel covers projects, roadmaps, and interview preparation with rare practical clarity.</p><p><a href="https://youtube.com/playlist?list=PLdpzxOOAlwvIc1TjTwopNSjRJkzES2ZXk&si=HGDf-igTTHuS_Wna&ref=linuxhandbook.com" rel="noreferrer">DevOps Engineer in 3 months</a> is the playlist many people follow to learn DevOps. He is also covering topics like AI assisted DevOps, Learning, DevSecOps and many more.</p><p><strong>Who it's best for: </strong>Beginners and intermediate learners who want a clear learning roadmap, hands-on project walkthroughs, and honest interview preparation content - especially those targeting their first or second DevOps role.</p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">🤔</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Why follow this channel?</strong></b><br>One of the clearest DevOps roadmap explanations available on YouTube. Project walkthroughs produce resume-ready artifacts. Interview prep content reflects what teams actually ask in 2026 DevOps interviews. Very popular in the global DevOps learner community, active comment sections.</div></div><p><strong>Verdict:</strong> If you are building toward a DevOps role and want a channel that connects learning to employment outcomes, Abhishek Veeramalla is one of the most practically useful channels on this list.</p><h2 id="jeff-geerlingbest-for-ansible-homelab-infrastructure-and-automation">Jeff Geerling - Best for Ansible, Homelab Infrastructure and Automation</h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/04/image-28.png" class="kg-image" alt="" loading="lazy" width="1051" height="424" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-28.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-28.png 1000w, https://linuxhandbook.com/content/images/2026/04/image-28.png 1051w" sizes="(min-width: 720px) 720px"></figure><p>Special mention for Jeff Geerling, the internet's go-to resource for Ansible, not as a passing topic, but as a deep, ongoing practice. Beyond Ansible, his channel covers Raspberry Pi infrastructure, homelab automation, and systems topics that most DevOps channels do not touch, all with a level of technical depth that reflects decades of hands-on systems work.</p><p><a href="https://youtube.com/playlist?list=PL2_OBreMn7FrsiSW0VDZjdq0xqUKkZYHT&si=CLkJE6mRZKdmgi4m&ref=linuxhandbook.com" rel="noreferrer">Homelab</a> playlist is one of the most popular ones viewers recommend for actual technical depth. <a href="https://youtube.com/playlist?list=PL2_OBreMn7FplshFCWYlaN2uS8et9RjNG&si=9UkOmVs2-xqKuUXt&ref=linuxhandbook.com" rel="noreferrer">Ansible</a> playlist contains all the content about Ansible, your one-stop solution for Ansible concepts.</p><p><strong>Who it's best for: </strong>Engineers who want to master Ansible for real infrastructure automation, homelab enthusiasts who want to take their setup to a professional engineering level, and anyone who wants content that goes deep on systems topics.</p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">🤔</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Why follow this channel?</strong></b><br>Books Ansible for DevOps and Ansible for Kubernetes are community standards; the channel extends that content. Homelab content bridges the gap between learning environments and production patterns. Honest, methodical approach, tests claims rigorously before publishing.</div></div><p><strong>Verdict: </strong>For Ansible specifically - Jeff Geerling is the answer, full stop. The channel is what trustworthy, technically serious free content looks like.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://www.youtube.com/@JeffGeerling?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">YouTube | Jeff Geerling</a></div><h2 id="faq">FAQ</h2><p>You will have some questions in mind, so let me answer some of those.<br><strong>Do I need to watch all these channels?</strong><br>No. Most people get structured value from 2-3 channels at a time. Start with one beginner-friendly channel (TechWorld with Nana, Kunal Kushwaha, or NetworkChuck), add a hands-on or cert-focused channel (KodeKloud), and a specialized one based on your current tool focus. Add the rest as your skill level grows.<br><br><strong>What is the recommended order for a complete beginner?</strong><br>A practical sequence: NetworkChuck (comfort with Linux and Docker basics) → TechWorld with Nana (structured DevOps roadmap) → KodeKloud (hands-on labs and cert prep) → DevOps Directive or That DevOps Guy (production depth). Use Fireship throughout as a quick reference when you encounter new concepts.<br><br><strong>Are these channels still actively updated in 2026?</strong><br>All channels on this list are actively publishing as of April 2026. Anton Putra and DevOps Directive publish less frequently but maintain consistent quality.<br><br><strong>Which channels are best specifically for Kubernetes?</strong><br>In rough order of depth: KubeSimplify (K8s-focused, breadth of ecosystem), That DevOps Guy (production realism),  KodeKloud (cert prep), Anton Putra (cluster operations, Terraform + K8s integration). TechWorld with Nana has solid K8s fundamentals for beginners.<br><br><strong>Are these channels useful for someone already working as a DevOps engineer?</strong><br>Yes - specifically That DevOps Guy, Anton Putra, Jeff Geerling, KubeSimplify, and Bret Fisher. These four channels produce content that reflects real production decisions rather than learner-facing introductions. The others are better suited to foundational or intermediate learning.<br><br><strong>Which channels cover cloud platforms (AWS, Azure, GCP) beyond just containers?</strong><br>Anton Putra (AWS + Terraform depth), TrainWithShubham and Abhishek.Veeramalla (AWS projects), freeCodeCamp (platform-agnostic full courses), TechWorld with Nana (all three major cloud providers covered). KodeKloud has certification prep for AWS, Azure, and GCP certifications.</p><h2 id="final-recommendation">Final recommendation</h2><p>If you are just starting out: <strong>TechWorld with Nana, trainwithshubham gives you the roadmap, KodeKloud gives you the practice.</strong> Those two together cover what most DevOps learners need through the intermediate stage.<br><br>If you are preparing for certifications: <strong>KodeKloud is the standard recommendation for a reason.</strong> The CKA and CKAD prep content is the best free version available.<br><br>If you want production-level depth: <strong>Anton Putra for infrastructure, That DevOps Guy for Kubernetes operations, Jeff Geerling for Ansible.</strong> These three channels give you what textbooks and tutorials usually skip.</p><p><strong>If you know of a channel that deserves to be on this list, don't wait and drop it in the comments below!</strong></p>]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Module 5 Practice Lab]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/elk-module5-practice-lab/</link>
                    <guid isPermaLink="false">69d4891cdf009b000197fd0f</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 17:07:56 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Module 4 Practice Lab]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/elk-module4-practice-lab/</link>
                    <guid isPermaLink="false">69cc958bdf009b000197f145</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 17:06:00 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Kibana for Debugging &amp; Exploration]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/kibana-debugging-exploration/</link>
                    <guid isPermaLink="false">69cb356adf009b000197ed31</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 17:05:13 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Security Basics]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/security-basics/</link>
                    <guid isPermaLink="false">69d33239df009b000197fbd9</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 17:00:04 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[ML Integration]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/ml-integration/</link>
                    <guid isPermaLink="false">69cf57b0df009b000197f961</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 16:55:10 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Scaling OpenSearch]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/scaling-opensearch/</link>
                    <guid isPermaLink="false">69cde496df009b000197f554</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 16:50:46 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Visualizations with Kibana]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/kibana-visualization/</link>
                    <guid isPermaLink="false">69c9dec8df009b000197e7af</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 16:42:47 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Kibana Basics]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/kibana-basics/</link>
                    <guid isPermaLink="false">69c60f40df009b000197df8d</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 16:39:51 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Module 3 Practice Lab]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/elk-module3-practice-lab/</link>
                    <guid isPermaLink="false">69c4ac0bdf009b000197db3e</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 16:27:23 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Searching &amp; Query DSL]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/searching-query-dsl/</link>
                    <guid isPermaLink="false">69c20e91df009b000197d589</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 16:25:44 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Indexing &amp; Mapping]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/indexing-mapping/</link>
                    <guid isPermaLink="false">69b3fde4df009b0001973ec6</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 16:24:24 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Why OpenSearch?]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/why-opensearch/</link>
                    <guid isPermaLink="false">69b3a377df009b0001973e33</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 16:21:29 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Module 2 Practice Lab]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/elk-module2-practice-lab/</link>
                    <guid isPermaLink="false">69b24adadf009b0001973be4</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 16:18:42 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Parsing &amp; Enriching Logs]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/parsing-enriching-logs/</link>
                    <guid isPermaLink="false">69b14d0cdf009b0001973a28</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 16:14:29 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Logstash Fundamentals]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/logstash-fundamentals/</link>
                    <guid isPermaLink="false">69b13975df009b00019739a5</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 16:05:51 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Module 1 Practice Lab]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/elk-module1-practice-lab/</link>
                    <guid isPermaLink="false">69b00f03df009b00019737de</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 16:04:37 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Your First OpenSearch Setup]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/opensearch-setup/</link>
                    <guid isPermaLink="false">699fccf0df009b0001971b14</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 16:02:49 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[ELK Stack Architecture]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/elk-stack-architecture/</link>
                    <guid isPermaLink="false">699f1d7bdf009b0001971988</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 15:52:16 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Introduction to ELK Stack]]></title>
                    <description><![CDATA[]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/elk-stack-intro/</link>
                    <guid isPermaLink="false">699efc9adf009b0001971895</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 15:49:46 +0530</pubDate>


                    <content:encoded><![CDATA[

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                                <span class="hidden first:inline">
                                This lesson is for paying subscribers only
                            </span>                           
                    <span class="hidden first:inline">
                        This post is for paying subscribers only
                    </span>  

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[The ELK Stack Handbook (With OpenSearch)]]></title>
                    <description><![CDATA[Stop SSH-ing into servers at 2 AM. Learn to centralize, search, and visualize logs across your entire infrastructure using fully open-source tools. ]]></description>
                    <link>https://linuxhandbook.com/courses/opensearch/</link>
                    <guid isPermaLink="false">6a0c328f0fd58500019fb02e</guid>

                        <category><![CDATA[OpenSearch]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 19 May 2026 15:36:43 +0530</pubDate>

                        <media:content url="https://linuxhandbook.com/content/images/2026/05/elk-stack-course.png" medium="image"/>

                    <content:encoded><![CDATA[<img src="https://linuxhandbook.com/content/images/2026/05/elk-stack-course.png" alt="The ELK Stack Handbook (With OpenSearch)"/> <p>You're debugging logs the hard way.</p><p>A single app on a single server is manageable. Ten servers? Fifty containers? Log files become a nightmare you can't grep your way out of.</p><p>Your current workflow at 2 AM:</p><pre><code>$ ssh prod-server-01
$ tail -f /var/log/app.log # nothing obvious
$ ssh prod-server-02
$ grep -r "error" /var/log/ | awk '{print $5}'
# 20 minutes later... still piecing it together</code></pre><p>The ELK Stack centralizes every log from every service into one searchable, visualizeable system. You go from <strong>reacting to incidents</strong> to <strong>proactively catching them before they happen.</strong></p><div class="kg-card kg-callout-card kg-callout-card-green"><div class="kg-callout-emoji">💡</div><div class="kg-callout-text">Why OpenSearch and not Elasticsearch?<br>In 2021, Elastic moved to a proprietary licence. OpenSearch, Amazon's Apache 2.0 fork, kept everything free: built-in TLS, SQL queries, anomaly detection, and alerting. We use OpenSearch throughout this course. The API is nearly identical to Elasticsearch, so everything you learn transfers directly.</div></div><h2 id="what-youll-learn">What you'll learn</h2><p>🏗️ <strong>ELK Architecture:</strong> How logs flow from your app through Logstash into OpenSearch and out to dashboards.</p><p>⚙️ <strong>Logstash Pipelines: </strong>Parse, filter, and enrich raw logs before they hit your index.</p><p>🔍 <strong>Query DSL &amp; Indexing:</strong>Search across millions of log events in milliseconds.</p><p>📊 <strong>Kibana Dashboards:</strong> Build visualisations that surface patterns raw log files never could.</p><p>🔒 <strong>Security &amp; Access Control:</strong> TLS, users, roles — features Elasticsearch charges for, free on OpenSearch.</p><p>🤖 <strong>ML-Powered Anomaly Detection: </strong>Let OpenSearch flag unusual patterns before your users notice them.</p><p>📈 <strong>Scaling OpenSearch:</strong> From a single node to a cluster that handles production traffic.</p><div class="kg-card kg-callout-card kg-callout-card-green"><div class="kg-callout-emoji">💡</div><div class="kg-callout-text">Each module has a practice lab. So you learn by doing it.</div></div><h2 id="who-this-course-is-for">Who this course is for?</h2><p>✅ <strong>Linux / DevOps Engineers: </strong>You manage servers and containers and want a proper observability stack without Elastic's licensing fees.</p><p>✅ <strong>Backend Developers: </strong>You deploy apps and want to understand what's actually happening in production when things break.</p><p>✅ <strong>SRE / Platform Engineers: </strong>You need centralised logging across microservices and want a self-hosted solution you fully control.</p><p>✅ <strong>Teams Migrating Off Elastic:</strong> You're moving away from paid tiers and want to get up to speed on OpenSearch fast.</p><h2 id="start-learning-today">Start learning today</h2><p>Stop reacting. Start observing.</p><p>Everything you need to build a production-grade observability stack. Free, open source, and ready to deploy.</p><p>Included with Linux Handbook Pro.</p>]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[I Stopped Using VMs for Demos, and I Run Linux in the Browser Now]]></title>
                    <description><![CDATA[Get a full Linux desktop experience inside a web browser, all thanks to containerization.]]></description>
                    <link>https://linuxhandbook.com/blog/webtop-instead-of-vms/</link>
                    <guid isPermaLink="false">699c3f7cdf009b0001969b13</guid>

                        <category><![CDATA[blog]]></category>

                        <dc:creator><![CDATA[Bhuwan Mishra]]></dc:creator>

                    <pubDate>Thu, 14 May 2026 12:55:19 +0530</pubDate>

                        <media:content url="https://linuxhandbook.com/content/images/2026/05/Reproducible-Linux-desktop-in-a-web-browser.png" medium="image"/>

                    <content:encoded><![CDATA[<img src="https://linuxhandbook.com/content/images/2026/05/Reproducible-Linux-desktop-in-a-web-browser.png" alt="I Stopped Using VMs for Demos, and I Run Linux in the Browser Now"/> <p>For years, my default setup for Linux demos was simple. Spin up a virtual machine, configure the environment, take a snapshot, and hope nothing breaks during the presentation.</p><p>In fact, my old demo setup was a collection of <a href="https://linuxhandbook.com/virtualization/" rel="noreferrer">virtual machines</a> I'd accumulated over the years. One for Docker demos, another for Kubernetes workshops, and a third one, a Debian box for shell scripting sessions. Each one sat on my SSD, consuming gigabytes of space and demanding occasional updates just to stay usable.</p><p>The breaking point came during a Kubernetes workshop I was running remotely. Screen sharing was already choppy because OBS, Chrome, and the VM were all fighting over the same CPU. Then the VM froze mid-demo during a kubectl walkthrough. The audience waited in silence. I got it working again, but the rhythm of the session never recovered.</p><p>That evening, I started looking for something better. I found Webtop, and it quietly replaced most of that VM setup.</p><h2 id="what-webtop-actually-is">What Webtop Actually Is</h2><p><a href="https://github.com/linuxserver/docker-webtop?ref=linuxhandbook.com">Webtop</a> is a Linux desktop environment packaged inside a Docker container and accessible entirely through a browser. You start the container, open a browser tab pointing to port 3000, and a full Linux desktop appears.</p><p><a href="https://www.linuxserver.io/?ref=linuxhandbook.com">LinuxServer.io</a> maintains this project. The same group provides container images for Jellyfin, Nextcloud, and dozens of other self-hosted tools.</p><p>What surprised me when I first launched it was how complete the experience felt. You get a real desktop environment, with the option to choose from XFCE, KDE, MATE, or others, depending on the image, with a terminal, file manager, and the ability to install packages normally through apt, dnf, or whatever the base distro uses. It behaves like a lightweight remote workstation that happens to live in your browser.</p><h2 id="getting-it-running">Getting It Running</h2><p>The quickest path is Docker Compose or <a href="https://linuxhandbook.com/courses/podman/podman-compose/" rel="noreferrer">Podman Compose</a>. Here's the configuration I started with:</p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">💡</div><div class="kg-callout-text">Podman is an alternative to Docker. It's rootless by default and daemonless. We have a <a href="https://linuxhandbook.com/courses/podman/" rel="noreferrer">free course on Podman</a>.</div></div><figure class="kg-card kg-code-card"><pre><code>services:
  webtop:
    image: lscr.io/linuxserver/webtop:ubuntu-xfce
    container_name: webtop
    security_opt:
      - seccomp:unconfined
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Asia/Kolkata
    volumes:
      - ./config:/config
    ports:
      - 3000:3000
    shm_size: "1gb"
    restart: unless-stopped</code></pre><figcaption><p><span style="white-space: pre-wrap;">Install WebTop Using Docker Compose</span></p></figcaption></figure><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/05/Screenshot-showing-webtop-running-using-podman.webp" class="kg-image" alt="Screenshot showing Webtop running with Podman" loading="lazy" width="1020" height="746" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/Screenshot-showing-webtop-running-using-podman.webp 600w, https://linuxhandbook.com/content/images/size/w1000/2026/05/Screenshot-showing-webtop-running-using-podman.webp 1000w, https://linuxhandbook.com/content/images/2026/05/Screenshot-showing-webtop-running-using-podman.webp 1020w" sizes="(min-width: 720px) 720px"></figure><p>Running <code>docker compose up -d</code> and then navigating to <code>http://[SERVER-IP]:3000, or http://localhost:3000</code> genuinely all it takes. The first boot took maybe 10 seconds before the desktop was usable.</p><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/05/Ubuntu-XFCE-running-in-browser-with-WebTop.webp" class="kg-image" alt="Ubuntu XFCE running in web browser with Webtop" loading="lazy" width="1477" height="863" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/Ubuntu-XFCE-running-in-browser-with-WebTop.webp 600w, https://linuxhandbook.com/content/images/size/w1000/2026/05/Ubuntu-XFCE-running-in-browser-with-WebTop.webp 1000w, https://linuxhandbook.com/content/images/2026/05/Ubuntu-XFCE-running-in-browser-with-WebTop.webp 1477w" sizes="(min-width: 720px) 720px"></figure><h2 id="choosing-the-right-image">Choosing the Right Image</h2><p>Webtop supports multiple distributions and desktop environments. The available combinations include Ubuntu, Debian, Fedora, Alpine, and Arch, each paired with desktop options like XFCE, KDE, and MATE. You can find all related tags on the project's GitHub page.</p><p>From my practical experience, XFCE consistently performs best for demos and workshops. It's lighter on resources, and the responsiveness during screen sharing is noticeably better than KDE. KDE is visually polished and worth running if you have headroom, but when your machine is also running OBS, a browser, and a video call simultaneously, the extra weight shows. </p><p>Alpine is worth knowing about if you need something extremely minimal. Its image is tiny and starts almost instantly, but package availability is limited compared to Ubuntu or Debian. For most demo scenarios, <code>ubuntu-xfce</code> hits the right balance of familiarity, package ecosystem, and performance.</p><h2 id="why-this-works-better-for-demos-than-vms">Why This Works Better for Demos Than VMs</h2><p>Recovery feels dramatically simpler. If I break something during a session, and with live demos, this happens. Restoring a VM means hunting for the right snapshot, waiting for it to load, and hoping the snapshot captured the right state. With Webtop, recovery looks like this:</p><pre><code class="language-bash">docker rm -f webtop
docker compose up -d</code></pre><p>That's it. A fresh environment in seconds. </p><p>Resource usage is another area where the difference is noticeable. A traditional Ubuntu VM with 8 GB allocated holds that memory whether it's being used or not. Containers are far more cooperative with the host system. After moving most of my demo environments to Webtop, I noticed the laptop fan spinning less during presentations and screen sharing becoming smoother. </p><h2 id="building-reproducible-demo-environments">Building Reproducible Demo Environments</h2><p>One thing I missed initially about VMs was the snapshot workflow. It's the ability to freeze a perfectly configured state and return to it. Webtop doesn't work that way, but the Docker approach is actually cleaner once you adjust your thinking.</p><p>Instead of snapshots, I build custom images. Here's an example Dockerfile for a Kubernetes demo environment:</p><pre><code class="language-dockerfile">FROM lscr.io/linuxserver/webtop:ubuntu-xfce

RUN apt-get update &amp;&amp; apt-get install -y \
    docker.io \
    kubectl \
    helm \
    neovim \
    tmux \
    htop \
    git</code></pre><p>Building that with <code>docker build -t demo-webtop .</code> produces an image I can launch anywhere, including on my homelab server, a VPS, a colleague's machine, and get an identical environment every time. </p><p>There are no multi-gigabyte VM disk files to transfer. The image is versioned, shareable, and rebuildable from scratch if needed. For a Kubernetes workshop I ran recently, I published the image so participants could run their own copy locally, which would have been considerably more complicated to coordinate with traditional VM images.</p><h2 id="accessing-it-remotely">Accessing It Remotely</h2><p>Browser-based access turned out to be more valuable than I expected. I can reach my Webtop environments from any device with a browser. That portability genuinely changed how I work while traveling.</p><p>For remote access, I put Webtop behind a reverse proxy with HTTPS and authentication. Running it directly to the internet without any protection is a bad idea. You'd be serving an unauthenticated Linux desktop to the world. Here is an example configuration for Caddy:</p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">💡</div><div class="kg-callout-text">Caddy is a web server written in Go. What separates it from Nginx or Apache is its automatic HTTPS behavior. The moment you point a domain at a server running Caddy and add it to the Caddyfile, Caddy contacts Let's Encrypt, obtains a certificate, and begins renewing it before it expires.</div></div><pre><code>webtop.lhb-tut.com {
    basicauth {
        bndev $2a$14$ebc7C6dlwFafmtZmfQ4vKe2ToQsTe6nWbV3k3ky6HAwLQr76u1l8m
    }

    reverse_proxy webtop:3000
}</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/05/Securing-Webtop-with-Caddy-basic-authentication.webp" class="kg-image" alt="" loading="lazy" width="1139" height="620" srcset="https://linuxhandbook.com/content/images/size/w600/2026/05/Securing-Webtop-with-Caddy-basic-authentication.webp 600w, https://linuxhandbook.com/content/images/size/w1000/2026/05/Securing-Webtop-with-Caddy-basic-authentication.webp 1000w, https://linuxhandbook.com/content/images/2026/05/Securing-Webtop-with-Caddy-basic-authentication.webp 1139w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Securing Webtop with Caddy basic authentication</span></figcaption></figure><p>My current setup uses Tailscale for network-level access control and Caddy for HTTPS termination. </p><p>Traefik and Cloudflare Tunnels are both solid alternatives, depending on your existing infrastructure. The key principle is the same regardless of tooling: don't expose port 3000 publicly without something in front of it.</p><h2 id="what-it-doesnt-handle-well">What It Doesn't Handle Well</h2><p>Webtop isn't a universal replacement for VMs, and overselling it would be dishonest. There are categories of work where I still reach for a traditional hypervisor without hesitation.</p><p>Kernel development and anything requiring full <code>systemd</code> Support needs a real VM. Container isolation isn't equivalent to hardware virtualization, and some low-level work simply requires full-stack virtualization and nested virtualization.</p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">💡</div><div class="kg-callout-text">With nested virtualization, a guest VM itself acts as a hypervisor and runs additional VMs inside it.</div></div><p>Low-level networking labs where you need to demonstrate VLAN behavior, DHCP servers, or raw packet analysis at the hardware interface level are also better suited to VMs, because container networking abstracts away exactly the things you're trying to show. Similarly, malware analysis and security sandboxing, where strong isolation is the whole point, shouldn't be done in a container environment.</p><p>GPU-accelerated workloads, video editing, and anything that genuinely needs graphics hardware won't be served well by Webtop. The rendering pipeline is inherently software-based, and the limitations are obvious in GPU-heavy applications. For terminal work, admin demos, and development environments, this is rarely relevant, but it's worth knowing upfront.</p><h2 id="practical-situations-where-it-shines">Practical Situations Where It Shines</h2><p>Training sessions where participants need identical environments are where Webtop provides the most obvious value. Instead of distributing VM images and debugging hypervisor incompatibilities across fifteen different laptop configurations, participants open a browser tab. That's a meaningful reduction in setup overhead and the inevitable "it doesn't work on my machine" troubleshooting.</p><p>The disposable workstation use case is one I didn't anticipate valuing, but I use it regularly. Sometimes I need a clean Linux environment to test a script, verify a package installation, or try something I don't want running on my main machine. Spinning up a Webtop container, doing the work, and removing it takes a minute. The equivalent with VMs took considerably longer and left behind disk state to clean up.</p><h2 id="final-thoughts">Final Thoughts</h2><p>I went into Webtop expecting curiosity. What I found was something that genuinely improved a recurring frustration in my workflow. The demo environment problem, maintaining multiple VMs, managing snapshots, and dealing with hypervisor overhead, completely went away.</p><p>The tradeoff with VMs isn't that containers are strictly superior. The point is that for the specific problem of running Linux environments for demos, workshops, and quick testing, the browser-based container approach solves the actual pain points without introducing new ones.</p><p>If you're maintaining a collection of demo VMs and spending time managing snapshots and debugging hypervisor issues, it's worth an hour to spin up Webtop and see how it feels. The barrier to trying it is low enough that the experiment costs almost nothing.</p>]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[This Self-hosted App Saved me $10 a Month]]></title>
                    <description><![CDATA[Once you start self-hosting, you start saving money.]]></description>
                    <link>https://linuxhandbook.com/blog/shlink-review/</link>
                    <guid isPermaLink="false">69f17c012dfed80001f7f645</guid>

                        <category><![CDATA[blog]]></category>
                        <category><![CDATA[Self Host]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Tue, 12 May 2026 13:09:43 +0530</pubDate>

                        <media:content url="https://linuxhandbook.com/content/images/2026/04/image-67-1.png" medium="image"/>

                    <content:encoded><![CDATA[<img src="https://linuxhandbook.com/content/images/2026/04/image-67-1.png" alt="This Self-hosted App Saved me $10 a Month"/> <p>If you've ever pasted a Bitly link into your marketing email and then checked your stats at the end of the month, only to find the analytics you actually wanted are locked behind a $10/month or $29/month plan, you've already felt the frustration that <strong>Shlink</strong> was built to solve.</p><p><strong>Shlink</strong> is a self-hosted, open-source URL shortener built in PHP. It gives you your own short domain (like <code>yourdomain.com/abc</code>), full visit tracking with geolocation, a REST API, a web dashboard, custom slugs, and more, all running on your own server. No per-link limits, no monthly bills, no vendor lock-in.</p><p>With nearly <strong>4.9k stars on GitHub</strong> and <strong>151 releases</strong> at the time of this writing, Shlink is not an experimental side project. It's a mature, actively maintained tool with real production deployments.</p><p><strong>Try it yourself</strong>: <a href="https://github.com/shlinkio/shlink?ref=linuxhandbook.com#self-hosted" rel="noreferrer">Shlink on GitHub</a> | <a href="https://shlink.io/?ref=linuxhandbook.com" rel="noreferrer">Official website</a></p><h2 id="what-is-shlink-exactly">What Is Shlink, Exactly?</h2><p>Let's start with the basics. Shlink (short for "short link") is a PHP application that you run on your own server. You point a short domain at it, and from that moment on, every link you create under that domain is yours, the data, the tracking, the slugs, everything.</p><p>Think of it as the backend engine that powers a URL shortener service. Shlink itself doesn't have a graphical UI built in, but it comes with two ways to control it out of the box:</p><p><strong>A command-line interface (CLI)</strong> - run <code>shlink short-url:create https://your-long-url.com</code> and get a short link back instantly.<br> <strong>A REST API</strong> - every operation available in the CLI is also exposed through a well-documented HTTP API, so you can integrate Shlink into any application or script.</p><p>And then, because most people don't want to manage links from a terminal forever, there's a <strong>separate web client</strong> called <a href="https://app.shlink.io/?ref=linuxhandbook.com" rel="noreferrer">Shlink Web Client</a>, a progressive web app that connects to your Shlink API and gives you a proper dashboard to manage everything visually.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/04/image-51.png" class="kg-image" alt="Shlink Web Client." loading="lazy" width="954" height="976" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-51.png 600w, https://linuxhandbook.com/content/images/2026/04/image-51.png 954w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Shlink Web Client.</span></figcaption></figure><p> You can use the hosted version at <code>app.shlink.io</code> (it talks directly to your own self-hosted server), or you can self-host it too. This separation of concerns - backend API + frontend client is a deliberate architectural choice that makes Shlink incredibly flexible for integrations.</p><h2 id="how-does-it-compare-to-bitly">How Does It Compare to Bitly?</h2><p>Before diving into the features, let's be honest about who Bitly is and what they charge.<br><br>Bitly's free tier limits you to <strong>50 links/month</strong>. <strong>2 QRs/month</strong> (yes, only two). Branded links with your custom domain require the <strong>Growth plan at ~$29/month</strong>. Detailed analytics and API access push you toward the <strong>Premium plan at ~$199/month</strong>. And the free tier obviously comes with a lot of ads.</p><p>Now here's the thing - Shlink gives you all of the following completely free, running on your own VPS:</p><table>
<thead>
<tr>
<th>Feature</th>
<th>Shlink (Self-Hosted)</th>
<th>Bitly Free</th>
<th>Bitly Growth (~$29/mo)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Custom domain</td>
<td>✅ Unlimited</td>
<td>2 pages</td>
<td>5 pages</td>
</tr>
<tr>
<td>Monthly links</td>
<td>✅ Unlimited</td>
<td>50 links</td>
<td>500 links</td>
</tr>
<tr>
<td>Visit analytics</td>
<td>✅ Full detail</td>
<td>❌</td>
<td>Upto 4 months data</td>
</tr>
<tr>
<td>Geolocation tracking</td>
<td>✅</td>
<td>❌</td>
<td>✅</td>
</tr>
<tr>
<td>REST API access</td>
<td>✅ Full</td>
<td>❌</td>
<td>✅</td>
</tr>
<tr>
<td>QR code generation</td>
<td>❌ handled by web client</td>
<td>❌</td>
<td>✅</td>
</tr>
<tr>
<td>Data ownership</td>
<td>✅ 100% yours</td>
<td>❌ Bitly's servers</td>
<td>❌ Bitly's servers</td>
</tr>
</tbody>
</table>
<p>The trade-off is real: Bitly is plug-and-play, while Shlink requires a server to run on and some initial setup time. But if you already have a VPS or a home server, the case for Shlink is very strong.</p><p><strong>The $10/month savings angle</strong>: If you're on even the cheapest Bitly paid plan ($10/month Core) just for the extra links, you're paying $120/year for something you could own outright. The math is obvious.</p><h2 id="getting-shlink-running">Getting Shlink Running</h2><p>The fastest way to get Shlink up is with Docker. The official image is published on both Docker Hub and GitHub Container Registry, and it handles all PHP dependencies internally.</p><p><strong>Quick Setup:</strong></p><pre><code class="language-yaml">services:
  shlink:
    image: shlinkio/shlink:stable
    container_name: shlink_review
    restart: unless-stopped
    ports:
      - "8888:8080"
    environment:
      # The domain Shlink will use to build short URLs
      DEFAULT_DOMAIN: localhost:8888
      # HTTP only for local testing (no SSL cert needed)
      IS_HTTPS_ENABLED: "false"
      # GeoLite2 key for geolocation — get a free one at https://www.maxmind.com/en/geolite2/signup
      # Leave as REPLACE_ME to start without geolocation (everything else works fine)
      GEOLITE_LICENSE_KEY: "REPLACE_ME"
      # Use SQLite — no external DB container needed for local testing
      DB_DRIVER: "sqlite"
</code></pre><p>You can use this compose and have to replace the placeholder for the Geolite key with you key. After setting up you will be able to see the container running.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/04/image-52.png" class="kg-image" alt="Shlink Container running." loading="lazy" width="901" height="146" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-52.png 600w, https://linuxhandbook.com/content/images/2026/04/image-52.png 901w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Shlink Container running.</span></figcaption></figure><p>There is a full list of commands for the CLI interaction of the shlink at the <a href="https://shlink.io/documentation/command-line-interface/entry-point/?ref=linuxhandbook.com" rel="noreferrer">official documentation</a>.</p><h2 id="the-web-client-your-dashboard-for-everything">The Web Client: Your Dashboard for Everything</h2><p>Once your Shlink backend is running, you connect it to the <a href="https://app.shlink.io/?ref=linuxhandbook.com" rel="noreferrer">Shlink Web Client</a>. This is a <strong>Progressive Web App (PWA),</strong> meaning you can install it on your desktop or phone like a native app, and it works entirely in your browser.</p><p>Here's the key thing to understand: the web client <strong>never stores your link data</strong>. It just communicates with your own Shlink server via the REST API. The hosted version at <code>app.shlink.io</code> is simply a UI; all your data stays on your server.</p><p>Let's setup web-client to see how efficient it is to manage your server through a GUI.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/04/image-53.png" class="kg-image" alt="Create server setup on shlink web-client." loading="lazy" width="947" height="828" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-53.png 600w, https://linuxhandbook.com/content/images/2026/04/image-53.png 947w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Create server setup on shlink web-client.</span></figcaption></figure><p>On this, you need to set up the name, URL and the API key generated by you through running the container. You can run the command:</p><pre><code class="language-bash">docker exec -it shlink_review shlink api-key:generate</code></pre><p>after configuring the server will be connected in 30-40 seconds.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/04/image-54.png" class="kg-image" alt="Self-Hosted server connected to web-client" loading="lazy" width="1920" height="765" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-54.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-54.png 1000w, https://linuxhandbook.com/content/images/size/w1600/2026/04/image-54.png 1600w, https://linuxhandbook.com/content/images/2026/04/image-54.png 1920w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Self-Hosted server connected to web-client</span></figcaption></figure><p>In this you can create short URLs by clicking on Create short URL:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/04/image-55.png" class="kg-image" alt="Shlink in action." loading="lazy" width="1773" height="996" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-55.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-55.png 1000w, https://linuxhandbook.com/content/images/size/w1600/2026/04/image-55.png 1600w, https://linuxhandbook.com/content/images/2026/04/image-55.png 1773w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Shlink in action.</span></figcaption></figure><p>After setting up, the short links are activated and you get the analytics like visits, oprhan visits, short URL, tags, etc.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/04/image-56.png" class="kg-image" alt="Hompage of shlink." loading="lazy" width="1773" height="996" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-56.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-56.png 1000w, https://linuxhandbook.com/content/images/size/w1600/2026/04/image-56.png 1600w, https://linuxhandbook.com/content/images/2026/04/image-56.png 1773w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Hompage of shlink.</span></figcaption></figure><p>I was simply able to redirect to the main URLs from the short URL generated by shlink, it was consistent and no complex configurations for making a shortened URL.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/04/image-57.png" class="kg-image" alt="Stats shown in shlink for every URL." loading="lazy" width="1773" height="996" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-57.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-57.png 1000w, https://linuxhandbook.com/content/images/size/w1600/2026/04/image-57.png 1600w, https://linuxhandbook.com/content/images/2026/04/image-57.png 1773w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Stats shown in shlink for every URL.</span></figcaption></figure><p>You get detailed stats according to the days, visits, visualizations, location, context, and exporting options for the stats report.</p><p><strong>Don't want to manage a server?</strong> Shlink is available on <a href="https://www.pikapods.com/pods?run=shlink&ref=linuxhandbook.com" rel="noreferrer">PikaPods</a>, which handles all the hosting for you with a one-click setup. Pricing starts at ~$2.3/ per month, and Shlink gets a portion of the revenue to fund the project.</p><h2 id="core-features-worth-knowing-about">Core Features Worth Knowing About</h2><h3 id="custom-slugs-and-multi-segment-slugs">Custom Slugs and Multi-Segment Slugs</h3><p>By default, Shlink auto-generates short codes like <code>s.yourdomain.com/abc123</code>. But you can set your own human-readable slug: <code>s.yourdomain.com/linux-guide</code> or even multi-segment slugs like <code>s.yourdomain.com/articles/linux-guide</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/04/image-58.png" class="kg-image" alt="Custom slug feature of shlink." loading="lazy" width="691" height="626" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-58.png 600w, https://linuxhandbook.com/content/images/2026/04/image-58.png 691w"><figcaption><span style="white-space: pre-wrap;">Custom slug feature of shlink.</span></figcaption></figure><h3 id="visit-tracking-and-analytics">Visit Tracking and Analytics</h3><p>Every click on a short URL gets tracked. Shlink records: <strong>Date and time</strong> of the visit, <strong>Country, region, and city</strong>(via MaxMind GeoLite2 geolocation), <strong>Device type</strong> (desktop/mobile/tablet), <strong>Browser and OS,</strong> <strong>Referrer</strong>(where the visitor came from).<br>IP addresses are <strong>anonymized by default</strong>, which is what makes Shlink GDPR-compliant out of the box.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/04/image-59.png" class="kg-image" alt="Analytics provided by shlink." loading="lazy" width="1661" height="909" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-59.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-59.png 1000w, https://linuxhandbook.com/content/images/size/w1600/2026/04/image-59.png 1600w, https://linuxhandbook.com/content/images/2026/04/image-59.png 1661w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Analytics provided by shlink.</span></figcaption></figure><h3 id="limited-access-and-expiry">Limited Access and Expiry</h3><p>This feature alone is worth highlighting. You can set a short URL to: <strong>Expire after a certain date</strong> - perfect for time-limited promotions or event links, <strong>Expire after a maximum number of visits</strong> - create a link that only the first 100 people can use, and after that it shows a 404.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/04/image-60.png" class="kg-image" alt="Limited Access and Expiry provided by shlink." loading="lazy" width="674" height="318" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-60.png 600w, https://linuxhandbook.com/content/images/2026/04/image-60.png 674w"><figcaption><span style="white-space: pre-wrap;">Limited Access and Expiry provided by shlink.</span></figcaption></figure><h3 id="dynamic-redirects-rule-based">Dynamic Redirects (Rule-Based)</h3><p>Here's where Shlink goes beyond being a "simple" URL shortener. You can set up rules that redirect visitors to different destinations based on: <strong>Geolocation</strong>, <strong>Device type</strong>, <strong>Language</strong> and <strong>OS.</strong> This turns a short link into a smart redirect engine, which is something you'd normally need a dedicated link management platform to do.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/04/image-61.png" class="kg-image" alt="Dynamic redirects for the Short URLs." loading="lazy" width="1599" height="821" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-61.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-61.png 1000w, https://linuxhandbook.com/content/images/2026/04/image-61.png 1599w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Dynamic redirects for the Short URLs.</span></figcaption></figure><h2 id="the-rest-api-and-cli-for-when-you-want-to-automate">The REST API and CLI: For When You Want to Automate</h2><p>Shlink's API is well-documented at <a href="https://api-spec.shlink.io/?ref=linuxhandbook.com" rel="noreferrer">api-spec.shlink.io</a>, with an interactive sandbox where you can try every endpoint. Every operation you can do from the web client is available via the API and a few things (like API key management) are only available from the CLI or API, not the web client.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/04/image-63.png" class="kg-image" alt="REST API spec documentation for shlink." loading="lazy" width="925" height="966" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-63.png 600w, https://linuxhandbook.com/content/images/2026/04/image-63.png 925w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">REST API spec documentation for shlink.</span></figcaption></figure><p>Some examples of what you can do with the CLI inside the Docker container:</p><pre><code class="language-bash"># Create a short URL with a custom slug
docker exec my_shlink shlink short-url:create https://itsfoss.com/linux-guide --custom-slug linux-guide

# List all short URLs
docker exec my_shlink shlink short-url:list

# View visit stats for a specific short URL
docker exec my_shlink shlink short-url:visits linux-guide

# Generate a new API key with a name
docker exec my_shlink shlink api-key:generate --name "automation-script"</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/04/image-64.png" class="kg-image" alt="Shlink CLI in action." loading="lazy" width="1199" height="326" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-64.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-64.png 1000w, https://linuxhandbook.com/content/images/2026/04/image-64.png 1199w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Shlink CLI in action.</span></figcaption></figure><p>The API makes Shlink a building block for larger systems. If you run a website, you can integrate Shlink to automatically generate short links for every new article you publish. If you send newsletters, you can use it to wrap all your links and get click tracking without any third-party service touching your subscriber data.</p><h2 id="importing-from-bitly-and-others">Importing From Bitly (and Others)</h2><p>If you're currently using Bitly and want to migrate, Shlink has a built-in importer. It can import existing short URLs from Bitly, YOURLS, CSV, Shlink, and kutt. </p><p>Import is performed from the command line, by running the&nbsp;<code>short-urls:import</code>&nbsp;command.</p><p>This command will guide you through the import process, asking you to provide the source from which you want to import, together with all required information for this process to succeed. The import preserves the original short codes where possible, so your existing links don't break after migration.</p><p>You can always refer to <a href="https://shlink.io/documentation/advanced/import-short-urls/?ref=linuxhandbook.com" rel="noreferrer">official documentation</a> for specific importing steps from different platforms.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/04/image-65.png" class="kg-image" alt="Importing URLs form Bitly." loading="lazy" width="928" height="201" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-65.png 600w, https://linuxhandbook.com/content/images/2026/04/image-65.png 928w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Importing URLs form Bitly.</span></figcaption></figure><h2 id="what-shlink-doesnt-do-yet">What Shlink Doesn't Do Yet</h2><p><strong>There's no built-in multi-user authentication</strong>. Shlink uses API keys for access control; there's no "create an account with a username and password" UI. If you want multiple people to manage links, you create separate API keys for them. This works, but it's not the polished team management experience you'd get from a SaaS product.<br><br><strong>The setup requires some technical comfort.</strong> You need to understand Docker (or PHP server setup), DNS configuration, and reverse proxy configuration to get Shlink running with HTTPS and custom domains. It's not hard if you've done it before, but it's not a one-click install for beginners either.<br><br><strong>The GeoLite2 license key requirement is a minor friction point.</strong> MaxMind's license key is free, but you have to register and include it manually. Without it, geolocation doesn't work. It's a licensing compliance thing, not a Shlink design flaw, but it adds a step.<br><br><strong>Real-time updates need extra infrastructure.</strong> Shlink supports real-time visit notifications through Mercure or RabbitMQ, but you have to set those up separately. If you don't, the web client just refreshes on a polling interval, which works fine for most people.</p><h2 id="what-works-really-well">What Works Really Well </h2><p><strong>The custom domain support is genuinely good.</strong> Most self-hosted shorteners make you pick one domain. Shlink's multi-domain support means you can run personal, professional, and team link shorteners all from one installation.<br><br><strong>The analytics are far better than Bitly's free tier.</strong> Country, device, browser, referrer - you get all of this without paying anything beyond your server cost.<br><br><strong>The API is excellent.</strong> Every feature is accessible via the API with consistent, well-designed endpoints. If you want to integrate URL shortening into your workflow or build tooling around it, Shlink is designed for this use case.<br><br><strong>The Docker image is production-ready.</strong> Non-root user execution (since v4.0.0), multi-architecture support (amd64 and arm64), proper versioning with <code>stable</code> and tags, it's thoughtfully packaged.</p><p><strong>151 releases and 4.9k stars.</strong> This is not a tool that gets abandoned after six months. Shlink has been actively developed since 2016, maintained by <a href="https://www.alejandrocelaya.com/?ref=linuxhandbook.com" rel="noreferrer">Alejandro Celaya</a>, and has a real community around it.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/04/image-66.png" class="kg-image" alt="Github Page of shlink." loading="lazy" width="1276" height="848" srcset="https://linuxhandbook.com/content/images/size/w600/2026/04/image-66.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/04/image-66.png 1000w, https://linuxhandbook.com/content/images/2026/04/image-66.png 1276w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Github Page of shlink.</span></figcaption></figure><h2 id="conclusion">Conclusion</h2><p>Shlink does one thing and it does it very well: it gives you a professional-grade URL shortener that you actually control. The custom domain support, visit analytics, dynamic redirects, and REST API together make it a legitimate replacement for Bitly across most use cases, without the monthly subscription.<br><br>The setup does require some server knowledge, but it's well within reach for anyone who has deployed a Docker application before. The documentation is thorough, the project is actively maintained, and if you don't want to manage a server at all, PikaPods makes it a one-click deployment.<br><br>If you're currently paying Bitly $10–$30 a month for features that Shlink provides for free, this is worth a serious look.</p>]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[I Tried Self-Hosting This Authentication Project from CNCF (And It Was a Humbling Experience)]]></title>
                    <description><![CDATA[I found setting up Keycloak challengeing. It was a good challenge and a learning experience that I share with you.]]></description>
                    <link>https://linuxhandbook.com/blog/keycloak-experiment/</link>
                    <guid isPermaLink="false">69945e40f7d3c300011c4d8a</guid>

                        <category><![CDATA[blog]]></category>
                        <category><![CDATA[Self Hosting Tutorials]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Mon, 20 Apr 2026 16:08:06 +0530</pubDate>

                        <media:content url="https://linuxhandbook.com/content/images/2026/02/keycloak.png" medium="image"/>

                    <content:encoded><![CDATA[<img src="https://linuxhandbook.com/content/images/2026/02/keycloak.png" alt="I Tried Self-Hosting This Authentication Project from CNCF (And It Was a Humbling Experience)"/> <p>In a world where authentication services charge per user and lock you into their ecosystem, Keycloak offers something rare: enterprise-grade identity management that you can run on your own infrastructure, completely free. No vendor lock-in, no monthly bills, no user limits.</p><p>After spending several days setting up <a href="https://github.com/keycloak/keycloak?ref=linuxhandbook.com">Keycloak</a>, integrating it with Portainer via OAuth, configuring social login with GitHub, and wrestling with the documentation gaps, here's what you need to know before diving in.</p><h2 id="what-is-keycloak">What is Keycloak?</h2><p>Keycloak is an open-source Identity and Access Management (IAM) solution that handles authentication and authorization for modern applications. Think of it as a self-hosted alternative to Auth0, Okta, or AWS Cognito, but without the per-user pricing or vendor lock-in.</p><p>It's a <a href="https://www.cncf.io/?ref=linuxhandbook.com">CNCF</a> (Cloud Native Computing Foundation) project under the Apache 2.0 license, which means it's backed by a strong community and actively developed. It includes featuers like Single Sign-On (SSO), Social login (GitHub, Google, Gitlab, etc.), OAuth 2.0 and OpenID Connect (OIDC) and many more.</p><p>The selling point isn't just the feature list - it's that you get all of this without paying per user or worrying about what happens if the vendor shuts down.</p><h2 id="the-setup-challenge">The Setup Challenge</h2><p>Yes, I am mentioning it as a challenge because in the official documentation, there is no proper <code>docker-compose</code> file to set up the whole database with Keycloak. You're left piecing together environment variables from different documentation pages. After many trial-and-error attempts, here's my custom <code>docker-compose.yml</code> that actually works:</p><pre><code class="language-YAML">services:
  postgresql:
    image: postgres:16
    container_name: keycloak_db
    environment:
      POSTGRES_USER: keycloak
      POSTGRES_DB: keycloak
      POSTGRES_PASSWORD: SUPERsecret
    volumes:
      - ./postgres_data:/var/lib/postgresql/data
    networks:
      - keycloak

  keycloak:
    image: quay.io/keycloak/keycloak:26.5.3
    container_name: keycloak
    depends_on:
      - postgresql
    command: start-dev
    environment:
      - KC_BOOTSTRAP_ADMIN_USERNAME=admin
      - KC_BOOTSTRAP_ADMIN_PASSWORD=admin
      - KC_DB=postgres
      - KC_DB_URL=jdbc:postgresql://postgresql:5432/keycloak
      - KC_DB_USERNAME=keycloak
      - KC_DB_PASSWORD=SUPERsecret
    ports:
      - "8081:8080"
    networks:
      - keycloak

networks:
  keycloak:
</code></pre><p>In this,<strong> </strong>we have mentioned PostgreSQL container for the database, <code>./postgres_data</code> ensures your users and configurations survive container restarts and stay persistent using volumes, <code>KC_BOOTSTRAP_ADMIN_USERNAME</code>&nbsp;and&nbsp;<code>KC_BOOTSTRAP_ADMIN_PASSWORD</code>&nbsp;create the initial admin account, port mapping is done as <code>8081:8080</code>&nbsp;because port 8080 is often already taken on development machines, a <strong>it, </strong>custom network <code>keycloak</code> ensures Keycloak and PostgreSQL can communicate by service name.</p><p>Save the above file as docker-compose.yml and run the following command: </p><pre><code class="language-bash">mkdir -p keycloak &amp;&amp; cd keycloak
# Save the compose file above
docker-compose up -d
</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/02/image-29.png" class="kg-image" alt="Keycloak running as a container." loading="lazy" width="1149" height="450" srcset="https://linuxhandbook.com/content/images/size/w600/2026/02/image-29.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/02/image-29.png 1000w, https://linuxhandbook.com/content/images/2026/02/image-29.png 1149w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Keycloak running as a container.</span></figcaption></figure><p>Within 30-60 seconds, you'll have Keycloak running at&nbsp;<code>http://localhost:8081</code>.</p><h2 id="initial-configuration">Initial Configuration</h2><p>When you first access Keycloak, you'll land on the admin console login page. Use the credentials you set in&nbsp;<code>username</code>&nbsp;and <code>password</code>&nbsp;(in this case,&nbsp;<code>admin</code>&nbsp;/&nbsp;<code>admin</code>).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/02/Screenshot-from-2026-02-17-10-37-55.png" class="kg-image" alt="Initial Login Page." loading="lazy" width="1909" height="992" srcset="https://linuxhandbook.com/content/images/size/w600/2026/02/Screenshot-from-2026-02-17-10-37-55.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/02/Screenshot-from-2026-02-17-10-37-55.png 1000w, https://linuxhandbook.com/content/images/size/w1600/2026/02/Screenshot-from-2026-02-17-10-37-55.png 1600w, https://linuxhandbook.com/content/images/2026/02/Screenshot-from-2026-02-17-10-37-55.png 1909w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Initial Login Page.</span></figcaption></figure><p>Once logged in, you'll see the&nbsp;<strong>master realm</strong>. Realms in Keycloak are isolated spaces for managing users, clients, and authentication policies. The master realm is for administrative purposes only - you can create a separate realm for different applications.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/02/image-30.png" class="kg-image" alt="Managing realms in keycloak." loading="lazy" width="1920" height="937" srcset="https://linuxhandbook.com/content/images/size/w600/2026/02/image-30.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/02/image-30.png 1000w, https://linuxhandbook.com/content/images/size/w1600/2026/02/image-30.png 1600w, https://linuxhandbook.com/content/images/2026/02/image-30.png 1920w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Managing realms in keycloak.</span></figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/02/image-38.png" class="kg-image" alt="Authentication and Users in keycloak." loading="lazy" width="875" height="707" srcset="https://linuxhandbook.com/content/images/size/w600/2026/02/image-38.png 600w, https://linuxhandbook.com/content/images/2026/02/image-38.png 875w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Authentication and Users in keycloak.</span></figcaption></figure><p>You can add Users, Groups, Events, etc., for your specific realm. You can add an email and verify it, <strong> </strong>which can be used later to add users and authenticate them.</p><h2 id="real-world-test-portainer-oauth-integration">Real-World Test: Portainer OAuth Integration</h2><p>The best way to understand Keycloak is to integrate it with a real application. Portainer (a Docker management UI) supports OAuth authentication, making it a perfect test case.</p><p>For this purpose, I have my Portainer running on port 9000, which shows me all the containers, images, networks, services, etc., running on my host machine.</p><p>You can run Portainer on your own by using the following command:</p><pre><code class="language-bash">docker run -d -p 9000:9000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:lts</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/02/image-31.png" class="kg-image" alt="Self hosted Portainer running on localhost:9000. " loading="lazy" width="1375" height="1018" srcset="https://linuxhandbook.com/content/images/size/w600/2026/02/image-31.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/02/image-31.png 1000w, https://linuxhandbook.com/content/images/2026/02/image-31.png 1375w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Self hosted Portainer running on localhost:9000. </span></figcaption></figure><p>You will see the Portainer running on <code>localhost:9000</code> and showing all the results of your Docker stuff.<br><br><strong>Creating an OAuth Client: </strong>For this, navigate to your <strong>realm,</strong> then open&nbsp;<strong>Clients </strong>and click on <strong>create client</strong>, here you need to paste the following so that it successfully connects to the portainer running on the system.</p><pre><code class="language-Text">Client ID: portainer
Client authentication: ON (this generates a client secret)
Valid redirect URIs: http://localhost:9000/*
Valid post logout redirect URIs: http://localhost:9000/*
Web origins: http://localhost:9000</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/02/image-32.png" class="kg-image" alt="Client configurations in keycloak." loading="lazy" width="1547" height="946" srcset="https://linuxhandbook.com/content/images/size/w600/2026/02/image-32.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/02/image-32.png 1000w, https://linuxhandbook.com/content/images/2026/02/image-32.png 1547w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Client configurations in keycloak.</span></figcaption></figure><p>Save the client, then go to the&nbsp;<strong>Credentials</strong>&nbsp;tab and copy the&nbsp;<strong>Client Secret</strong>. You'll need this for Portainer.</p><p><strong>Configuring Portainer: </strong>In Portainer, go to&nbsp;<strong>Settings,</strong>&nbsp;then&nbsp;<strong>Authentication,</strong>,<strong> </strong>navigate to &nbsp;<strong>OAuth</strong>, where you need to configure some things inorder to connect to the client created at keycloak and the portainer Oauth.</p><pre><code class="language-Text">Client ID: portainer
Client secret: (paste the secret from Keycloak)
Authorization URL: http://localhost:8081/realms/myrealm/protocol/openid-connect/auth
Access token URL: http://localhost:8081/realms/myrealm/protocol/openid-connect/token
Resource URL: http://localhost:8081/realms/myrealm/protocol/openid-connect/userinfo
Redirect URL: http://localhost:9000/
User identifier: email
Scopes: email openid profile</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/02/image-33.png" class="kg-image" alt="Custom auth support in Portainer." loading="lazy" width="1911" height="941" srcset="https://linuxhandbook.com/content/images/size/w600/2026/02/image-33.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/02/image-33.png 1000w, https://linuxhandbook.com/content/images/size/w1600/2026/02/image-33.png 1600w, https://linuxhandbook.com/content/images/2026/02/image-33.png 1911w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Custom auth support in Portainer.</span></figcaption></figure><p>Then save the configurations and you are ready to test your Keycloak authentication. </p><p><strong>Testing the flow: </strong>The actual test is to see if we can log out from the Portainer and see the login with OAuth, and as expected, after logging out from the portainer the login with OAuth button is visible in the Portainer.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/02/Screenshot-from-2026-02-17-11-54-45.png" class="kg-image" alt="Keycloak OAuth in action." loading="lazy" width="1920" height="975" srcset="https://linuxhandbook.com/content/images/size/w600/2026/02/Screenshot-from-2026-02-17-11-54-45.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/02/Screenshot-from-2026-02-17-11-54-45.png 1000w, https://linuxhandbook.com/content/images/size/w1600/2026/02/Screenshot-from-2026-02-17-11-54-45.png 1600w, https://linuxhandbook.com/content/images/2026/02/Screenshot-from-2026-02-17-11-54-45.png 1920w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Keycloak OAuth in action.</span></figcaption></figure><p>which redirects to the Keycloak sign-in page and if you have added the same user in the Keycloak with an active login session, then you will be able to log in to Portainer and be redirected to the homescreen with that user; the entire process happens seamlessly.</p><p>To be honest, as it is seamless in execution, I found it very complex and time consuming to configure the proper urls, as for the self hosted websites and architechture you need to configure the urls correctly handling the routes perfectly, otherwise there are many errors, like not redirecting to the correct destination, OAuth failed, url does not contains needed parameter, etc. that I faced during the configuration. </p><h2 id="social-login-integration">Social Login Integration</h2><p>One of Keycloak's standout features is built-in support for social login providers. Adding GitHub authentication takes about 5 minutes. I tested with GitHub Identity Provider.</p><p><strong>Setting Up: </strong> In Keycloak, you can have options to add an <strong>Identity Provider; </strong>I have taken GitHub for example. There is a list of options for the Identity provider, you can choose any as per your need. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/02/image-34.png" class="kg-image" alt="Identity providers supported in keycloak." loading="lazy" width="349" height="666"><figcaption><span style="white-space: pre-wrap;">Identity providers supported in keycloak.</span></figcaption></figure><p>For GitHub, you need to go to your GitHub Profile → Settings → Developer settings → OAuth Apps → New OAuth App and set the Auth callback URL as <code>http://localhost:8081/realms/master/broker/github/endpoint</code></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/02/image-35.png" class="kg-image" alt="Setting OAuth for Github through keycloak." loading="lazy" width="808" height="912" srcset="https://linuxhandbook.com/content/images/size/w600/2026/02/image-35.png 600w, https://linuxhandbook.com/content/images/2026/02/image-35.png 808w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Setting OAuth for Github through keycloak.</span></figcaption></figure><p>Copy the&nbsp;<strong>Client ID</strong>&nbsp;and&nbsp;<strong>Client Secret</strong>&nbsp;from GitHub into Keycloak and save the identity provider configuration.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/02/image-36.png" class="kg-image" alt="Settings for Identity Provider with credentials." loading="lazy" width="956" height="738" srcset="https://linuxhandbook.com/content/images/size/w600/2026/02/image-36.png 600w, https://linuxhandbook.com/content/images/2026/02/image-36.png 956w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Settings for Identity Provider with credentials.</span></figcaption></figure><p>When a user logs in via GitHub for the first time, Keycloak automatically creates a user account and links it to their GitHub identity. You can see linked accounts in the user's account console.</p><p>After doing this, I was able to get the expected GitHub Identity Provider in the login window.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/02/Screenshot-from-2026-02-17-11-15-44.png" class="kg-image" alt="GitHub added as Sign In option in keycloak." loading="lazy" width="1920" height="975" srcset="https://linuxhandbook.com/content/images/size/w600/2026/02/Screenshot-from-2026-02-17-11-15-44.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/02/Screenshot-from-2026-02-17-11-15-44.png 1000w, https://linuxhandbook.com/content/images/size/w1600/2026/02/Screenshot-from-2026-02-17-11-15-44.png 1600w, https://linuxhandbook.com/content/images/2026/02/Screenshot-from-2026-02-17-11-15-44.png 1920w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">GitHub added as Sign In option in keycloak.</span></figcaption></figure><p>This same process works for Google, Facebook, Twitter, Microsoft, and 20+ other providers. You can even enable multiple social logins simultaneously, giving users the choice.</p><h2 id="what-works-really-well-in-keycloak">What Works Really Well In Keycloak</h2><p>Multi-factor authentication, social login, user federation with LDAP/Active Directory and fine-grained authorization policies - features that cost hundreds of dollars per month on SaaS platforms are all included. No per-user pricing, no feature gates. Which gives <strong>Enterprise Features for free</strong>.</p><p>Keycloak implements OAuth 2.0, OpenID Connect, and SAML 2.0 correctly. This means it works with virtually any modern application that supports these protocols. You're not locked into proprietary APIs.</p><p>You can customize login themes to match your brand, create custom authentication flows (e.g., require email verification before MFA), and even write custom extensions in Java. The level of control is unmatched, giving <strong>Flexibility and customization</strong>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/02/image-39.png" class="kg-image" alt="Customization options in keycloak." loading="lazy" width="957" height="561" srcset="https://linuxhandbook.com/content/images/size/w600/2026/02/image-39.png 600w, https://linuxhandbook.com/content/images/2026/02/image-39.png 957w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Customization options in keycloak.</span></figcaption></figure><p>As a CNCF project with backing from Red Hat, Keycloak receives regular updates, security patches, and new features. The community is active, and GitHub issues get responses signifying <strong>active development</strong>.</p><p>The experience of testing the Keycloak was seamless in terms of <strong>performance</strong>.</p><h2 id="where-keycloak-falls-short">Where Keycloak Falls Short</h2><p>No tool is perfect, and Keycloak has some significant limitations you should know about upfront.</p><p><strong>Documentation gaps.</strong>&nbsp;The official docs are comprehensive but scattered. The biggest pain point: there's no official <code>docker-compose</code> example that includes a production database. You're left piecing together environment variables from different pages. This is why the custom <code>docker-compose</code> file above took trial and error to get right.</p><p><strong>Steep learning curve.</strong>&nbsp;Keycloak has a lot of concepts: realms, clients, client scopes, protocol mappers, identity providers, user federation, and authentication flows. For someone new to IAM, the admin console can be overwhelming. Expect to spend a few days just understanding the terminology.</p><p><strong>Scalability and Multi-Tenancy.</strong>&nbsp;Keycloak can struggle with a high number of realms (multi-tenant environments), experiencing performance degradation in the Admin Console and realm management. While newer versions are improving,, earlier and default configurations have limitations.</p><p><strong>Resource hungry.</strong>&nbsp;Keycloak is a Java application that needs a PostgreSQL database. It's not lightweight like some self-hosted tools. Expect at least 512MB of RAM for Keycloak alone, plus database overhead. Startup time is 30-60 seconds, not instant.<strong> </strong></p><p><strong>Default Security Configuration.</strong>&nbsp;The default password hashing iterations are low, which requires administrators to manually tune security to prevent brute-force attacks. Keycloak can struggle with a high number of realms (multi-tenant environments), experiencing performance degradation. While newer versions are improving, earlier and default configurations have limitations.</p><h2 id="conclusion">Conclusion</h2><p>Keycloak delivers enterprise-grade identity and access management without the enterprise price tag. The setup complexity is real - the lack of official Docker Compose examples and the steep learning curve are genuine barriers - but the features you get in return make it worthwhile.</p><p>Is it overkill for a simple single-app project? Absolutely. If you just need basic username/password authentication, Keycloak is too much. But if you're building a multi-app ecosystem, need SSO across services, want social login without vendor lock-in, or require features like MFA and user federation, Keycloak is one of the best self-hosted options available.</p><p>The <code>docker-compose</code> file above solves the biggest setup hurdle. Once you're past the initial configuration, Keycloak is remarkably powerful and flexible.</p>]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[LHB Linux Digest #26.06: DIY Linux Learning Labs, Docker Tools, Drone Logs and More Linux Stuff]]></title>
                    <description><![CDATA[Lab is the differentiator.]]></description>
                    <link>https://linuxhandbook.com/newsletter/26-06/</link>
                    <guid isPermaLink="false">69c9f7b1df009b000197e832</guid>

                        <category><![CDATA[Newsletter]]></category>

                        <dc:creator><![CDATA[Abhishek Prakash]]></dc:creator>

                    <pubDate>Tue, 07 Apr 2026 20:11:32 +0530</pubDate>

                        <media:content url="https://linuxhandbook.com/content/images/2026/04/lhb-newsletter.webp" medium="image"/>

                    <content:encoded><![CDATA[<img src="https://linuxhandbook.com/content/images/2026/04/lhb-newsletter.webp" alt="LHB Linux Digest #26.06: DIY Linux Learning Labs, Docker Tools, Drone Logs and More Linux Stuff"/> <p>True learning begins when you actively work on something. That’s why a balance of theory and hands-on practice is essential.</p><p>To address this, we are creating labs. These are small, guided projects designed to help you practice on your Linux system. When you work through them yourself, you naturally encounter challenges you didn’t anticipate. In this way, these labs help prepare you for real-world scenarios.</p><p>You can test it out with this lab where <a href="https://linuxhandbook.com/labs/automated-image-optimization/">you have to build an automated image optimization system</a>. </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://linuxhandbook.com/labs/automated-image-optimization/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Building an Automated Image Optimization Pipeline</div><div class="kg-bookmark-description">In this lab, you’ll build an automated process that watches a folder for new images and automatically optimizes them.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://linuxhandbook.com/content/images/icon/Linux-Handbook-New-Logo-197.png" alt=""><span class="kg-bookmark-author">Linux Handbook</span><span class="kg-bookmark-publisher">Roland Taylor</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://linuxhandbook.com/content/images/thumbnail/image-optimization-lab.webp" alt="" onerror="this.style.display = 'none'"></div></a></figure><p>I'll be making a collection of such labs for your learning pleasure. Stay tuned.</p><p>That's not the only change. We have a <a href="https://linuxhandbook.com/blog/">blog section</a> now. As I am reorganizing the content on Linux Handbook, it makes sense to write blogs around tools and tips we discover as a Linux user.</p>

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">
        <div data-sx-content-cta-blur class="absolute w-full start-0 -top-0.5 -translate-y-full bg-linear-to-b to-70% from-black/0 to-background dark:to-background-dark pointer-events-none">
            &nbsp; <br> &nbsp; <br> &nbsp;
        </div>

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                        <span class="hidden first:inline">
                        This post is for subscribers only
                    </span>                

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Building an Automated Image Optimization Pipeline]]></title>
                    <description><![CDATA[In this lab, you&#x27;ll build an automated process that watches a folder for new images and automatically optimizes them.]]></description>
                    <link>https://linuxhandbook.com/labs/automated-image-optimization/</link>
                    <guid isPermaLink="false">692602d77f7be70001e8e828</guid>

                        <category><![CDATA[Labs]]></category>

                        <dc:creator><![CDATA[Roland Taylor]]></dc:creator>

                    <pubDate>Tue, 07 Apr 2026 19:27:04 +0530</pubDate>

                        <media:content url="https://linuxhandbook.com/content/images/2026/04/image-optimization-lab.webp" medium="image"/>

                    <content:encoded><![CDATA[<img src="https://linuxhandbook.com/content/images/2026/04/image-optimization-lab.webp" alt="Building an Automated Image Optimization Pipeline"/> <p>Optimizing images for the web is a common step in website design and development, but it can also be one of the most tedious. With all the steps like resizing, compressing, stripping metadata, and exporting multiple formats, it can eat chunks of time that rack up quickly when you’re just trying to work your blog, portfolio, or even a small business website.</p><p>This lab exercises will show you how to not only make that process easier, but automate it in a way that can be replicated on your own system or even a Linux server.</p><h2 id="%F0%9F%8E%AF-the-goal">🎯 The goal</h2><p>For this Linux Lab project, we'll be building a simple, fully automated image processing pipeline that does the following:</p><ul><li>Watches a specific folder for new images</li><li>Automatically optimizes them using ImageMagick</li><li>(Optionally) Generates web-friendly WebP copies</li><li>(Optionally) Moves images into section-specific folders like <code>optimized/blog/img/</code> for rapid reference and deployment</li><li>(Preferably) Runs the automation as a systemd user service</li></ul><p>By the time we're finished, you’ll have a reusable automation that you can implement on your desktop or server, with minimal overhead, no need for configuration, and <strong>no need for Docker or any external services</strong>.</p><h2 id="prerequisites">Prerequisites</h2><p>Before you dive in, there are a few dependencies that should be taken care of first. The details may differ slightly for your distro, so please be aware that you may need to consult your distro's documentation where necessary to install the correct packages. Once this stage is done, however, you should be able to follow everything just the same on most distributions.</p><p><strong>You'll need to install:</strong></p><ul><li>ImageMagick: for resizing and compressing images in common formats</li><li>inotify-tools: for watching the target folder for any new files</li><li>(optionally) webp: for converting images to the WebP format</li></ul><p><strong>On Ubuntu systems, you can run:</strong></p><pre><code class="language-bash">sudo apt update
sudo apt install -y imagemagick inotify-tools webp</code></pre><p><strong>On Fedora, you can use:</strong></p><pre><code class="language-bash">sudo dnf -y install ImageMagick inotify-tools libwebp-tools</code></pre><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">📋</div><div class="kg-callout-text">As with Fedora, the ImageMagick package may not always be called <code spellcheck="false" style="white-space: pre-wrap;">imagemagick</code> in your distro repository. Be sure to check before attempting to install on other distros, as package names are typically case-sensitive.</div></div><p>Once you've installed these packages, you're ready to move on to setting up the project folders.</p><h2 id="building-out-the-project-folders">Building out the project folders</h2><p>For this endeavor, we'll build a single parent folder with three sub-directories. Technically, you can place the three sub-directories anywhere you like, but for keeping things organized, we'll keep them in a dedicated folder for this tutorial.</p><p><strong>The structure we'll use looks something like this:</strong></p><ul><li><code>~/image-lab:</code> the parent folder<ul><li><code>/incoming:</code> where you'll drop original images for optimization</li><li><code>/optimized:</code> where optimized images will be saved</li><li><code>/logs:</code> for storing a simple log file with timestamps and actions</li></ul></li></ul><p><strong>To create these folders, you just need to run the following command:</strong></p><pre><code class="language-bash">mkdir -p ~/image-lab/{incoming,optimized,logs}</code></pre><p>This will automatically create the sub-directories with <code>~/image-lab</code> for you.</p>

<aside data-sx-content-cta class="relative p-0.5 js-toc-ignore">
        <div data-sx-content-cta-blur class="absolute w-full start-0 -top-0.5 -translate-y-full bg-linear-to-b to-70% from-black/0 to-background dark:to-background-dark pointer-events-none">
            &nbsp; <br> &nbsp; <br> &nbsp;
        </div>

    <div class="relative flex flex-col items-center text-center w-full px-4 py-10 lg:px-10 text-base rounded-xl sm:rounded-2xl">
        <div class="dark:hidden absolute -inset-px -z-10 rounded-xl bg-white shadow-pretty-sm transition-shadow duration-200"></div>
        <span class="hidden dark:block absolute -z-10 -inset-px rounded-inherit bg-radial-[50%_100%_at_50%_0%] from-white/10"></span>        
        <div class="hidden dark:block absolute -inset-px -z-10 rounded-xl bg-white/1 transition-colors duration-500 inset-shadow-md inset-shadow-white/2"></div>
        
        <div class="hidden dark:block absolute -z-10 -inset-0.5 mask-to-b mask-position-to-70% mask-opacity-to-50%">
            <div class="hidden dark:block absolute -z-10 inset-px rounded-xl border border-gray-50/10"></div>
        </div>                                                
        <div class="hidden dark:block absolute -z-10 -inset-px rounded-xl border border-gray-50/5 opacity-0"></div>

        <div class="hidden dark:block absolute -top-px start-1/2 -translate-x-1/2 w-1/2 h-px bg-linear-to-r from-white/0 to-white/0 via-gray-400/50"></div>

        <h2 class="text-gray-900 dark:text-gray-100 text-pretty text-xl sm:text-2xl leading-snug tracking-tight">




                                        <span class="hidden first:inline">
                        This post is for subscribers only
                    </span>                

        </h2>

            <button data-portal="signup" class="mt-7 px-4 py-2.5 font-semibold text-sm text-center text-accent-contrast bg-primary rounded-full shadow-primary dark:shadow-none dark:drop-shadow-primary-sm hover:opacity-90 transition-opacity duration-200">
                Subscribe now
            </button>
            <p class="mt-5 text-sm">
                Already have an account? <button data-portal="signin" class="block sm:inline mx-auto font-medium underline decoration-primary decoration-2 underline-offset-2 hover:text-primary transition-colors duration-200">Sign in</button>
            </p>
    </div>
</aside>
]]></content:encoded>
                </item>
                <item>
                    <title><![CDATA[Watchtower Discontinued! Here Are Alternative Projects for Your Docker Containers]]></title>
                    <description><![CDATA[Watchtower was the goto tool for keeping the containers updated timely. It&#x27;s not developed anymore. I explored a few alternatives.]]></description>
                    <link>https://linuxhandbook.com/blog/watchtower-like-docker-tools/</link>
                    <guid isPermaLink="false">69b90f2edf009b000197bec3</guid>

                        <category><![CDATA[blog]]></category>

                        <dc:creator><![CDATA[Yash Kiran Patil]]></dc:creator>

                    <pubDate>Sat, 04 Apr 2026 16:44:23 +0530</pubDate>

                        <media:content url="https://linuxhandbook.com/content/images/2026/04/penguin-with-telescope.webp" medium="image"/>

                    <content:encoded><![CDATA[<img src="https://linuxhandbook.com/content/images/2026/04/penguin-with-telescope.webp" alt="Watchtower Discontinued! Here Are Alternative Projects for Your Docker Containers"/> <p>There are plenty of <a href="https://linuxhandbook.com/blog/docker-workflow-tools/">tools that help you use Docker containers more effectively and smoothly</a>. One of the most popular was Watchtower. Was...because the project has been discontinued in December 2025.</p><p>If you've been running Watchtower to automatically keep your containers updated, you're not alone in suddenly wondering what's next after <a href="https://github.com/containrrr/watchtower?ref=linuxhandbook.com">the repo has been archived</a>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/03/image-36.png" class="kg-image" alt="" loading="lazy" width="1024" height="1024" srcset="https://linuxhandbook.com/content/images/size/w600/2026/03/image-36.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/03/image-36.png 1000w, https://linuxhandbook.com/content/images/2026/03/image-36.png 1024w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Watchtower's GitHub repo was archived on </span><b><strong style="white-space: pre-wrap;">December 17, 2025</strong></b><span style="white-space: pre-wrap;">. Read-only. Done.</span></figcaption></figure><p>Good news - the alternatives are actually <strong><em>better</em></strong>. Here are some solid tools worth your time in my opinion and experience.</p><h2 id="diundocker-image-update-notifier"><strong>Diun - D</strong>ocker&nbsp;<strong>I</strong>mage&nbsp;<strong>U</strong>pdate&nbsp;<strong>N</strong>otifier</h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/03/image-44.png" class="kg-image" alt="" loading="lazy" width="445" height="213"></figure><p>It is a CLI application written in&nbsp;<a href="https://golang.org/?ref=linuxhandbook.com">Go</a>&nbsp;and delivered as a&nbsp;<a href="https://github.com/crazy-max/diun/releases/latest?ref=linuxhandbook.com">single executable</a>&nbsp;(and a&nbsp;<a href="https://crazymax.dev/diun/install/docker/?ref=linuxhandbook.com">Docker image</a>) to receive notifications when a Docker image is updated on a Docker registry.</p><p>Diun does one thing: <strong>watches your images and notifies you when they're updated</strong>. It will not touch your containers. That's intentional. If you've ever had Watchtower silently pull a Postgres major version upgrade at 2 am, you'll appreciate this approach. You stay in control of when the actual update happens.</p><p><strong>Quick compose setup:</strong></p><pre><code class="language-yaml">services:
  diun:
    image: crazymax/diun:latest
    volumes:
      - "./data:/data"
      - "/var/run/docker.sock:/var/run/docker.sock"
      - "./diun.yml:/diun.yml:ro"
    environment:
      - "DIUN_WATCH_SCHEDULE=0 */6 * * *"
    restart: always</code></pre><p>and make one <code>diun.yml</code>: </p><pre><code class="language-yaml"># diun.yml
watch:
  schedule: "0 */6 * * *"
providers:
  docker:
    watchStopped: true
notif:
  discord:
    webhookURL: https://discordapp.com/api/YOUR/WEBHOOK</code></pre><p>You can mention your webhook URL for Slack, Telegram, Discord, etc. if there is any update, you will receive it like: </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/03/image-37.png" class="kg-image" alt="" loading="lazy" width="550" height="449"><figcaption><span style="white-space: pre-wrap;">credit: </span><a href="https://crazymax.dev/diun?ref=linuxhandbook.com"><span style="white-space: pre-wrap;">crazymax.dev/diun</span></a></figcaption></figure><p>This will notify you in all supported applications, just like what we have received on Discord: the hostname, provider, the date it was created, platform and the Docker Hub link.</p><p><strong>Use this if:</strong> You want awareness without the risk of surprise updates. Great for production-adjacent setups.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://github.com/crazy-max/diun?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">GitHub | Diun</a></div><h2 id="tugtainer"><strong>Tugtainer</strong></h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/03/image-41.png" class="kg-image" alt="" loading="lazy" width="897" height="343" srcset="https://linuxhandbook.com/content/images/size/w600/2026/03/image-41.png 600w, https://linuxhandbook.com/content/images/2026/03/image-41.png 897w" sizes="(min-width: 720px) 720px"></figure><p>Tugtainer is a self-hosted app for automating updates of your Docker containers. Relatively new (October 2025), devs say not production-ready yet. But moves fast — v1.25.0 dropped March 2026.</p><p>Tugtainer gives you a proper web dashboard to manage container updates. Think Portainer, but focused specifically on the update workflow.</p><p><strong>Quick setup:</strong></p><pre><code class="language-bash"># create volume
docker volume create tugtainer_data

# pull image
docker pull ghcr.io/quenary/tugtainer:1

# run container
docker run -d -p 9412:80 \
    --name=tugtainer \
    --restart=unless-stopped \
    -v tugtainer_data:/tugtainer \
    -v /var/run/docker.sock:/var/run/docker.sock:ro \
    ghcr.io/quenary/tugtainer:1</code></pre><p>Hit <code>http://your-server:3000</code> and you get this:</p><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/03/image-38.png" class="kg-image" alt="" loading="lazy" width="1920" height="858" srcset="https://linuxhandbook.com/content/images/size/w600/2026/03/image-38.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/03/image-38.png 1000w, https://linuxhandbook.com/content/images/size/w1600/2026/03/image-38.png 1600w, https://linuxhandbook.com/content/images/2026/03/image-38.png 1920w" sizes="(min-width: 720px) 720px"></figure><p>Some of the main features are: Notifications to a wide range of services, Per-container config (check only or auto-update), Automatic/manual check and update, Automatic/manual image pruning and Linked containers support (compose and custom).</p><p><strong>Use this if:</strong> You want a UI to manage your homelab updates. Especially good for Docker Compose setups.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://github.com/Quenary/tugtainer?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">GitHub | Tugtainer</a></div><h2 id="wudwhats-up-docker"><strong>WUD</strong> - <strong>What's Up Docker </strong></h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/03/image-42.png" class="kg-image" alt="" loading="lazy" width="515" height="387"></figure><p>WUD is the closest thing to a drop-in Watchtower replacement - but it's smarter. It has a web dashboard, notification support, and can auto-update containers. The key difference? It lets you set <strong>thresholds</strong>.</p><pre><code class="language-bash">WUD_TRIGGER_DOCKER_LOCAL_THRESHOLD=patch
</code></pre><p>With that set, WUD auto-updates <code>1.2.3 → 1.2.4</code> but just <strong><em>notifies</em></strong> you for <code>1.2.3 → 1.3.0</code> or a major bump. Watchtower had no concept of this.</p><p><strong>Quick setup:</strong></p><pre><code class="language-yaml">services:
  wud:
    image: getwud/wud:latest
    ports:
      - "3000:3000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - WUD_NOTIFIER_TELEGRAM_BOTTOKEN=your-token
      - WUD_NOTIFIER_TELEGRAM_CHATID=your-chat-id
      - WUD_TRIGGER_DOCKER_LOCAL_THRESHOLD=patch
    restart: unless-stopped</code></pre><p>If you hit <code>localhost:3000</code> you will get a simple, minimalist UI.</p><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/03/image-39.png" class="kg-image" alt="" loading="lazy" width="1920" height="975" srcset="https://linuxhandbook.com/content/images/size/w600/2026/03/image-39.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/03/image-39.png 1000w, https://linuxhandbook.com/content/images/size/w1600/2026/03/image-39.png 1600w, https://linuxhandbook.com/content/images/2026/03/image-39.png 1920w" sizes="(min-width: 720px) 720px"></figure><p>Notifications go to Slack, Telegram, Discord, Gotify, Ntfy, Pushover, email and more. </p><p><strong>Use this if</strong>: You want something close to Watchtower's auto-update behavior, but with actual guardrails and a dashboard.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://github.com/getwud/wud?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">GitHub | WUD</a></div><h2 id="dockcheck"><strong>dockcheck</strong></h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/03/image-43.png" class="kg-image" alt="" loading="lazy" width="601" height="430" srcset="https://linuxhandbook.com/content/images/size/w600/2026/03/image-43.png 600w, https://linuxhandbook.com/content/images/2026/03/image-43.png 601w"></figure><p>The odd one out - it's a bash script. And it's my personal favorite.</p><p>The trick: dockcheck uses <code>regctl</code> to <strong>compare image digests directly</strong> against the registry. It never pre-pulls images just to check for updates. Saves bandwidth, doesn't hit Docker Hub rate limits, and is just plain faster.</p><p>Install <code>regctl</code> first:</p><pre><code class="language-bash">curl -L https://github.com/regclient/regclient/releases/latest/download/regctl-linux-amd64 \
  -o /usr/local/bin/regctl &amp;&amp; chmod +x /usr/local/bin/regctl</code></pre><pre><code class="language-bash">curl -fsSL https://raw.githubusercontent.com/mag37/dockcheck/main/dockcheck.sh -o dockcheck.sh
chmod +x dockcheck.sh
./dockcheck.sh</code></pre><p>You will get output like this:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://linuxhandbook.com/content/images/2026/03/image-40.png" class="kg-image" alt="" loading="lazy" width="885" height="562" srcset="https://linuxhandbook.com/content/images/size/w600/2026/03/image-40.png 600w, https://linuxhandbook.com/content/images/2026/03/image-40.png 885w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">credit: cdn.jsdelivr.net</span></figcaption></figure><p>You get a numbered list of containers with updates available. Pick which ones to update, or type <code>a</code> for all. Clean and simple.</p><p>To automate it, just cron it:</p><pre><code class="language-bash"># Every Sunday at 3AM, auto-update all, send notification
0 3 * * 0 /home/user/dockcheck.sh -a -n &gt;&gt; /var/log/dockcheck.log 2&gt;&amp;1</code></pre><p>It also supports image backups <code>-b</code> so you can roll back if something breaks, and parallel checks with <code>-x N</code>, for more flag you can check <code>-h</code> flag for help.</p><p><strong>Use this if:</strong> You're comfortable with the terminal, run a Linux homelab, and want something lightweight and auditable (it's a bash script, you can read the whole thing).</p><div class="kg-card kg-button-card kg-align-center"><a href="https://github.com/mag37/dockcheck?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">GitHub | dockcheck</a></div><h2 id="cup"><strong>Cup</strong></h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/03/image-54.png" class="kg-image" alt="" loading="lazy" width="584" height="394"></figure><p>Cup might be the fastest update checker on this list. It claims to scan <strong>58 images in 3.7 seconds</strong> on a <strong>Raspberry Pi 5</strong>!</p><p>The secret is that instead of pulling images to compare them, it makes minimal API calls - one auth request per registry, then lightweight manifest HEAD requests. This means it <strong>never burns through Docker Hub's pull rate limits</strong>, which matters a lot now that Docker Hub has been tightening limits for unauthenticated users.</p><p><strong>Quick setup:</strong></p><pre><code class="language-bash">#Pull the image 
docker pull ghcr.io/sergi0g/cup

#Run the image with port mapping
docker run -tv /var/run/docker.sock:/var/run/docker.sock -p 9001:9001 ghcr.io/sergi0g/cup serve -p 9001</code></pre><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/03/image-48.webp" class="kg-image" alt="" loading="lazy" width="1100" height="479" srcset="https://linuxhandbook.com/content/images/size/w600/2026/03/image-48.webp 600w, https://linuxhandbook.com/content/images/size/w1000/2026/03/image-48.webp 1000w, https://linuxhandbook.com/content/images/2026/03/image-48.webp 1100w" sizes="(min-width: 720px) 720px"></figure><p>Then, if you visit <code>localhost:9001</code> you will get a simple look where you will see all the monitored images, updates available and up-to-date images with a command given to update to the latest image.</p><p>It tells you what's out of date and leaves the rest to you - via a cron job, a webhook consumer, or just checking the dashboard manually. It supports Docker Hub, ghcr.io, Quay, lscr.io, Gitea and more.</p><p><strong>Use this if:</strong> You're hitting Docker Hub rate limits with other tools, or just want the fastest possible update check without anything auto-touching your containers.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://github.com/sergi0g/cup?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">GitHub | Cup</a></div><h2 id="dockwatch"><strong>Dockwatch</strong></h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/03/image-53.png" class="kg-image" alt="" loading="lazy" width="644" height="587" srcset="https://linuxhandbook.com/content/images/size/w600/2026/03/image-53.png 600w, https://linuxhandbook.com/content/images/2026/03/image-53.png 644w"></figure><p>Simple UI driven way to manage updates &amp; notifications for Docker containers. Dockwatch comes from the <strong>Notifiarr</strong> team; the same folks who built one of the best notification routing systems in the self-hosted world. That DNA shows.</p><p>It's built around a beautiful web UI and a genuinely impressive notification system. The kind of thing you'd show someone to convince them that self-hosting is actually fun.</p><p><strong>Quick compose setup:</strong></p><pre><code class="language-yaml">services:
  dockwatch:
    image: ghcr.io/notifiarr/dockwatch:latest
    ports:
      - "3001:80"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./dockwatch/config:/config
    restart: unless-stopped</code></pre><p>Once you're done, run the command:</p><pre><code class="language-bash">docker compose up -d
</code></pre><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/03/image-50.png" class="kg-image" alt="" loading="lazy" width="1119" height="485" srcset="https://linuxhandbook.com/content/images/size/w600/2026/03/image-50.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/03/image-50.png 1000w, https://linuxhandbook.com/content/images/2026/03/image-50.png 1119w" sizes="(min-width: 720px) 720px"></figure><p>Then visit the <code>localhost:3001</code>, you will see the advanced setup, which shows a beautiful UI giving you information about disk usage, network I/O, CPU usage, memory usage and updates available for the images.</p><p><strong>Use this if</strong>: You want a feature-rich dashboard with serious notification chops, especially if you're already in the Notifiarr/Servarr ecosystem.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://github.com/Notifiarr/dockwatch?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">GitHub | Dockwatch</a></div><h2 id="nicholas-fedorwatchtower"><strong>nicholas-fedor/watchtower</strong></h2><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/03/image-52.png" class="kg-image" alt="" loading="lazy" width="644" height="587" srcset="https://linuxhandbook.com/content/images/size/w600/2026/03/image-52.png 600w, https://linuxhandbook.com/content/images/2026/03/image-52.png 644w"></figure><p>For Those Who Don't Want to Change Anything. Okay, real talk. Maybe you've been running Watchtower for years. Your whole homelab is tuned around it. Your cron jobs reference it. Your muscle memory knows the flags. You don't want to learn a new tool.</p><p>Fair. Enter <strong>nicholas-fedor/watchtower</strong> - a community-maintained fork that picks up exactly where the archived original left off.</p><pre><code class="language-bash"># Before (archived, no longer works on newer Docker versions):
image: containrrr/watchtower

# After (actively maintained):
image: nickfedor/watchtower</code></pre><p><strong>Quick setup:</strong></p><pre><code class="language-yaml"># Get the compose file 
curl -L https://raw.githubusercontent.com/nicholas-fedor/watchtower/refs/heads/main/examples/default/docker-compose.yaml -o docker-compose.yaml

# Run command
docker compose up -d</code></pre><figure class="kg-card kg-image-card"><img src="https://linuxhandbook.com/content/images/2026/03/image-51.png" class="kg-image" alt="" loading="lazy" width="1418" height="477" srcset="https://linuxhandbook.com/content/images/size/w600/2026/03/image-51.png 600w, https://linuxhandbook.com/content/images/size/w1000/2026/03/image-51.png 1000w, https://linuxhandbook.com/content/images/2026/03/image-51.png 1418w" sizes="(min-width: 720px) 720px"></figure><p>After this, the expected behaviour is it will monitor all running containers on the host and every 24 hours, it will poll if the monitored containers have updated image digests; if available, it will pull the updated image without changing the previous configurations.</p><p> auto-updates everything it can see, by default. There's no semantic versioning awareness, no dashboard, no diff before it updates</p><p><strong>Use this if:</strong> You want zero migration friction and just need the original Watchtower to keep running on modern Docker.</p><div class="kg-card kg-button-card kg-align-center"><a href="https://github.com/nicholas-fedor/watchtower?ref=linuxhandbook.com" class="kg-btn kg-btn-accent">GitHub | nicholas-fedor/watchtower</a></div><h2 id="so-which-one-to-choose"><strong>So, which one to choose?</strong></h2><p>Yes, if you are impressed with all of these here, I will give you one line suggestions: </p><p>Want notification-only, no auto-updates - <strong>Diun </strong>or<strong> Cup</strong>,  Want a web UI for your homelab - <strong>Tugtainer</strong> or <strong>WUD </strong>or <strong>Dockwatch</strong>,  Closest Watchtower replacement with smarter auto-updates - <strong>WUD</strong>, Terminal-first, minimal dependencies - <strong>dockcheck</strong>, Running Kubernetes or Swarm - Only <strong>Diun</strong> supports that, Want zero migration from the original Watchtower - <strong>nicholas-fedor/watchtower</strong>, Already in the Notifiarr/Servarr ecosystem - <strong>Dockwatch</strong> is a natural fit.</p><p><strong><em>Know another tool worth adding? Drop it in the comments.</em></strong></p>]]></content:encoded>
                </item>
    </channel>
</rss>