<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>DevOps von UCLAB</title>
    <link>https://uclab.dev/</link>
    <description>Recent content on DevOps von UCLAB</description>
    <generator>Hugo</generator>
    <language>en</language>
    <lastBuildDate>Wed, 15 Apr 2026 08:02:44 +0000</lastBuildDate>
    <atom:link href="https://uclab.dev/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Containers From Scratch</title>
      <link>https://uclab.dev/posts/containers-from-scratch/</link>
      <pubDate>Wed, 15 Apr 2026 08:02:44 +0000</pubDate>
      <guid>https://uclab.dev/posts/containers-from-scratch/</guid>
      <description>&lt;p&gt;Liz Rice&amp;rsquo;s &lt;a href=&#34;https://github.com/lizrice/containers-from-scratch&#34;&gt;containers-from-scratch&lt;/a&gt; talk is one of the best explanations of how containers work under the hood.&#xA;You build a container runtime from ~100 lines of Go, and by the end you understand what Docker is actually doing.&lt;/p&gt;&#xA;&lt;p&gt;The problem: the code was written when cgroups v1 was standard. Ubuntu 24.04 (Noble) ships with cgroups v2 only, and a few other things have changed since Go 1.16.&#xA;This post walks through the fixes.&lt;/p&gt;</description>
    </item>
    <item>
      <title>AI Devcontainer — Architecture &amp; Setup</title>
      <link>https://uclab.dev/posts/ai-devcontainer/</link>
      <pubDate>Tue, 07 Apr 2026 07:46:04 +0000</pubDate>
      <guid>https://uclab.dev/posts/ai-devcontainer/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;images/gemini.png&#34; alt=&#34;AI&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;&#xA;&lt;p&gt;This devcontainer provides a self-contained, GPU-accelerated AI development environment running inside a &lt;a href=&#34;https://devpod.sh/&#34;&gt;DevPod&lt;/a&gt; workspace. It serves a full local LLM stack accessible publicly via a Cloudflare tunnel at &lt;strong&gt;&lt;a href=&#34;https://ai.uclab.dev&#34;&gt;https://ai.uclab.dev&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Internet&#xA;   │&#xA;   ▼&#xA;Cloudflare (ai.uclab.dev)&#xA;   │  Zero Trust Tunnel&#xA;   ▼&#xA;cloudflared (container)&#xA;   │  http://localhost:8080&#xA;   ▼&#xA;Open WebUI  ──────────────────►  Ollama API (localhost:11434)&#xA;(port 8080)                           │&#xA;                                       ▼&#xA;                                 GPU: RTX 5060 (8 GB VRAM)&#xA;                                 Models: llama3.1:8b, qwen2.5:7b,&#xA;                                         deepseek-coder-v2:16b-lite-instruct-q4_K_M,&#xA;                                         mistral-nemo&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;&#xA;&lt;h2 id=&#34;host-requirements&#34;&gt;Host Requirements&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Requirement&lt;/th&gt;&#xA;          &lt;th&gt;Details&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Container runtime&lt;/td&gt;&#xA;          &lt;td&gt;Docker with &lt;a href=&#34;https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html&#34;&gt;nvidia-container-toolkit&lt;/a&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;GPU passthrough&lt;/td&gt;&#xA;          &lt;td&gt;CDI (&lt;code&gt;nvidia.com/gpu=all&lt;/code&gt;)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;DevPod workspace&lt;/td&gt;&#xA;          &lt;td&gt;Workspace ID: &lt;code&gt;ai&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Host directories&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;~/.ollama&lt;/code&gt; (model storage), &lt;code&gt;~/.cloudflared&lt;/code&gt; (tunnel credentials)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;file-structure&#34;&gt;File Structure&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;.devcontainer/&#xA;├── Dockerfile              # Image definition&#xA;├── devcontainer.json       # DevPod/VS Code container config&#xA;├── pull-models             # Script to pull Ollama models (idempotent)&#xA;├── supervisord.conf        # Reference config (not active — see note below)&#xA;├── supervisord/&#xA;│   ├── ollama.conf         # Supervisor program: Ollama&#xA;│   ├── open-webui.conf     # Supervisor program: Open WebUI&#xA;│   └── cloudflared.conf    # Supervisor program: Cloudflare tunnel&#xA;└── scripts/&#xA;    ├── setup               # Trusts and installs mise tools for workspace&#xA;    └── setup_project       # One-time project setup (commitizen, pre-commit)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;&#xA;&lt;h2 id=&#34;docker-image&#34;&gt;Docker Image&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;Base&lt;/strong&gt;: &lt;code&gt;nvidia/cuda:12.8.0-runtime-ubuntu24.04&lt;/code&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Vault on a Synology NAS and Migrating Secrets</title>
      <link>https://uclab.dev/posts/vault-migrate/</link>
      <pubDate>Sat, 04 Apr 2026 11:24:04 +0000</pubDate>
      <guid>https://uclab.dev/posts/vault-migrate/</guid>
      <description>&lt;p&gt;I recently needed to migrate my HashiCorp Vault instance from a dedicated Ubuntu VM to a Docker container running on my Synology DS918+ NAS. This post covers the entire process: setting up Vault on Synology, configuring it behind the built-in reverse proxy, creating a proper policy and user structure, and finally migrating all secrets from the old instance — including re-connecting everything to an External Secrets Operator running in a k3s cluster.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Tmux Multiple Panes</title>
      <link>https://uclab.dev/posts/tmux-multiple-panes/</link>
      <pubDate>Mon, 30 Mar 2026 09:01:36 +0000</pubDate>
      <guid>https://uclab.dev/posts/tmux-multiple-panes/</guid>
      <description>&lt;h2 id=&#34;sending-the-same-command-to-multiple-paneswindows-in-tmux&#34;&gt;Sending the Same Command to Multiple Panes/Windows in tmux&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Ctrl+b  :set-window-option synchronize-panes on&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now anything you type goes to all panes simultaneously. Turn it off with:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Ctrl+b  :set-window-option synchronize-panes off&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Building a Virtual Cisco Network Lab with Containerlab</title>
      <link>https://uclab.dev/posts/containerlab/</link>
      <pubDate>Sat, 28 Mar 2026 20:10:52 +0000</pubDate>
      <guid>https://uclab.dev/posts/containerlab/</guid>
      <description>&lt;p&gt;So you want a real Cisco lab running on your laptop or a small Linux box — no physical hardware, no expensive CML server license, just containers. This post walks through exactly that: installing &lt;strong&gt;Containerlab&lt;/strong&gt;, building Docker images from Cisco &lt;strong&gt;IOL&lt;/strong&gt; binaries using &lt;strong&gt;vrnetlab&lt;/strong&gt;, defining a multi-node topology, and finally pushing configuration to every device automatically from &lt;strong&gt;AWX&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;p&gt;By the end you will have two routers and two switches wired up, OSPF converged, VLANs pushed, and L2/L3 interfaces configured — all from Ansible playbooks running in AWX.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Deploying NetBox on k3s</title>
      <link>https://uclab.dev/posts/netbox/</link>
      <pubDate>Sat, 28 Mar 2026 07:41:10 +0000</pubDate>
      <guid>https://uclab.dev/posts/netbox/</guid>
      <description>&lt;p&gt;NetBox is the source of truth for network and infrastructure documentation. If you run a homelab or a small datacenter and want to know what IP belongs where, what VLANs exist, and which rack holds which server — NetBox is the tool for the job. This post walks through deploying it on a k3s cluster using the official Helm chart, FluxCD for GitOps, and HashiCorp Vault via ExternalSecrets for secret management.&lt;/p&gt;</description>
    </item>
    <item>
      <title>AWX in Practice</title>
      <link>https://uclab.dev/posts/awx-in-practice/</link>
      <pubDate>Thu, 26 Mar 2026 08:53:02 +0000</pubDate>
      <guid>https://uclab.dev/posts/awx-in-practice/</guid>
      <description>&lt;p&gt;In my &lt;a href=&#34;https://uclab.dev/posts/awx&#34;&gt;previous post&lt;/a&gt;, I got AWX running on k3s with a custom Execution Environment for Cisco collections. Time to actually use it for something practical: a self-service VLAN provisioning job that lets anyone on the team provision a VLAN on specific switches by filling in a form — no CLI, no SSH, no risk of typos in config mode.&lt;/p&gt;&#xA;&lt;p&gt;This post covers building it end to end, including the surprising number of gotchas I hit with surveys, host targeting, and variable scoping.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Deploying AWX on kubernetes</title>
      <link>https://uclab.dev/posts/awx/</link>
      <pubDate>Wed, 25 Mar 2026 18:11:08 +0000</pubDate>
      <guid>https://uclab.dev/posts/awx/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;images/gemini.png&#34; alt=&#34;awx&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;After running Ansible playbooks directly from my workstation for a while, I decided it was time to get a proper AWX instance running in my homelab k3s cluster. This post covers the full journey — from Flux manifests to a custom Execution Environment with Cisco collections — including every gotcha I hit along the way.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-stack&#34;&gt;The Stack&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;k3s&lt;/strong&gt; multi-node cluster (aarch64 NUC nodes)&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Flux v2.8.1&lt;/strong&gt; for GitOps&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Cilium&lt;/strong&gt; CNI with Gateway API&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;cert-manager&lt;/strong&gt; for TLS&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Forgejo&lt;/strong&gt; self-hosted git and container registry&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;AWX 24.6.1&lt;/strong&gt; via the &lt;a href=&#34;https://github.com/ansible-community/awx-operator-helm&#34;&gt;awx-operator Helm chart&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;repository-structure&#34;&gt;Repository Structure&lt;/h2&gt;&#xA;&lt;p&gt;I use a base/overlay pattern in my GitOps repo. AWX lives under &lt;code&gt;apps/&lt;/code&gt;:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kubectl Kustomize</title>
      <link>https://uclab.dev/posts/kubectl-kustomize/</link>
      <pubDate>Wed, 25 Mar 2026 09:03:31 +0000</pubDate>
      <guid>https://uclab.dev/posts/kubectl-kustomize/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;images/gemini.png&#34; alt=&#34;kustomize&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Managing a homelab Kubernetes cluster with &lt;a href=&#34;https://fluxcd.io/&#34;&gt;Flux GitOps&lt;/a&gt; means I rarely &lt;code&gt;kubectl apply&lt;/code&gt; raw YAML anymore.&#xA;Everything lives in Git and Flux reconciles it.&#xA;But there&amp;rsquo;s still one pair of commands I reach for constantly when developing or debugging an app:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;k kustomize      &lt;span style=&#34;color:#75715e&#34;&gt;# inspect the rendered output&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;k apply -k .     &lt;span style=&#34;color:#75715e&#34;&gt;# apply it manually when I need to&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This post walks through what these commands actually do, how they fit into a Flux-based workflow, and a real example from my &lt;code&gt;n8n&lt;/code&gt; deployment on a Raspberry Pi 5 k3s cluster.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Hello World in Python</title>
      <link>https://uclab.dev/posts/python-hello-world/</link>
      <pubDate>Sun, 22 Mar 2026 07:37:44 +0000</pubDate>
      <guid>https://uclab.dev/posts/python-hello-world/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://github.com/danielmiessler/Fabric&#34;&gt;fabric&lt;/a&gt; is an open-source framework for augmenting humans using AI.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;write hello world in python and describe what everything does&amp;#34;&lt;/span&gt; | f-coding_master&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;the-code&#34;&gt;The Code&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#xA;&lt;h2 id=&#34;what-everything-does&#34;&gt;What Everything Does&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Breaking down each component:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  ^      ^         ^&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  |      |         |&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  |      |         └── Closing parenthesis ends the function call&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  |      └── The string argument passed to the print function&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  └── Built-in Python function that outputs text to the console&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#xA;&lt;h2 id=&#34;detailed-breakdown&#34;&gt;Detailed Breakdown&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# COMPONENT 1: print()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# print is a built-in Python FUNCTION&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Functions perform specific tasks when called&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# COMPONENT 2: Parentheses ()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Parentheses CALL the function and wrap arguments&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# COMPONENT 3: &amp;#34;Hello, World!&amp;#34; - This is a STRING&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Strings are text wrapped in quotation marks&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# COMPONENT 4: Quotation Marks &amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# These define the beginning and end of your string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;my_string &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# COMPONENT 5: Running the complete statement&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt;)  &lt;span style=&#34;color:#75715e&#34;&gt;# Output: Hello, World!&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#xA;&lt;h2 id=&#34;extended-example&#34;&gt;Extended Example&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# You can also use single quotes&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Hello, World!&amp;#39;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# You can store the message in a variable first&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;message &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(message)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# You can print multiple things&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;World&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# You can use an f-string for dynamic output&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;name &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;World&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello, &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;name&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;!&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#xA;&lt;h2 id=&#34;ideas&#34;&gt;IDEAS&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Python&amp;rsquo;s &lt;code&gt;print()&lt;/code&gt; function is the most fundamental building block every beginner learns first.&lt;/li&gt;&#xA;&lt;li&gt;Strings in Python can be wrapped using either single or double quotation marks interchangeably.&lt;/li&gt;&#xA;&lt;li&gt;Functions in Python always require parentheses to actually execute and perform their task.&lt;/li&gt;&#xA;&lt;li&gt;Hello World programs traditionally serve as a programmer&amp;rsquo;s very first introduction to any language.&lt;/li&gt;&#xA;&lt;li&gt;Python is designed to be readable, making it perfect for absolute beginners starting their journey.&lt;/li&gt;&#xA;&lt;li&gt;Built-in functions like &lt;code&gt;print()&lt;/code&gt; come pre-installed with Python requiring no additional imports whatsoever.&lt;/li&gt;&#xA;&lt;li&gt;Variables can store strings allowing reusable and dynamic text output throughout your entire program.&lt;/li&gt;&#xA;&lt;li&gt;F-strings allow you to embed variables directly inside strings using curly brace syntax elegantly.&lt;/li&gt;&#xA;&lt;li&gt;Python does not require semicolons at the end of statements unlike many other languages.&lt;/li&gt;&#xA;&lt;li&gt;The console or terminal is where &lt;code&gt;print()&lt;/code&gt; sends its output for the user to see.&lt;/li&gt;&#xA;&lt;li&gt;Comments in Python start with a hashtag symbol and are completely ignored during execution.&lt;/li&gt;&#xA;&lt;li&gt;Python code executes line by line from top to bottom in a sequential logical order.&lt;/li&gt;&#xA;&lt;li&gt;Strings are considered a data type in Python representing sequences of individual characters.&lt;/li&gt;&#xA;&lt;li&gt;NetworkChuck emphasizes that Python&amp;rsquo;s simplicity makes it the best first language for absolute beginners.&lt;/li&gt;&#xA;&lt;li&gt;Codecademy teaches Hello World as lesson one because it immediately shows satisfying visible results.&lt;/li&gt;&#xA;&lt;li&gt;Arguments are values passed inside function parentheses telling the function exactly what to process.&lt;/li&gt;&#xA;&lt;li&gt;Python 3 requires parentheses with print unlike Python 2 which treated print as a statement.&lt;/li&gt;&#xA;&lt;li&gt;The comma inside &amp;ldquo;Hello, World!&amp;rdquo; is simply part of the string and not Python syntax.&lt;/li&gt;&#xA;&lt;li&gt;Indentation matters deeply in Python but Hello World requires none making it perfectly simple.&lt;/li&gt;&#xA;&lt;li&gt;Every Python program can be saved with a &lt;code&gt;.py&lt;/code&gt; file extension for proper execution later.&lt;/li&gt;&#xA;&lt;li&gt;Running Python files through terminal teaches beginners the connection between code and real execution.&lt;/li&gt;&#xA;&lt;li&gt;Understanding output functions early helps beginners debug their code by printing variable values constantly.&lt;/li&gt;&#xA;&lt;li&gt;Hello World is universally recognized across every programming language as the starting point tradition.&lt;/li&gt;&#xA;&lt;li&gt;Python&amp;rsquo;s interpreter reads your code and translates it into machine-readable instructions automatically for you.&lt;/li&gt;&#xA;&lt;li&gt;String concatenation allows combining multiple strings together inside a single print statement very easily.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;insights&#34;&gt;INSIGHTS&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Simplicity of Hello World masks the deep complexity of what computers actually do underneath.&lt;/li&gt;&#xA;&lt;li&gt;Learning print first teaches beginners that programming is fundamentally about communication between human and machine.&lt;/li&gt;&#xA;&lt;li&gt;Python&amp;rsquo;s readable syntax reduces cognitive load allowing beginners to focus on logic not memorization.&lt;/li&gt;&#xA;&lt;li&gt;Built-in functions represent years of developer work abstracted into simple callable one-word commands for everyone.&lt;/li&gt;&#xA;&lt;li&gt;The tradition of Hello World unifies all programmers globally regardless of language or experience level.&lt;/li&gt;&#xA;&lt;li&gt;F-strings represent Python&amp;rsquo;s evolution toward more intuitive human-readable dynamic string formatting over time.&lt;/li&gt;&#xA;&lt;li&gt;Variables teach the core concept that computers can remember and recall information on demand.&lt;/li&gt;&#xA;&lt;li&gt;Understanding arguments prepares beginners for the deeper concept of passing data between functions later.&lt;/li&gt;&#xA;&lt;li&gt;Console output is the simplest form of human-computer interaction forming the foundation of all programming.&lt;/li&gt;&#xA;&lt;li&gt;Python&amp;rsquo;s design philosophy prioritizes human readability proving that powerful code does not require complexity.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;recommendations&#34;&gt;RECOMMENDATIONS&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Start every Python learning journey by typing Hello World manually never copying and pasting it.&lt;/li&gt;&#xA;&lt;li&gt;Practice modifying the string inside print to build confidence with changing and experimenting with code.&lt;/li&gt;&#xA;&lt;li&gt;Use Codecademy&amp;rsquo;s free Python course to get immediate browser-based feedback without installing anything locally first.&lt;/li&gt;&#xA;&lt;li&gt;Watch NetworkChuck&amp;rsquo;s Python beginner videos for entertaining real-world context around foundational programming concepts today.&lt;/li&gt;&#xA;&lt;li&gt;Always save your Python files with the &lt;code&gt;.py&lt;/code&gt; extension to ensure proper syntax highlighting works.&lt;/li&gt;&#xA;&lt;li&gt;Experiment with single and double quotes to understand that both produce identical string results always.&lt;/li&gt;&#xA;&lt;li&gt;Try storing your Hello World message in a variable to learn about memory and storage.&lt;/li&gt;&#xA;&lt;li&gt;Use comments liberally while learning to annotate what each line does for future reference.&lt;/li&gt;&#xA;&lt;li&gt;Progress from print to f-strings early to understand how dynamic output makes programs more powerful.&lt;/li&gt;&#xA;&lt;li&gt;Run your Python code from the terminal as NetworkChuck recommends to build real command-line confidence.&lt;/li&gt;&#xA;&lt;li&gt;Break your code intentionally to understand error messages which are Python&amp;rsquo;s way of teaching you.&lt;/li&gt;&#xA;&lt;li&gt;Combine multiple words in one print statement using commas to explore how output formatting works.&lt;/li&gt;&#xA;&lt;li&gt;Install Python locally after mastering browser-based environments to experience real development workflow properly.&lt;/li&gt;&#xA;&lt;li&gt;Join coding communities on Discord or Reddit where beginners share their first Hello World proudly.&lt;/li&gt;&#xA;&lt;li&gt;Read Python&amp;rsquo;s official documentation early to build the habit of consulting authoritative sources for answers.&lt;/li&gt;&#xA;&lt;li&gt;Practice daily even if only for ten minutes because consistency beats intensity in learning programming.&lt;/li&gt;&#xA;&lt;li&gt;Challenge yourself to print Hello World five different ways to deeply understand Python&amp;rsquo;s flexible syntax.&lt;/li&gt;&#xA;&lt;li&gt;Teach Hello World to someone else immediately after learning it because teaching solidifies understanding permanently.&lt;/li&gt;&#xA;&lt;li&gt;Use VS Code as your editor since NetworkChuck and most professionals recommend it for Python development.&lt;/li&gt;&#xA;&lt;li&gt;Track your progress by saving every version of your Hello World experiments in organized folders.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;habits&#34;&gt;HABITS&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Type code manually every single day instead of copying to build genuine muscle memory quickly.&lt;/li&gt;&#xA;&lt;li&gt;Read error messages carefully every time because Python&amp;rsquo;s errors are actually helpful instructional feedback always.&lt;/li&gt;&#xA;&lt;li&gt;Comment your code consistently so future you understands exactly what past you was thinking clearly.&lt;/li&gt;&#xA;&lt;li&gt;Experiment fearlessly with modifications because breaking code in a safe environment accelerates real learning dramatically.&lt;/li&gt;&#xA;&lt;li&gt;Review previously written code weekly to notice how much your understanding has genuinely improved over time.&lt;/li&gt;&#xA;&lt;li&gt;Use the terminal daily to run Python files building comfort with command-line interfaces progressively.&lt;/li&gt;&#xA;&lt;li&gt;Watch one coding tutorial video daily from creators like NetworkChuck to stay motivated and inspired.&lt;/li&gt;&#xA;&lt;li&gt;Practice explaining code concepts aloud because verbalization reveals gaps in your understanding very quickly.&lt;/li&gt;&#xA;&lt;li&gt;Save all your practice files organized by date to track your complete programming learning journey.&lt;/li&gt;&#xA;&lt;li&gt;Write at least one new Python program daily even if it only contains a single line.&lt;/li&gt;&#xA;&lt;li&gt;Search Codecademy forums whenever stuck before asking others to build independent problem-solving skills effectively.&lt;/li&gt;&#xA;&lt;li&gt;Test every code example you encounter by actually running it rather than just reading passively.&lt;/li&gt;&#xA;&lt;li&gt;Celebrate small wins like your first Hello World because positive reinforcement sustains long-term learning motivation.&lt;/li&gt;&#xA;&lt;li&gt;Set a consistent coding time each day making programming a non-negotiable daily habit permanently.&lt;/li&gt;&#xA;&lt;li&gt;Review Python documentation regularly even as a beginner to normalize consulting official sources for answers.&lt;/li&gt;&#xA;&lt;li&gt;Share your code with beginner communities regularly to receive feedback and build accountability over time.&lt;/li&gt;&#xA;&lt;li&gt;Refactor your Hello World code in new ways weekly to continuously deepen your foundational Python understanding.&lt;/li&gt;&#xA;&lt;li&gt;Keep a coding journal documenting what you learned each session to reinforce retention significantly.&lt;/li&gt;&#xA;&lt;li&gt;Challenge yourself to write code without looking at references to measure your true comprehension level.&lt;/li&gt;&#xA;&lt;li&gt;Build a portfolio from day one saving even simple Hello World scripts as documented learning artifacts.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;facts&#34;&gt;FACTS&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Python was created by Guido van Rossum and first released publicly in the year 1991.&lt;/li&gt;&#xA;&lt;li&gt;The traditional Hello World program was first popularized in Brian Kernighan&amp;rsquo;s 1972 C programming tutorial.&lt;/li&gt;&#xA;&lt;li&gt;Python consistently ranks as the world&amp;rsquo;s most popular programming language according to multiple annual surveys.&lt;/li&gt;&#xA;&lt;li&gt;The &lt;code&gt;print()&lt;/code&gt; function in Python 3 differs from Python 2 where print was a statement.&lt;/li&gt;&#xA;&lt;li&gt;Codecademy was founded in 2011 and has taught over 50 million people to code worldwide.&lt;/li&gt;&#xA;&lt;li&gt;Python files use the &lt;code&gt;.py&lt;/code&gt; extension which tells the operating system how to execute them.&lt;/li&gt;&#xA;&lt;li&gt;F-strings were officially introduced in Python version 3.6 released in December of the year 2016.&lt;/li&gt;&#xA;&lt;li&gt;Python&amp;rsquo;s name was inspired by Monty Python&amp;rsquo;s Flying Circus not the snake species as assumed.&lt;/li&gt;&#xA;&lt;li&gt;The Python interpreter processes code line by line making debugging easier than compiled languages generally.&lt;/li&gt;&#xA;&lt;li&gt;Strings are immutable in Python meaning once created their individual characters cannot be directly changed.&lt;/li&gt;&#xA;&lt;li&gt;NetworkChuck has over 3 million YouTube subscribers teaching networking and programming to beginners worldwide enthusiastically.&lt;/li&gt;&#xA;&lt;li&gt;Python does not use curly braces for code blocks unlike JavaScript C and Java programming languages.&lt;/li&gt;&#xA;&lt;li&gt;The &lt;code&gt;print()&lt;/code&gt; function can accept multiple arguments separated by commas outputting them with spaces automatically.&lt;/li&gt;&#xA;&lt;li&gt;Python&amp;rsquo;s official style guide PEP 8 recommends using four spaces for indentation throughout all code.&lt;/li&gt;&#xA;&lt;li&gt;Hello World requires zero imports zero classes and zero functions making it Python&amp;rsquo;s most minimal program.&lt;/li&gt;&#xA;&lt;li&gt;Single and double quotes are completely interchangeable for defining strings in Python with identical results.&lt;/li&gt;&#xA;&lt;li&gt;Python runs on Windows Mac and Linux making it the most cross-platform beginner language available.&lt;/li&gt;&#xA;&lt;li&gt;The &lt;code&gt;#&lt;/code&gt; symbol creates single-line comments in Python and these lines are never executed by Python.&lt;/li&gt;&#xA;&lt;li&gt;Python&amp;rsquo;s &lt;code&gt;print()&lt;/code&gt; function automatically adds a newline character after output unless you specify &lt;code&gt;end=&amp;quot;&amp;quot;&lt;/code&gt; explicitly.&lt;/li&gt;&#xA;&lt;li&gt;Stack Overflow&amp;rsquo;s 2023 survey confirmed Python as the most wanted programming language for eleven consecutive years.&lt;/li&gt;&#xA;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Adding Avatar to my Hugo blog</title>
      <link>https://uclab.dev/posts/avatar/</link>
      <pubDate>Thu, 19 Mar 2026 18:56:24 +0000</pubDate>
      <guid>https://uclab.dev/posts/avatar/</guid>
      <description>&lt;p&gt;When I set up this blog using the &lt;a href=&#34;https://github.com/joeroe/risotto&#34;&gt;risotto&lt;/a&gt; Hugo theme, I wanted to add a profile picture to the left sidebar, right below the site title. Sounds simple — and it is, once you know where to look. Here&amp;rsquo;s exactly what I did.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-goal&#34;&gt;The Goal&lt;/h2&gt;&#xA;&lt;p&gt;Add a circular avatar image below the blog title in the sidebar, without touching the theme files directly (so updates don&amp;rsquo;t break anything).&lt;/p&gt;&#xA;&lt;h2 id=&#34;step-1--place-the-image&#34;&gt;Step 1 — Place the Image&lt;/h2&gt;&#xA;&lt;p&gt;Drop your image into the &lt;code&gt;static/&lt;/code&gt; directory at the root of your Hugo site:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Building a Microservice for my Hugo Blog on k3s</title>
      <link>https://uclab.dev/posts/view-counter/</link>
      <pubDate>Thu, 19 Mar 2026 16:54:39 +0000</pubDate>
      <guid>https://uclab.dev/posts/view-counter/</guid>
      <description>&lt;p&gt;A self-hosted view counter for a static Hugo blog — built from scratch&#xA;in Python, containerized, signed, deployed to k3s via GitOps, and&#xA;integrated into the Hugo frontend. No third-party services. Every piece&#xA;runs in the cluster.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;images/gemini16.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;architecture&#34;&gt;Architecture&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Visitor loads post&#xA;    ↓&#xA;Hugo frontend JS → POST /views/{slug} → view-counter API&#xA;                → GET  /views/{slug} → display count&#xA;                         ↓&#xA;                   FastAPI (Python)&#xA;                         ↓&#xA;                   PostgreSQL (CNPG)&#xA;                   2 instances, WAL archiving to MinIO&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;CI/CD flow:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kubernetes Port Configuration</title>
      <link>https://uclab.dev/posts/kubernetes-port-configuration/</link>
      <pubDate>Thu, 19 Mar 2026 14:55:05 +0000</pubDate>
      <guid>https://uclab.dev/posts/kubernetes-port-configuration/</guid>
      <description>&lt;h2 id=&#34;key-insight-the-full-traffic-chain&#34;&gt;Key Insight: The Full Traffic Chain&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Internet&#xA;   ↓&#xA;Ingress  (routes by hostname/path → service name + service port)&#xA;   ↓&#xA;Service  (port → targetPort)&#xA;   ↓&#xA;Pod/Container  (containerPort / what the process actually binds)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Each arrow is where a &lt;strong&gt;port number must match its neighbour&lt;/strong&gt;. A mismatch at any link causes traffic to silently fail to route.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;images/gemini15.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;containerport-is-documentation-only&#34;&gt;&lt;code&gt;containerPort&lt;/code&gt; is Documentation Only&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;containers&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;containerPort&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3005&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# ← has NO effect on actual network behaviour&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;This is purely informational — a hint for humans and tooling.&lt;/li&gt;&#xA;&lt;li&gt;Kubernetes does &lt;strong&gt;not&lt;/strong&gt; use it to expose or map any port.&lt;/li&gt;&#xA;&lt;li&gt;The container listens on whatever port its process actually binds to.&lt;/li&gt;&#xA;&lt;li&gt;The container will still listen on its default port (e.g. 80) regardless of what &lt;code&gt;containerPort&lt;/code&gt; says.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;[!note] Edge case&#xA;Some tools (e.g. &lt;code&gt;kubectl port-forward&lt;/code&gt;) can use &lt;strong&gt;named ports&lt;/strong&gt; defined here, but the field has zero effect on actual network routing.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Self-Hosting Meilisearch Search for a Hugo Blog on k3s</title>
      <link>https://uclab.dev/posts/meilsearch/</link>
      <pubDate>Sun, 15 Mar 2026 19:58:08 +0000</pubDate>
      <guid>https://uclab.dev/posts/meilsearch/</guid>
      <description>&lt;p&gt;Adding search to a static Hugo blog without relying on Algolia or any&#xA;third-party service. Everything runs in the cluster — Meilisearch as a&#xA;pod, secrets managed via HashiCorp Vault and External Secrets Operator,&#xA;the index populated by the CI pipeline on every deploy, and the search&#xA;endpoint exposed through Cloudflare Tunnel.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;images/gemini15.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-meilisearch&#34;&gt;Why Meilisearch&lt;/h2&gt;&#xA;&lt;p&gt;Hugo is a static site generator — there is no server-side logic, no&#xA;database, no search. The common solutions are either paying for Algolia&#xA;or embedding a client-side library like Lunr.js that downloads the&#xA;entire index to the browser.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Bash Scripting Logical Operators</title>
      <link>https://uclab.dev/posts/bash-scripting-logical-operators/</link>
      <pubDate>Fri, 13 Mar 2026 14:32:22 +0000</pubDate>
      <guid>https://uclab.dev/posts/bash-scripting-logical-operators/</guid>
      <description>&lt;ol&gt;&#xA;&lt;li&gt;AND: &amp;amp;&amp;amp;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Run the second command only if the first succeeds:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir mydir &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; cd mydir&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git pull &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Pull successful&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#xA;&lt;li&gt;OR: ||&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Run the second command only if the first fails:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd mydir &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; mkdir mydir&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;command -v docker &amp;amp;&amp;gt;/dev/null &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; sudo apt install docker&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#xA;&lt;li&gt;Chaining&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&amp;amp;&amp;amp; and || are your bread and butter. They check exit codes.&lt;/p&gt;&#xA;&lt;p&gt;This is why exit codes matter - they drive conditional execution.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd project &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; mkdir project &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; cd project&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./run-tests &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./deploy &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Tests failed!&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#xA;&lt;li&gt;The [[]] Test command - Security Critical&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;“Single brackets are a security vulnerability. Double brackets. Always. No exceptions.”&lt;/strong&gt;*&lt;/p&gt;</description>
    </item>
    <item>
      <title>Bash Scripting - Handling Defaults</title>
      <link>https://uclab.dev/posts/bash-scripting/</link>
      <pubDate>Fri, 13 Mar 2026 07:44:42 +0000</pubDate>
      <guid>https://uclab.dev/posts/bash-scripting/</guid>
      <description>&lt;h2 id=&#34;persistent-vs-temporary&#34;&gt;Persistent vs. Temporary&lt;/h2&gt;&#xA;&lt;h3 id=&#34;vardefault--the-persistent-assignment&#34;&gt;${var:=default} — The Persistent Assignment&lt;/h3&gt;&#xA;&lt;p&gt;Logic: If $var is empty or unset, set $var to default and then return that value.&lt;/p&gt;&#xA;&lt;p&gt;Example:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ubuntu in 🌐 cato in ~&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ echo $name&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ubuntu in 🌐 cato in ~&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;name:=User&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;User&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ubuntu in 🌐 cato in ~&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ echo $name&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;User&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#xA;&lt;li&gt;name=&amp;quot;&amp;quot; (name is empty)&lt;/li&gt;&#xA;&lt;li&gt;echo &amp;ldquo;${name:=User}&amp;rdquo;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Bash sees name is empty.&lt;/li&gt;&#xA;&lt;li&gt;It assigns &amp;ldquo;User&amp;rdquo; to the variable name&lt;/li&gt;&#xA;&lt;li&gt;It then prints &amp;ldquo;User&amp;rdquo;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;echo $name now prints &amp;ldquo;User&amp;rdquo; because the variable was actually changed.Bash&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The = stands for equal, as in &amp;ldquo;Make the variable equal to this from now on.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Pandoc Instant Markdown-to-HTML</title>
      <link>https://uclab.dev/posts/pandoc/</link>
      <pubDate>Wed, 11 Mar 2026 19:13:39 +0000</pubDate>
      <guid>https://uclab.dev/posts/pandoc/</guid>
      <description>&lt;p&gt;If you write HTML by hand, you already know the pain of typing &lt;code&gt;&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;&lt;/code&gt; over and over. Here&amp;rsquo;s a trick that lets you write plain Markdown inline and convert it on the spot using &lt;code&gt;pandoc&lt;/code&gt; as a Vim filter.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;images/gemini14.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-basic-idea&#34;&gt;The Basic Idea&lt;/h2&gt;&#xA;&lt;p&gt;Vim&amp;rsquo;s &lt;code&gt;!&lt;/code&gt; command pipes a range of lines through an external program and replaces them with the output. Pandoc reads Markdown on stdin and writes HTML to stdout — a perfect match.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Markdown</title>
      <link>https://uclab.dev/posts/markdown/</link>
      <pubDate>Wed, 11 Mar 2026 17:29:33 +0000</pubDate>
      <guid>https://uclab.dev/posts/markdown/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;images/gemini12.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-is-markdown&#34;&gt;What Is Markdown?&lt;/h2&gt;&#xA;&lt;p&gt;Markdown is a lightweight markup language — a way of adding formatting to plain text using simple punctuation. The idea is that the source file should be readable as-is, without rendering, and that converting it to HTML (or PDF, or DOCX, or anything else) should be trivial.&lt;/p&gt;&#xA;&lt;p&gt;You write this:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-md&#34; data-lang=&#34;md&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;**This is bold** and &lt;span style=&#34;font-style:italic&#34;&gt;*this is italic*&lt;/span&gt;.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And a renderer turns it into: &lt;strong&gt;This is bold&lt;/strong&gt; and &lt;em&gt;this is italic&lt;/em&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Latex KaTex MathJax</title>
      <link>https://uclab.dev/posts/latex/</link>
      <pubDate>Wed, 11 Mar 2026 11:38:41 +0000</pubDate>
      <guid>https://uclab.dev/posts/latex/</guid>
      <description>&lt;p&gt;LaTeX, KaTeX, and MathJax solve different parts of the same problem: representing and rendering mathematical notation with precision.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;images/gemini13.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-is-latex&#34;&gt;What is Latex?&lt;/h2&gt;&#xA;&lt;p&gt;LaTeX (pronounced &amp;ldquo;lah-tech&amp;rdquo; or &amp;ldquo;lay-tech&amp;rdquo;) is a document preparation system used for typesetting high-quality documents, especially those with complex mathematical notation.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Key points:&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Not a word processor&lt;/strong&gt; — you write plain text with markup commands, then compile it to PDF&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Built on TeX&lt;/strong&gt;, a typesetting engine created by Donald Knuth in the 1970s&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;LaTeX&lt;/strong&gt; itself was created by Leslie Lamport in the 1980s as a higher-level layer on top of TeX&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;strong&gt;What it&amp;rsquo;s used for:&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>AKS Cluster: Flux GitOps</title>
      <link>https://uclab.dev/posts/aks-flux-terraform/</link>
      <pubDate>Tue, 10 Mar 2026 08:53:21 +0000</pubDate>
      <guid>https://uclab.dev/posts/aks-flux-terraform/</guid>
      <description>&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;&#xA;&lt;p&gt;In the &lt;a href=&#34;https://uclab.dev/posts/aks-terraform&#34;&gt;previous post&lt;/a&gt;, I walked through the foundational Terraform config for an AKS cluster with Azure Key Vault integration. That was a minimal dev setup — one node, no GitOps, no application secrets.&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://uclab.dev/posts/aks-flux-terraform/images/gemini11.png&#34;&#xA;    alt=&#34;aks-flux-terraform&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;p&gt;This post covers the staging evolution of that config. The new additions are:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A 2-node AKS cluster with a proper staging DNS prefix&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Flux v2&lt;/strong&gt; installed as a cluster extension and wired to a private GitHub repo via SSH&lt;/li&gt;&#xA;&lt;li&gt;A structured &lt;strong&gt;Kustomization&lt;/strong&gt; hierarchy — controllers → configs → apps — with garbage collection&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Auto-generated DB credentials&lt;/strong&gt; stored directly in Key Vault at provision time&lt;/li&gt;&#xA;&lt;li&gt;Terraform &lt;strong&gt;outputs&lt;/strong&gt; that expose Key Vault details and the secrets provider client ID for use in &lt;code&gt;SecretProviderClass&lt;/code&gt; manifests&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;what-changed-from-dev&#34;&gt;What Changed from Dev&lt;/h2&gt;&#xA;&lt;p&gt;The resource group and cluster names now reflect the staging environment (&lt;code&gt;rg-n8n-uclabdev-aks&lt;/code&gt;, &lt;code&gt;n8n-uclabdev-staging&lt;/code&gt;), the node count is bumped to 2, and the DNS prefix is &lt;code&gt;staging&lt;/code&gt;. Everything else — Cilium networking, system-assigned identity, Key Vault secrets provider — carries over unchanged.&lt;/p&gt;</description>
    </item>
    <item>
      <title>AKS with Azure Key Vault Using Terraform</title>
      <link>https://uclab.dev/posts/aks-terraform/</link>
      <pubDate>Tue, 10 Mar 2026 07:58:46 +0000</pubDate>
      <guid>https://uclab.dev/posts/aks-terraform/</guid>
      <description>&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;&#xA;&lt;p&gt;In this post I&amp;rsquo;ll walk through the Terraform configuration I used to spin up an AKS cluster for my &lt;code&gt;uclabdev&lt;/code&gt; environment as part of an n8n self-hosted setup on Azure. The config covers:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;An AKS cluster with Cilium as both the CNI and network policy engine&lt;/li&gt;&#xA;&lt;li&gt;The Azure Key Vault Secrets Provider add-on enabled on the cluster&lt;/li&gt;&#xA;&lt;li&gt;An Azure Key Vault instance with RBAC-based access control&lt;/li&gt;&#xA;&lt;li&gt;Proper role assignments for both the operator and the AKS managed identity&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://uclab.dev/posts/aks-terraform/images/gemini10.png&#34;&#xA;    alt=&#34;aks-terraform&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;authenticating-with-azure-cli&#34;&gt;Authenticating with Azure CLI&lt;/h2&gt;&#xA;&lt;p&gt;Before running Terraform, you need an active Azure CLI session. Since this setup runs inside a dev container, browser-based login isn&amp;rsquo;t always available — device code flow is the reliable fallback:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Cloudflare Tunnels to Securely Expose Kubernetes Services</title>
      <link>https://uclab.dev/posts/cloudflare-tunnels/</link>
      <pubDate>Fri, 06 Mar 2026 08:03:36 +0000</pubDate>
      <guid>https://uclab.dev/posts/cloudflare-tunnels/</guid>
      <description>&lt;p&gt;If you&amp;rsquo;re running a homelab Kubernetes cluster — like my Raspberry Pi 5 cluster — you&amp;rsquo;ve probably hit the same wall: you want to expose a service to the internet, but you don&amp;rsquo;t want to poke holes in your firewall or deal with dynamic IP headaches. Cloudflare Tunnels solve this elegantly. Here&amp;rsquo;s how I wired it all up with &lt;code&gt;cloudflared&lt;/code&gt;, HashiCorp Vault, ExternalSecrets, and FluxCD.&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://uclab.dev/posts/cloudflare-tunnels/images/gemini9.png&#34;&#xA;    alt=&#34;cloudflared-tunnel&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;h2 id=&#34;how-it-works&#34;&gt;How It Works&lt;/h2&gt;&#xA;&lt;p&gt;Cloudflare Tunnels work by running a lightweight daemon (&lt;code&gt;cloudflared&lt;/code&gt;) inside your cluster. This daemon opens an outbound connection to Cloudflare&amp;rsquo;s edge — so no inbound ports need to be opened. Traffic hits &lt;code&gt;yourdomain.com&lt;/code&gt;, Cloudflare routes it through the tunnel, and &lt;code&gt;cloudflared&lt;/code&gt; forwards it to your internal service.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Conventional Commits</title>
      <link>https://uclab.dev/posts/conventional-commits/</link>
      <pubDate>Thu, 05 Mar 2026 08:57:10 +0000</pubDate>
      <guid>https://uclab.dev/posts/conventional-commits/</guid>
      <description>&lt;p&gt;If you&amp;rsquo;re running a DevPod-based development environment and want to enforce &lt;a href=&#34;https://www.conventionalcommits.org/&#34;&gt;Conventional Commits&lt;/a&gt; across your team, this post walks through how to wire up &lt;strong&gt;Commitizen&lt;/strong&gt; and &lt;strong&gt;pre-commit&lt;/strong&gt; automatically — so every developer gets the right hooks installed the moment they enter the container, with zero manual setup.&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://uclab.dev/posts/conventional-commits/images/gemini1.png&#34;&#xA;    alt=&#34;commitizen&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;why-conventional-commits&#34;&gt;Why Conventional Commits?&lt;/h2&gt;&#xA;&lt;p&gt;Conventional Commits give your Git history a consistent, machine-readable structure:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;feat(auth): add OAuth2 login support&#xA;fix(api): handle null response from upstream&#xA;chore(deps): bump helm to 3.14.0&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This unlocks automated changelogs, semantic versioning, and better collaboration signals in pull requests. Commitizen adds a CLI wizard to guide you through writing them; pre-commit enforces the format at commit time so nothing slips through.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Enforcing Image Signing in k3s</title>
      <link>https://uclab.dev/posts/cosign/</link>
      <pubDate>Wed, 04 Mar 2026 19:15:15 +0000</pubDate>
      <guid>https://uclab.dev/posts/cosign/</guid>
      <description>&lt;p&gt;One of the things I wanted to get right in my Pi5 cluster was ensuring that only images I&amp;rsquo;ve actually built and signed can run — no surprises, no unsigned images sneaking into my workloads. This post walks through how I set up &lt;a href=&#34;https://docs.sigstore.dev/policy-controller/overview/&#34;&gt;Sigstore&amp;rsquo;s Policy Controller&lt;/a&gt; with Flux to enforce Cosign image signatures in my &lt;code&gt;uclab&lt;/code&gt; namespace.&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://uclab.dev/posts/cosign/images/gemini2.png&#34;&#xA;    alt=&#34;ClusterImagePolicy&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;h2 id=&#34;the-goal&#34;&gt;The Goal&lt;/h2&gt;&#xA;&lt;p&gt;Every image I deploy to the &lt;code&gt;uclab&lt;/code&gt; namespace is built in my own CI pipeline, pushed to my self-hosted Forgejo registry, and signed with Cosign using a key pair I control. The Policy Controller&amp;rsquo;s job is to sit as an admission webhook and &lt;strong&gt;reject any pod that tries to run an image without a valid signature&lt;/strong&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Hugo Blog — Hardening the Pipeline</title>
      <link>https://uclab.dev/posts/hugo-blog-gitops-hardening/</link>
      <pubDate>Wed, 04 Mar 2026 19:06:41 +0000</pubDate>
      <guid>https://uclab.dev/posts/hugo-blog-gitops-hardening/</guid>
      <description>&lt;h2 id=&#34;securing-the-cicd-chain&#34;&gt;Securing the CI/CD Chain&lt;/h2&gt;&#xA;&lt;p&gt;In the &lt;a href=&#34;https://uclab.dev/posts/hugo-blog-gitops/&#34;&gt;previous post&lt;/a&gt; we built a full GitOps pipeline: push to Forgejo, build a Hugo image, ship it to k3s via Flux. It worked. But it was naive in a few ways — running nginx as root, no image scanning, no signing, and deploying by mutable tag.&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://uclab.dev/posts/hugo-blog-gitops-hardening/images/gemini3.png&#34;&#xA;    alt=&#34;Hardening&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;p&gt;This post covers the fixes. Three independent improvements, each worth doing on its own:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;Unprivileged nginx&lt;/strong&gt; — drop root from the container entirely&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Trivy&lt;/strong&gt; — scan the image for HIGH/CRITICAL CVEs before it ever touches the registry&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Cosign&lt;/strong&gt; — sign the image so the cluster can verify it came from CI&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;The full updated files are at the bottom. Here is the reasoning behind each change.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kubernetes Architecture</title>
      <link>https://uclab.dev/posts/k8s-arch/</link>
      <pubDate>Wed, 04 Mar 2026 09:13:32 +0000</pubDate>
      <guid>https://uclab.dev/posts/k8s-arch/</guid>
      <description>&lt;figure&gt;&lt;img src=&#34;https://uclab.dev/posts/k8s-arch/images/k8s_arch.jpeg&#34;&#xA;    alt=&#34;K8S&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;If you&amp;rsquo;ve ever stared at a Kubernetes diagram and felt your eyes glaze over, you&amp;rsquo;re not alone. Let&amp;rsquo;s break it down simply.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-two-big-pieces-control-plane--worker-nodes&#34;&gt;The Two Big Pieces: Control Plane &amp;amp; Worker Nodes&lt;/h2&gt;&#xA;&lt;p&gt;Kubernetes splits its responsibilities cleanly into two halves.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;strong&gt;Control Plane&lt;/strong&gt; (the master) is the brain of the cluster. It&amp;rsquo;s made up of four key components:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;API Server&lt;/strong&gt; — every request goes through here, no exceptions&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;etcd&lt;/strong&gt; — a key-value store that holds all cluster state and data&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Scheduler&lt;/strong&gt; — decides which node a new Pod should run on&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Controller Manager&lt;/strong&gt; — constantly watches the cluster and reconciles the actual state with the desired state (think Replica, Node, and Job controllers)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The &lt;strong&gt;Worker Nodes&lt;/strong&gt; (minions) are where your actual workloads run. Each node runs:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Self-hosting Umami Analytics</title>
      <link>https://uclab.dev/posts/umami/</link>
      <pubDate>Tue, 03 Mar 2026 11:04:08 +0000</pubDate>
      <guid>https://uclab.dev/posts/umami/</guid>
      <description>&lt;p&gt;I wanted to add visitor analytics to this blog without relying on Google Analytics or any third-party cloud service. &lt;a href=&#34;https://umami.is&#34;&gt;Umami&lt;/a&gt; is a great fit — it&amp;rsquo;s open source, privacy-friendly, GDPR-compliant, and self-hostable. This post covers how I deployed it on my k3s cluster using Cilium Gateway API and Cloudflare Tunnels, and the one gotcha that had me debugging for longer than I&amp;rsquo;d like to admit.&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://uclab.dev/posts/umami/images/gemini4.png&#34;&#xA;    alt=&#34;Analytics&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;h2 id=&#34;stack&#34;&gt;Stack&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;k3s&lt;/strong&gt; — lightweight Kubernetes running on a Raspberry Pi 5 cluster&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;CloudNative PG (CNPG)&lt;/strong&gt; — Postgres operator for the Umami database&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Cloudflare Tunnels&lt;/strong&gt; — for exposing services to the internet without opening ports&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Umami 3.0.3&lt;/strong&gt; — the analytics server itself&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;database&#34;&gt;Database&lt;/h2&gt;&#xA;&lt;p&gt;I use CloudNative PG to manage the Postgres cluster. Two instances for HA, with WAL archiving to an object store via the barman-cloud plugin.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Automating Renovate PR Reviews with n8n</title>
      <link>https://uclab.dev/posts/automating-prs-with-n8n/</link>
      <pubDate>Mon, 02 Mar 2026 17:16:08 +0000</pubDate>
      <guid>https://uclab.dev/posts/automating-prs-with-n8n/</guid>
      <description>&lt;h2 id=&#34;the-problem-renovate-bot-is-prolific&#34;&gt;The Problem: Renovate Bot is Prolific&lt;/h2&gt;&#xA;&lt;p&gt;If you run a Kubernetes homelab with &lt;a href=&#34;https://docs.renovatebot.com/&#34;&gt;Renovate Bot&lt;/a&gt;, you know the drill. Every morning you wake up to a flood of open pull requests — patch updates, minor bumps, the occasional major version change. Each one needs a decision: safe to merge, needs a closer look, or definitely hands-off.&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://uclab.dev/posts/automating-prs-with-n8n/images/gemini5.png&#34;&#xA;    alt=&#34;automation&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;p&gt;Doing this manually gets old fast. But blindly auto-merging everything is a bad idea too — you really don&amp;rsquo;t want Renovate silently bumping your CloudNativePG major version at 2am.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Forgejo on K3S</title>
      <link>https://uclab.dev/posts/forgejo/</link>
      <pubDate>Sun, 01 Mar 2026 19:30:11 +0000</pubDate>
      <guid>https://uclab.dev/posts/forgejo/</guid>
      <description>&lt;p&gt;Forgejo is a lightweight, self-hosted Git service — a community fork of Gitea. In this post I&amp;rsquo;ll walk through how I deployed it on my home k3s cluster backed by a CloudNativePG (CNPG) PostgreSQL database, MinIO S3-compatible object storage for backups, and exposed it via Cilium&amp;rsquo;s Gateway API with automatic TLS through cert-manager.&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://uclab.dev/posts/forgejo/images/gemini6.png&#34;&#xA;    alt=&#34;forgejo&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;h2 id=&#34;architecture-overview&#34;&gt;Architecture Overview&lt;/h2&gt;&#xA;&lt;p&gt;The setup involves three main layers:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;App layer&lt;/strong&gt; — the Forgejo deployment, services, and ingress (Gateway + HTTPRoute)&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Database layer&lt;/strong&gt; — a CloudNativePG PostgreSQL cluster with WAL archiving to MinIO&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Secrets layer&lt;/strong&gt; — External Secrets Operator pulling credentials from Vault&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Here&amp;rsquo;s the directory structure I&amp;rsquo;m using in my GitOps repo:&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to Safely Upgrade a k3s Cluster</title>
      <link>https://uclab.dev/posts/k3s-cluster-upgrade/</link>
      <pubDate>Sun, 01 Mar 2026 19:14:12 +0000</pubDate>
      <guid>https://uclab.dev/posts/k3s-cluster-upgrade/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been running a small home k3s cluster for a while now — one Raspberry Pi 5 as the control plane and two Intel NUC8i7s as workers. It&amp;rsquo;s a fun setup, but upgrading Kubernetes always feels like it deserves a bit of care. This post documents how I think about and execute k3s upgrades for this specific setup.&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://uclab.dev/posts/k3s-cluster-upgrade/images/gemini7.png&#34;&#xA;    alt=&#34;upgrading&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;h2 id=&#34;my-cluster-layout&#34;&gt;My Cluster Layout&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;NAME     ROLE            IP             OS              ARCH&#xA;athena   control-plane   10.10.10.244   Ubuntu 24.04    arm64 (Pi 5)&#xA;nuc242   worker          10.10.10.242   Ubuntu 24.04    amd64&#xA;nuc243   worker          10.10.10.243   Ubuntu 24.04    amd64&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A few things worth noting about this setup:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Hugo End-to-End Security</title>
      <link>https://uclab.dev/posts/hugo-blog-security-hardening/</link>
      <pubDate>Sun, 01 Mar 2026 17:12:37 +0000</pubDate>
      <guid>https://uclab.dev/posts/hugo-blog-security-hardening/</guid>
      <description>&lt;h2 id=&#34;-hardened-hugo--nginx-static-site-on-kubernetes-pss-restricted&#34;&gt;🔐 Hardened Hugo + NGINX Static Site on Kubernetes (PSS Restricted)&lt;/h2&gt;&#xA;&lt;p&gt;This guide provides a &lt;strong&gt;production-grade, defense-in-depth setup&lt;/strong&gt; for deploying a Hugo static site using NGINX inside Kubernetes with:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Non-root container&lt;/li&gt;&#xA;&lt;li&gt;Read-only root filesystem&lt;/li&gt;&#xA;&lt;li&gt;Dropped Linux capabilities&lt;/li&gt;&#xA;&lt;li&gt;Seccomp RuntimeDefault&lt;/li&gt;&#xA;&lt;li&gt;No privilege escalation&lt;/li&gt;&#xA;&lt;li&gt;Secure NGINX configuration&lt;/li&gt;&#xA;&lt;li&gt;Writable ephemeral mounts only where required&lt;/li&gt;&#xA;&lt;li&gt;NetworkPolicy isolation&lt;/li&gt;&#xA;&lt;li&gt;Image scanning &amp;amp; signing&lt;/li&gt;&#xA;&lt;li&gt;GitOps-ready deployment&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://uclab.dev/posts/hugo-blog-security-hardening/images/gemini8.png&#34;&#xA;    alt=&#34;security&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;secure-dockerfile&#34;&gt;Secure Dockerfile&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ---------- Stage 1: Build Hugo site ----------&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;hugomods/hugo:0.157.0&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;builder&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;WORKDIR&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/site&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;COPY&lt;/span&gt; . .&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;RUN&lt;/span&gt; hugo --minify&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ---------- Stage 2: Hardened NGINX ----------&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;nginx:1.28-alpine&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Remove default config&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;RUN&lt;/span&gt; rm /etc/nginx/conf.d/default.conf&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Create writable directories required by nginx&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;RUN&lt;/span&gt; mkdir -p /var/cache/nginx &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; mkdir -p /var/run &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; chown -R nginx:nginx /var/cache/nginx /var/run /usr/share/nginx/html&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Copy static site&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;COPY&lt;/span&gt; --from&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;builder /site/public /usr/share/nginx/html&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Copy hardened nginx config&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;COPY&lt;/span&gt; nginx.conf /etc/nginx/conf.d/default.conf&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Fix ownership and permissions&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;RUN&lt;/span&gt; chown -R nginx:nginx /usr/share/nginx/html &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; chmod -R &lt;span style=&#34;color:#ae81ff&#34;&gt;755&lt;/span&gt; /usr/share/nginx/html&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Run as non-root&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;USER&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;nginx&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;EXPOSE&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;8080&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CMD&lt;/span&gt; [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nginx&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-g&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;daemon off;&amp;#34;&lt;/span&gt;]&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#xA;&lt;h2 id=&#34;hardened-nginxconf&#34;&gt;Hardened nginx.conf&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;server&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;default_server&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;server_name&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;_&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;root&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/usr/share/nginx/html&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;index&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;index.html&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;server_tokens&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;off&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;access_log&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/dev/stdout&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;error_log&lt;/span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;/dev/stderr&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;warn&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;gzip_static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;on&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Security headers&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;X-Content-Type-Options&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nosniff&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;always&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;X-Frame-Options&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DENY&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;always&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;Referrer-Policy&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;strict-origin-when-cross-origin&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;always&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;X-XSS-Protection&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&lt;/span&gt;; &lt;span style=&#34;color:#f92672&#34;&gt;mode=block&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;always&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;Strict-Transport-Security&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;max-age=31536000&lt;/span&gt;; &lt;span style=&#34;color:#f92672&#34;&gt;includeSubDomains&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;always&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;location&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;try_files&lt;/span&gt; $uri $uri/ $uri.html =&lt;span style=&#34;color:#ae81ff&#34;&gt;404&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;location&lt;/span&gt; ~&lt;span style=&#34;color:#e6db74&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;\.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)&lt;/span&gt;$ {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;expires&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;1y&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;Cache-Control&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;public,&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;immutable&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;access_log&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;off&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;location&lt;/span&gt; ~&lt;span style=&#34;color:#e6db74&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;\.html&lt;/span&gt;$ {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;Cache-Control&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;no-cache&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;location&lt;/span&gt; ~ &lt;span style=&#34;color:#e6db74&#34;&gt;/\.(?!well-known).*&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;deny&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;all&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#xA;&lt;h2 id=&#34;hardened-kubernetes-deployment&#34;&gt;Hardened Kubernetes Deployment&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;v1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Namespace&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;uclab&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;labels&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;pod-security.kubernetes.io/enforce&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;restricted&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;apps/v1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Deployment&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;uclab&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;namespace&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;uclab&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;replicas&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;strategy&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;type&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Recreate&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;selector&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;matchLabels&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;app&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;uclab&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;template&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;labels&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;app&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;uclab&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;automountServiceAccountToken&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;imagePullSecrets&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;forgejo-registry&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;securityContext&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;runAsNonRoot&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;runAsUser&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;runAsGroup&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;fsGroup&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;seccompProfile&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;type&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;RuntimeDefault&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;containers&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nginx&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;forgejo.uclab.dev/affragak/uclab:338e164&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;securityContext&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;allowPrivilegeEscalation&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;readOnlyRootFilesystem&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;capabilities&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;drop&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                - &lt;span style=&#34;color:#ae81ff&#34;&gt;ALL&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#f92672&#34;&gt;containerPort&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;protocol&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;TCP&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;resources&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;requests&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;cpu&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;50m&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;memory&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;32Mi&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;limits&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;cpu&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;200m&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;memory&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;64Mi&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;readinessProbe&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;httpGet&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;path&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;initialDelaySeconds&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;periodSeconds&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;livenessProbe&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;httpGet&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;path&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;initialDelaySeconds&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;periodSeconds&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;volumeMounts&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tmp&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;mountPath&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/tmp&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nginx-cache&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;mountPath&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/var/cache/nginx&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nginx-run&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;mountPath&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/var/run&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;restartPolicy&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Always&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tmp&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;emptyDir&lt;/span&gt;: {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nginx-cache&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;emptyDir&lt;/span&gt;: {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nginx-run&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;emptyDir&lt;/span&gt;: {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#xA;&lt;h2 id=&#34;networkpolicy-zero-trust-model&#34;&gt;NetworkPolicy (Zero Trust Model)&lt;/h2&gt;&#xA;&lt;p&gt;Allow ingress only from cloudflared pods:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Hugo Blog — Full CI/CD GitOps</title>
      <link>https://uclab.dev/posts/hugo-blog-gitops/</link>
      <pubDate>Sun, 01 Mar 2026 07:39:04 +0000</pubDate>
      <guid>https://uclab.dev/posts/hugo-blog-gitops/</guid>
      <description>&lt;h2 id=&#34;forgejo--k3s-with-flux&#34;&gt;Forgejo → k3s with Flux&lt;/h2&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; Hugo + Risotto theme (git submodule) → Forgejo Actions → Forgejo Container Registry → k3s → Flux&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Flow:&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;git push &#xA;→ Forgejo Actions builds Hugo image &#xA;→ pushes to Forgejo registry&#xA;→ updates image tag in k8s manifest &#xA;→ commits back to repo&#xA;→ Flux detects commit &#xA;→ applies Deployment &#xA;→ k3s rolls out new image&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;No Bitnami charts. No Flux image automation controllers. No runtime git cloning. Just a plain nginx Deployment running your pre-built static site.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Self-Hosting n8n on k3s</title>
      <link>https://uclab.dev/posts/n8n-self-host/</link>
      <pubDate>Fri, 27 Feb 2026 12:02:07 +0000</pubDate>
      <guid>https://uclab.dev/posts/n8n-self-host/</guid>
      <description>&lt;p&gt;This post walks through deploying &lt;a href=&#34;https://n8n.io/&#34;&gt;n8n&lt;/a&gt; on a local k3s cluster with production-grade practices: a CloudNativePG-managed PostgreSQL cluster, continuous backups to MinIO via Barman, GitOps with Flux, secrets from Vault via External Secrets Operator, and a hardened pod security posture.&lt;/p&gt;&#xA;&lt;h2 id=&#34;stack&#34;&gt;Stack&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;k3s&lt;/strong&gt; — lightweight Kubernetes for bare-metal/homelab&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;CloudNativePG (CNPG)&lt;/strong&gt; — Postgres operator with built-in HA and backup&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Barman Cloud Plugin&lt;/strong&gt; — WAL archiving and point-in-time recovery to S3/MinIO&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;MinIO&lt;/strong&gt; — self-hosted S3-compatible object storage&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Flux&lt;/strong&gt; — GitOps continuous delivery&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;External Secrets Operator + Vault&lt;/strong&gt; — secret management&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Cloudflare Tunnel&lt;/strong&gt; — secure ingress without exposing ports&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;1-namespace&#34;&gt;1. Namespace&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kubectl create namespace n8n&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#xA;&lt;h2 id=&#34;2-postgresql-cluster-with-cloudnativepg&#34;&gt;2. PostgreSQL Cluster with CloudNativePG&lt;/h2&gt;&#xA;&lt;p&gt;CNPG handles HA, replication, and automated failover. We use 2 instances (primary + async standby) spread across nodes.&lt;/p&gt;</description>
    </item>
    <item>
      <title>The Linux File Descriptor</title>
      <link>https://uclab.dev/posts/proc-filesystem/</link>
      <pubDate>Thu, 26 Feb 2026 09:45:25 +0000</pubDate>
      <guid>https://uclab.dev/posts/proc-filesystem/</guid>
      <description>&lt;h2 id=&#34;what-does-echo-hello--proc1fd1-actually-do&#34;&gt;What Does &lt;code&gt;echo &amp;quot;Hello&amp;quot; &amp;gt; /proc/1/fd/1&lt;/code&gt; Actually Do?&lt;/h2&gt;&#xA;&lt;p&gt;If you&amp;rsquo;ve spent time debugging containers or reading shell scripts, you may have stumbled across a curious one-liner:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt; &amp;gt; /proc/1/fd/1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At first glance it looks like magic. Let&amp;rsquo;s break it down piece by piece.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;the-proc-filesystem&#34;&gt;The &lt;code&gt;/proc&lt;/code&gt; Filesystem&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;/proc&lt;/code&gt; is a &lt;strong&gt;virtual filesystem&lt;/strong&gt; built into the Linux kernel. It doesn&amp;rsquo;t exist on disk — it&amp;rsquo;s generated on the fly by the kernel to expose information about running processes, system resources, and hardware.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Audiocodes SBC Webex Calling &amp; Twilio Pstn</title>
      <link>https://uclab.dev/posts/audiocodes-sbc-webex-calling-twilio-pstn/</link>
      <pubDate>Sun, 22 Feb 2026 13:04:26 +0000</pubDate>
      <guid>https://uclab.dev/posts/audiocodes-sbc-webex-calling-twilio-pstn/</guid>
      <description>&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;&#xA;&lt;p&gt;Running a full end-to-end SIP trunk lab that bridges Webex Calling to the PSTN via Twilio is a great way to understand how a Session Border Controller (SBC) sits in the middle of modern cloud telephony. In this post I&amp;rsquo;ll walk through my home lab setup where an AudioCodes Mediant SW SBC — deployed on VMware ESXi — interconnects a Webex Calling sandbox and a Twilio free-tier PSTN account.&lt;/p&gt;</description>
    </item>
    <item>
      <title>BGP Redistribute-Internal</title>
      <link>https://uclab.dev/posts/bgp-redistribute-internal/</link>
      <pubDate>Fri, 20 Feb 2026 08:47:34 +0000</pubDate>
      <guid>https://uclab.dev/posts/bgp-redistribute-internal/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;Throughout this BGP series, I&amp;rsquo;ve covered attributes, policies, and mechanisms that control BGP behavior within the BGP domain – how routes are selected, advertised, and propagated through BGP. But what happens when you need to move routes &lt;strong&gt;out of BGP&lt;/strong&gt; and into an IGP like OSPF or EIGRP?&lt;/p&gt;&#xA;&lt;p&gt;Redistribution from BGP to IGP is common in enterprise networks:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;BGP handles external connectivity (Internet, MPLS, partners)&lt;/li&gt;&#xA;&lt;li&gt;IGP handles internal routing (OSPF, EIGRP within the AS)&lt;/li&gt;&#xA;&lt;li&gt;Redistribution bridges the two domains&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;But there&amp;rsquo;s a critical default behavior most engineers discover the hard way:&lt;/p&gt;</description>
    </item>
    <item>
      <title>BGP Multipath</title>
      <link>https://uclab.dev/posts/bgp-multi-paths/</link>
      <pubDate>Fri, 20 Feb 2026 08:20:21 +0000</pubDate>
      <guid>https://uclab.dev/posts/bgp-multi-paths/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;Throughout this BGP series, I&amp;rsquo;ve covered numerous attributes that influence &lt;strong&gt;which single path&lt;/strong&gt; BGP selects as best:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://uclab.dev/posts/bgp-attributes-weight&#34;&gt;&lt;strong&gt;Weight&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&#34;https://uclab.dev/posts/bgp-attributes-local-pref&#34;&gt;&lt;strong&gt;Local Preference&lt;/strong&gt;&lt;/a&gt;: Control outbound path selection&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://uclab.dev/posts/bgp-attributes-as-path&#34;&gt;&lt;strong&gt;AS-Path&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&#34;https://uclab.dev/posts/bgp-attributes-med&#34;&gt;&lt;strong&gt;MED&lt;/strong&gt;&lt;/a&gt;: Influence path decisions&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://uclab.dev/posts/bgp-attributes-community-standard&#34;&gt;&lt;strong&gt;Communities&lt;/strong&gt;&lt;/a&gt;: Signal routing policies&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;But all of these mechanisms follow the same fundamental principle: &lt;strong&gt;BGP selects one best path&lt;/strong&gt; per prefix. Even if you have multiple equal-cost paths to a destination, by default, BGP picks one and discards the rest.&lt;/p&gt;&#xA;&lt;p&gt;That&amp;rsquo;s where &lt;strong&gt;BGP Multipath&lt;/strong&gt; comes in.&lt;/p&gt;</description>
    </item>
    <item>
      <title>BGP Conditional Advertisement</title>
      <link>https://uclab.dev/posts/bgp-conditional-advertisement/</link>
      <pubDate>Fri, 20 Feb 2026 07:35:27 +0000</pubDate>
      <guid>https://uclab.dev/posts/bgp-conditional-advertisement/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;In all the previous BGP posts, route advertisements have been static – you configure a &lt;code&gt;network&lt;/code&gt; statement or redistribution, and the route is advertised continuously to configured neighbors. But what if you need advertisements to be &lt;strong&gt;dynamic&lt;/strong&gt;, appearing and disappearing based on network conditions?&lt;/p&gt;&#xA;&lt;p&gt;That&amp;rsquo;s what &lt;strong&gt;BGP Conditional Advertisement&lt;/strong&gt; solves.&lt;/p&gt;&#xA;&lt;p&gt;Conditional advertisement allows you to say: &amp;ldquo;Only advertise route X to neighbor Y &lt;strong&gt;if&lt;/strong&gt; route Z exists in the BGP table&amp;rdquo; (or conversely, &amp;ldquo;&lt;strong&gt;if&lt;/strong&gt; route Z does NOT exist&amp;rdquo;). This enables sophisticated scenarios like:&lt;/p&gt;</description>
    </item>
    <item>
      <title>BGP Attributes: Standard Community</title>
      <link>https://uclab.dev/posts/bgp-attributes-community-standard/</link>
      <pubDate>Thu, 19 Feb 2026 10:21:11 +0000</pubDate>
      <guid>https://uclab.dev/posts/bgp-attributes-community-standard/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;In the previous posts, I&amp;rsquo;ve covered BGP attributes that control traffic flow:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://uclab.dev/posts/bgp-attributes-weight&#34;&gt;&lt;strong&gt;Weight&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&#34;https://uclab.dev/posts/bgp-attributes-local-pref&#34;&gt;&lt;strong&gt;Local Preference&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&#34;https://uclab.dev/posts/bgp-attributes-as-path&#34;&gt;&lt;strong&gt;AS-Path&lt;/strong&gt;&lt;/a&gt;: Control which path traffic takes&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://uclab.dev/posts/bgp-attributes-med&#34;&gt;&lt;strong&gt;MED&lt;/strong&gt;&lt;/a&gt;: Influence inbound traffic selection&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Now it&amp;rsquo;s time for a different kind of BGP attribute: &lt;strong&gt;BGP Communities&lt;/strong&gt;. Instead of influencing which path to take, communities control &lt;strong&gt;how far routes propagate&lt;/strong&gt; through the network.&lt;/p&gt;&#xA;&lt;p&gt;BGP Communities are tags attached to routes that signal routing policy information. Think of them as labels that say &amp;ldquo;hey, treat this route specially.&amp;rdquo; The two most fundamental standard communities are:&lt;/p&gt;</description>
    </item>
    <item>
      <title>BGP Attributes: AS-Path</title>
      <link>https://uclab.dev/posts/bgp-attributes-as-path/</link>
      <pubDate>Wed, 18 Feb 2026 12:48:18 +0000</pubDate>
      <guid>https://uclab.dev/posts/bgp-attributes-as-path/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;So far in the BGP Attributes series, I&amp;rsquo;ve covered three traffic control mechanisms:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://uclab.dev/posts/bgp-attributes-weight&#34;&gt;&lt;strong&gt;Weight&lt;/strong&gt;&lt;/a&gt;: Router-local outbound control (Cisco proprietary, never propagates)&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://uclab.dev/posts/bgp-attributes-local-pref&#34;&gt;&lt;strong&gt;Local Preference&lt;/strong&gt;&lt;/a&gt;: AS-wide outbound control (propagates via iBGP)&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://uclab.dev/posts/bgp-attributes-med&#34;&gt;&lt;strong&gt;MED&lt;/strong&gt;&lt;/a&gt;: Inbound influence to neighboring AS (limited scope)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Now it&amp;rsquo;s time for the most versatile BGP traffic engineering tool: &lt;strong&gt;AS-Path manipulation&lt;/strong&gt;, specifically &lt;strong&gt;AS-Path prepending&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;p&gt;AS-Path prepending is unique because it:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Controls &lt;strong&gt;both inbound AND outbound&lt;/strong&gt; traffic&lt;/li&gt;&#xA;&lt;li&gt;Works across &lt;strong&gt;multiple AS hops&lt;/strong&gt; (not just directly connected neighbors)&lt;/li&gt;&#xA;&lt;li&gt;Is &lt;strong&gt;universally recognized&lt;/strong&gt; (part of BGP standard, works on all vendors)&lt;/li&gt;&#xA;&lt;li&gt;Uses BGP&amp;rsquo;s &lt;strong&gt;core loop-prevention mechanism&lt;/strong&gt; (AS-Path length) for traffic engineering&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The concept is deceptively simple: make a path look artificially longer by repeating AS numbers, and BGP will naturally avoid it in favor of shorter paths.&lt;/p&gt;</description>
    </item>
    <item>
      <title>BGP Attributes: Weight</title>
      <link>https://uclab.dev/posts/bgp-attributes-weight/</link>
      <pubDate>Wed, 18 Feb 2026 11:38:14 +0000</pubDate>
      <guid>https://uclab.dev/posts/bgp-attributes-weight/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;In the previous posts, I&amp;rsquo;ve covered &lt;a href=&#34;https://uclab.dev/posts/bgp-attributes-local-pref&#34;&gt;Local Preference&lt;/a&gt; for AS-wide outbound traffic control and &lt;a href=&#34;https://uclab.dev/posts/bgp-attributes-med&#34;&gt;MED&lt;/a&gt; for influencing inbound traffic from neighbors. Both attributes affect routing decisions across multiple routers – Local Preference coordinates exit point selection throughout your entire AS, while MED suggests entry points to neighboring ASes.&lt;/p&gt;&#xA;&lt;p&gt;But what if you need to make a routing decision that affects &lt;strong&gt;only one specific router&lt;/strong&gt; without changing anyone else&amp;rsquo;s behavior?&lt;/p&gt;&#xA;&lt;p&gt;That&amp;rsquo;s where &lt;strong&gt;Weight&lt;/strong&gt; comes in. It&amp;rsquo;s Cisco&amp;rsquo;s proprietary attribute that sits at the very top of the BGP best-path algorithm, overriding even Local Preference. Weight is completely local to a single router – it&amp;rsquo;s never advertised to any neighbor, iBGP or eBGP. This makes it perfect for router-specific policy without the coordination overhead.&lt;/p&gt;</description>
    </item>
    <item>
      <title>BGP Attributes: MED</title>
      <link>https://uclab.dev/posts/bgp-attributes-med/</link>
      <pubDate>Wed, 18 Feb 2026 10:45:04 +0000</pubDate>
      <guid>https://uclab.dev/posts/bgp-attributes-med/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;In the &lt;a href=&#34;https://uclab.dev/posts/bgp-attributes-local-pref&#34;&gt;previous post&lt;/a&gt;, I covered Local Preference – BGP&amp;rsquo;s tool for controlling &lt;strong&gt;outbound&lt;/strong&gt; traffic from your AS. Now it&amp;rsquo;s time for the flip side: &lt;strong&gt;MED (Multi-Exit Discriminator)&lt;/strong&gt;, which influences &lt;strong&gt;inbound&lt;/strong&gt; traffic into your AS.&lt;/p&gt;&#xA;&lt;p&gt;While Local Preference tells your routers &amp;ldquo;use this exit,&amp;rdquo; MED tells your neighbors &amp;ldquo;use this entry.&amp;rdquo; It&amp;rsquo;s your way of saying to external autonomous systems: &amp;ldquo;Hey, if you want to reach my networks, I prefer you use this link over that one.&amp;rdquo;&lt;/p&gt;</description>
    </item>
    <item>
      <title>BGP Attributes: Local Preference</title>
      <link>https://uclab.dev/posts/bgp-attributes-local-pref/</link>
      <pubDate>Wed, 18 Feb 2026 10:07:21 +0000</pubDate>
      <guid>https://uclab.dev/posts/bgp-attributes-local-pref/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;Welcome to a new series on &lt;strong&gt;BGP Path Attributes&lt;/strong&gt; – the mechanisms that control how BGP makes routing decisions. While my previous posts focused on route filtering and aggregation, this series dives into how BGP actually chooses the best path when multiple routes to the same destination exist.&lt;/p&gt;&#xA;&lt;p&gt;We&amp;rsquo;re starting with one of the most powerful and commonly used attributes: &lt;strong&gt;Local Preference&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Local Preference is your primary tool for controlling &lt;strong&gt;outbound traffic&lt;/strong&gt; from your autonomous system. When you have multiple exit points to reach external destinations, Local Preference determines which exit your entire AS will prefer. Set it once on the edge router receiving the routes, and every router in your AS will make consistent forwarding decisions.&lt;/p&gt;</description>
    </item>
    <item>
      <title>BGP Route Aggregation: Unsuppress-Maps</title>
      <link>https://uclab.dev/posts/bgp-route-aggregation-unsuppress-maps/</link>
      <pubDate>Tue, 17 Feb 2026 08:50:06 +0000</pubDate>
      <guid>https://uclab.dev/posts/bgp-route-aggregation-unsuppress-maps/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;The previous post on &lt;code&gt;suppress-map&lt;/code&gt; showed how to selectively suppress specific component routes when creating a BGP aggregate. But there&amp;rsquo;s a complementary scenario that comes up just as often in practice: you have a global suppression policy (like &lt;code&gt;summary-only&lt;/code&gt;) applied to an aggregate, and you need to &lt;strong&gt;restore&lt;/strong&gt; one or more suppressed routes to a specific neighbor only.&lt;/p&gt;&#xA;&lt;p&gt;That&amp;rsquo;s what &lt;code&gt;unsuppress-map&lt;/code&gt; does. It operates at the &lt;strong&gt;neighbor level&lt;/strong&gt; and overrides the global suppression for that peer, re-advertising chosen routes that would otherwise stay hidden behind the aggregate.&lt;/p&gt;</description>
    </item>
    <item>
      <title>BGP Route Aggregation: Suppress-Maps</title>
      <link>https://uclab.dev/posts/bgp-route-aggregation-suppress-maps/</link>
      <pubDate>Tue, 17 Feb 2026 08:33:47 +0000</pubDate>
      <guid>https://uclab.dev/posts/bgp-route-aggregation-suppress-maps/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;The previous two posts in this series covered the two ends of the BGP aggregation spectrum:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Default &lt;code&gt;aggregate-address&lt;/code&gt;&lt;/strong&gt;: advertises both the aggregate AND all component routes to everyone&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;summary-only&lt;/code&gt;&lt;/strong&gt;: advertises only the aggregate, suppresses ALL component routes to everyone&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;But real networks rarely fit neatly into either extreme. What if you want to advertise the aggregate alongside &lt;em&gt;some&lt;/em&gt; of the component routes, but suppress &lt;em&gt;others&lt;/em&gt;? That&amp;rsquo;s exactly what &lt;code&gt;suppress-map&lt;/code&gt; solves.&lt;/p&gt;</description>
    </item>
    <item>
      <title>BGP Route Aggregation: Summary-Only Mode</title>
      <link>https://uclab.dev/posts/bgp-route-aggregation-summary-only/</link>
      <pubDate>Tue, 17 Feb 2026 08:09:23 +0000</pubDate>
      <guid>https://uclab.dev/posts/bgp-route-aggregation-summary-only/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;In my &lt;a href=&#34;https://uclab.dev/posts/bgp-route-aggregation&#34;&gt;previous post on BGP Route Aggregation&lt;/a&gt;, I demonstrated how the &lt;code&gt;aggregate-address&lt;/code&gt; command creates a summary route while continuing to advertise the more-specific component routes alongside it. I also showed how to use prefix lists to selectively control which neighbors see the aggregate versus the specifics.&lt;/p&gt;&#xA;&lt;p&gt;But there&amp;rsquo;s a simpler, more direct approach when you want &lt;strong&gt;only&lt;/strong&gt; the summary route advertised to everyone: the &lt;code&gt;summary-only&lt;/code&gt; keyword.&lt;/p&gt;&#xA;&lt;p&gt;This post focuses specifically on this option, what it does under the hood, and how it compares to IGP summarization behavior.&lt;/p&gt;</description>
    </item>
    <item>
      <title>BGP Route Aggregation</title>
      <link>https://uclab.dev/posts/bgp-route-aggregation/</link>
      <pubDate>Sun, 15 Feb 2026 18:09:07 +0000</pubDate>
      <guid>https://uclab.dev/posts/bgp-route-aggregation/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;In my previous posts on BGP filtering, I&amp;rsquo;ve covered Access Control Lists, Prefix Lists, and AS-Path filters – all focused on controlling which routes are accepted or advertised. But there&amp;rsquo;s another critical BGP capability that every network engineer needs to master: &lt;strong&gt;route aggregation&lt;/strong&gt; (also called route summarization).&lt;/p&gt;&#xA;&lt;p&gt;Route aggregation is the practice of combining multiple specific routes into a single, less-specific summary route. This technique serves multiple purposes:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Reduces routing table size&lt;/strong&gt; across the internet&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Improves routing stability&lt;/strong&gt; by hiding network flapping&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Simplifies routing policies&lt;/strong&gt; with fewer routes to manage&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Conserves bandwidth&lt;/strong&gt; by reducing BGP update traffic&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Enhances security&lt;/strong&gt; by hiding internal network details&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;In this post, I&amp;rsquo;ll demonstrate BGP route aggregation using the same lab topology from my &lt;a href=&#34;https://uclab.dev/categories/networking/&#34;&gt;previous BGP posts&lt;/a&gt;, showing you how to create aggregate routes and implement sophisticated policies that advertise different levels of detail to different neighbors.&lt;/p&gt;</description>
    </item>
    <item>
      <title>BGP AS-Path Filtering</title>
      <link>https://uclab.dev/posts/bgp-as-path-filtering/</link>
      <pubDate>Sun, 15 Feb 2026 12:30:20 +0000</pubDate>
      <guid>https://uclab.dev/posts/bgp-as-path-filtering/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;In my previous posts, I explored BGP route filtering using Access Control Lists and Prefix Lists. Both methods filter routes based on network prefixes and subnet masks. But what if you need to filter routes based on where they originated or which autonomous systems they&amp;rsquo;ve traversed?&lt;/p&gt;&#xA;&lt;p&gt;Enter &lt;strong&gt;AS-Path filtering&lt;/strong&gt; – a powerful BGP route manipulation technique that allows you to make routing decisions based on the autonomous system path. Combined with &lt;strong&gt;regular expressions&lt;/strong&gt;, AS-Path filters provide surgical precision in controlling route propagation across complex multi-AS topologies.&lt;/p&gt;</description>
    </item>
    <item>
      <title>BGP Route Filtering with Prefix Lists</title>
      <link>https://uclab.dev/posts/bgp-prefix-list-filtering/</link>
      <pubDate>Sun, 15 Feb 2026 11:17:22 +0000</pubDate>
      <guid>https://uclab.dev/posts/bgp-prefix-list-filtering/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;In my &lt;a href=&#34;https://uclab.dev/posts/bgp-acl-filtering&#34;&gt;previous post&lt;/a&gt;, I explored BGP route filtering using standard Access Control Lists (ACLs). While ACLs are powerful, they have limitations when it comes to matching based on prefix length. Enter &lt;strong&gt;prefix lists&lt;/strong&gt; – a purpose-built tool for route filtering that offers superior control and readability for BGP route manipulation.&lt;/p&gt;&#xA;&lt;p&gt;Prefix lists provide functionality that ACLs simply cannot match: the ability to filter routes based on both network address AND prefix length. This makes them the preferred choice for BGP route filtering in production networks.&lt;/p&gt;</description>
    </item>
    <item>
      <title>BGP Route Filtering in Practice</title>
      <link>https://uclab.dev/posts/bgp-acl-filtering/</link>
      <pubDate>Sun, 15 Feb 2026 10:19:48 +0000</pubDate>
      <guid>https://uclab.dev/posts/bgp-acl-filtering/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;Access Control Lists (ACLs) are one of the most fundamental tools in a network engineer&amp;rsquo;s toolkit. While they&amp;rsquo;re commonly associated with security and packet filtering, ACLs play an equally critical role in route filtering and manipulation. In this post, I&amp;rsquo;ll walk through three real-world scenarios from my lab environment where I used standard access lists with BGP distribute-lists to control route propagation between autonomous systems.&lt;/p&gt;&#xA;&lt;h2 id=&#34;lab-topology&#34;&gt;Lab Topology&lt;/h2&gt;&#xA;&lt;p&gt;My lab consists of six routers spanning multiple autonomous systems:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Bibata Modern Ice Cursor Theme</title>
      <link>https://uclab.dev/posts/cursors-arch-linux/</link>
      <pubDate>Sat, 14 Feb 2026 10:22:24 +0000</pubDate>
      <guid>https://uclab.dev/posts/cursors-arch-linux/</guid>
      <description>&lt;p&gt;If you&amp;rsquo;re running Hyprland on Arch Linux and want to improve your desktop aesthetics, installing a modern cursor theme is a great place to start. The &lt;strong&gt;Bibata Modern Ice&lt;/strong&gt; cursor theme is sleek, professional, and pairs beautifully with modern desktop environments.&lt;/p&gt;&#xA;&lt;p&gt;In this guide, I&amp;rsquo;ll walk you through two methods of installing Bibata Modern Ice: the manual method and using the graphical tool &lt;strong&gt;nwg-look&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-is-bibata-modern-ice&#34;&gt;What is Bibata Modern Ice?&lt;/h2&gt;&#xA;&lt;p&gt;Bibata is a popular cursor theme that offers several variants. The &amp;ldquo;Modern Ice&amp;rdquo; variant features a clean, light blue accent that looks fantastic on dark themes. It&amp;rsquo;s widely used in the Linux community and is the default cursor in many Hyprland configurations, including the popular ML4W dotfiles.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Fixing PGP Signature Errors During Arch Linux Installation</title>
      <link>https://uclab.dev/posts/fix-pgp-arch-linux/</link>
      <pubDate>Sat, 14 Feb 2026 09:19:15 +0000</pubDate>
      <guid>https://uclab.dev/posts/fix-pgp-arch-linux/</guid>
      <description>&lt;p&gt;If you&amp;rsquo;re installing Arch Linux and encounter PGP signature errors during the &lt;code&gt;pacstrap&lt;/code&gt; command, you&amp;rsquo;re not alone.&lt;br&gt;&#xA;This is one of the most common issues faced during Arch installation, but fortunately, it&amp;rsquo;s usually straightforward to fix.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-error&#34;&gt;The Error&lt;/h2&gt;&#xA;&lt;p&gt;The error typically looks something like this:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;error: linux: signature from &amp;#34;...&amp;#34; is invalid&#xA;error: failed to commit transaction (invalid or corrupted package)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;why-this-happens&#34;&gt;Why This Happens&lt;/h2&gt;&#xA;&lt;p&gt;PGP (Pretty Good Privacy) signatures are used to verify that packages haven&amp;rsquo;t been tampered with. The errors occur when:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Fixing Time Synchronization</title>
      <link>https://uclab.dev/posts/fix-time-sync/</link>
      <pubDate>Thu, 12 Feb 2026 07:55:03 +0000</pubDate>
      <guid>https://uclab.dev/posts/fix-time-sync/</guid>
      <description>&lt;p&gt;I recently noticed my Arch Linux system time was consistently 1 hour behind, despite having the correct timezone configured. Here&amp;rsquo;s how I fixed it using systemd&amp;rsquo;s built-in NTP client.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-problem&#34;&gt;The Problem&lt;/h2&gt;&#xA;&lt;p&gt;My system showed the wrong time even though the timezone was correctly set to &lt;code&gt;Europe/Berlin&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ date&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Thu Feb &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt; 09:45:36 AM CET &lt;span style=&#34;color:#ae81ff&#34;&gt;2026&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ stat /etc/localtime&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;File: /etc/localtime -&amp;gt; /usr/share/zoneinfo/Europe/Berlin&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Checking the time sync status revealed the issue:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ timedatectl status&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               Local time: Thu 2026-02-12 09:48:17 CET&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           Universal time: Thu 2026-02-12 08:48:17 UTC&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 RTC time: Thu 2026-02-12 08:48:17&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                Time zone: Europe/Berlin &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;CET, +0100&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;System clock synchronized: no&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              NTP service: inactive&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          RTC in local TZ: no&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The NTP service was &lt;strong&gt;inactive&lt;/strong&gt;, meaning the system wasn&amp;rsquo;t synchronizing with any time servers.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Cat9000v_baseline</title>
      <link>https://uclab.dev/posts/cat9000v_baseline/</link>
      <pubDate>Wed, 11 Feb 2026 08:57:31 +0000</pubDate>
      <guid>https://uclab.dev/posts/cat9000v_baseline/</guid>
      <description>&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ip domain name automation.local&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;hostname iosxe-switch-1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;crypto key generate rsa mod 2048&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;aaa new-model&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;aaa authentication login local&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;aaa authorization exec default local if-authenticated&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ip ssh version 2&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;username admin privilege 15 secret automation&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;enable secret automation&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;int gi0/0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ip add 10.3.19.107 255.255.255.0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;no&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;cdp enable&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;no&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;shut&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ip route vrf Mgmt-vrf 0.0.0.0 0.0.0.0 10.3.19.254&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;no&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;ip http server&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;no&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;ip http secure-server&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;no&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;crypto pki trustpoint SLA-TrustPoint&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ip http secure-server&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;restconf&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;end&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Network Automation with RESTCONF</title>
      <link>https://uclab.dev/posts/restconf/</link>
      <pubDate>Mon, 09 Feb 2026 12:46:52 +0000</pubDate>
      <guid>https://uclab.dev/posts/restconf/</guid>
      <description>&lt;p&gt;Network automation has become essential for modern infrastructure management, and RESTCONF provides a standardized, programmable interface for configuring and managing network devices. In this guide, I&amp;rsquo;ll walk you through practical examples of using RESTCONF with Cisco IOS-XE devices.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-is-restconf&#34;&gt;What is RESTCONF?&lt;/h2&gt;&#xA;&lt;p&gt;RESTCONF is a protocol defined in RFC 8040 that provides a RESTful API for accessing data defined in YANG models. It combines the simplicity of REST APIs with the power of YANG data modeling, making network automation more accessible to developers and network engineers alike.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Nvidia Hyprland</title>
      <link>https://uclab.dev/posts/nvidia-hyprland/</link>
      <pubDate>Sun, 08 Feb 2026 15:22:24 +0000</pubDate>
      <guid>https://uclab.dev/posts/nvidia-hyprland/</guid>
      <description>&lt;p&gt;If you&amp;rsquo;re running Arch Linux with an NVIDIA GPU and want to experience the modern, tiling Wayland compositor Hyprland, you&amp;rsquo;re in for a treat. However, getting NVIDIA to play nicely with Wayland compositors requires some specific configuration. This guide will walk you through the entire setup process.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-this-matters&#34;&gt;Why This Matters&lt;/h2&gt;&#xA;&lt;p&gt;NVIDIA&amp;rsquo;s proprietary drivers have historically been challenging with Wayland compositors. Thanks to recent improvements in the NVIDIA driver stack (especially with the open-source kernel modules), running Hyprland on NVIDIA hardware is now not only possible but performs quite well. The key is proper configuration.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Hugo Git Submodules: Do Not Forget Your Theme!</title>
      <link>https://uclab.dev/posts/hugo-git-submodule-theme/</link>
      <pubDate>Sun, 08 Feb 2026 15:12:39 +0000</pubDate>
      <guid>https://uclab.dev/posts/hugo-git-submodule-theme/</guid>
      <description>&lt;h2 id=&#34;the-problem&#34;&gt;The Problem&lt;/h2&gt;&#xA;&lt;p&gt;After cloning my Hugo blog from GitLab and adding a new post, I ran into a frustrating issue: &lt;code&gt;hugo server&lt;/code&gt; would start successfully, but the site wouldn&amp;rsquo;t render any pages. Instead, I got a blank page with only the livereload script.&lt;/p&gt;&#xA;&lt;p&gt;The build output showed warnings about missing layout files:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;WARN  found no layout file for &amp;#34;html&amp;#34; for kind &amp;#34;term&amp;#34;&#xA;WARN  found no layout file for &amp;#34;html&amp;#34; for kind &amp;#34;section&amp;#34;&#xA;WARN  found no layout file for &amp;#34;html&amp;#34; for kind &amp;#34;taxonomy&amp;#34;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;the-root-cause&#34;&gt;The Root Cause&lt;/h2&gt;&#xA;&lt;p&gt;When I cloned the repository, &lt;strong&gt;the theme directory was empty&lt;/strong&gt;. Hugo themes are typically added as Git submodules, and by default, &lt;code&gt;git clone&lt;/code&gt; doesn&amp;rsquo;t automatically download submodule content.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Dual Booting Arch Linux and Windows 11</title>
      <link>https://uclab.dev/posts/dual_boot/</link>
      <pubDate>Sun, 08 Feb 2026 15:03:24 +0000</pubDate>
      <guid>https://uclab.dev/posts/dual_boot/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;Setting up a dual boot system with Arch Linux and Windows 11 can be challenging, especially when you want to maintain full disk encryption on both operating systems while keeping Secure Boot enabled. This guide documents my journey and the solutions I found to create a secure, encrypted dual boot setup on two separate NVMe drives.&lt;/p&gt;&#xA;&lt;h2 id=&#34;hardware-configuration&#34;&gt;Hardware Configuration&lt;/h2&gt;&#xA;&lt;p&gt;My system consists of:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;nvme0n1&lt;/strong&gt; (953.9GB): Windows 11 drive&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;nvme1n1&lt;/strong&gt; (1.8TB): Arch Linux drive&lt;/li&gt;&#xA;&lt;li&gt;UEFI firmware with Secure Boot enabled&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;initial-setup&#34;&gt;Initial Setup&lt;/h2&gt;&#xA;&lt;p&gt;Both operating systems were already installed:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Setting Up SSH Keys for GitHub on Arch Linux</title>
      <link>https://uclab.dev/posts/ssh_key/</link>
      <pubDate>Sun, 08 Feb 2026 11:38:40 +0000</pubDate>
      <guid>https://uclab.dev/posts/ssh_key/</guid>
      <description>&lt;p&gt;If you&amp;rsquo;re running Arch Linux and want to set up SSH authentication for GitHub, here&amp;rsquo;s a quick guide to get you started. This process allows you to push and pull from GitHub repositories without entering your password every time.&lt;/p&gt;&#xA;&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;&#xA;&lt;p&gt;First, you&amp;rsquo;ll need to install OpenSSH if it&amp;rsquo;s not already on your system:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo pacman -S openssh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;generate-your-ssh-key&#34;&gt;Generate Your SSH Key&lt;/h2&gt;&#xA;&lt;p&gt;Create a new ED25519 SSH key pair with this command:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Cilium LoadBalancer IPAM and BGP Service Advertisement</title>
      <link>https://uclab.dev/posts/cilium_loadbalancer_ipam_and_bgp_service_advertisement/</link>
      <pubDate>Wed, 04 Feb 2026 20:09:50 +0100</pubDate>
      <guid>https://uclab.dev/posts/cilium_loadbalancer_ipam_and_bgp_service_advertisement/</guid>
      <description>&lt;p&gt;In the &lt;a href=&#34;https://uclab.dev/posts/bgp_on_cilium/&#34;&gt;previous post&lt;/a&gt;, we established BGP peering between our Kubernetes cluster and a virtual leaf-spine datacenter fabric, enabling dynamic Pod CIDR advertisement.&lt;/p&gt;&#xA;&lt;p&gt;But Pod connectivity is only half the story.&lt;/p&gt;&#xA;&lt;p&gt;In production Kubernetes environments, &lt;strong&gt;Services&lt;/strong&gt; — especially &lt;code&gt;LoadBalancer&lt;/code&gt; type services — are how applications expose themselves to the outside world. Traditionally, this requires external load balancers like MetalLB or cloud provider integrations.&lt;/p&gt;&#xA;&lt;p&gt;With &lt;strong&gt;Cilium&amp;rsquo;s LoadBalancer IPAM&lt;/strong&gt; and &lt;strong&gt;BGP Service Advertisement&lt;/strong&gt;, we can eliminate that dependency entirely.&lt;/p&gt;</description>
    </item>
    <item>
      <title>BGP on Cilium</title>
      <link>https://uclab.dev/posts/bgp_on_cilium/</link>
      <pubDate>Wed, 04 Feb 2026 13:58:29 +0100</pubDate>
      <guid>https://uclab.dev/posts/bgp_on_cilium/</guid>
      <description>&lt;h1 id=&#34;bgp-on-cilium-peering-kubernetes-with-a-leafspine-datacenter&#34;&gt;BGP on Cilium: Peering Kubernetes with a Leaf‑Spine Datacenter&lt;/h1&gt;&#xA;&lt;p&gt;BGP is not just the routing protocol that powers the Internet — it has become &lt;em&gt;the&lt;/em&gt; standard control plane inside modern data centers.&lt;/p&gt;&#xA;&lt;p&gt;Today’s data centers are typically built using a &lt;strong&gt;leaf–spine architecture&lt;/strong&gt;, where BGP is responsible for distributing reachability information between racks, spines, and endpoints. And when your endpoints are Kubernetes Pods, it makes perfect sense for Kubernetes networking to speak BGP as well.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Path bash script</title>
      <link>https://uclab.dev/posts/path_bash_script/</link>
      <pubDate>Tue, 03 Feb 2026 09:35:19 +0100</pubDate>
      <guid>https://uclab.dev/posts/path_bash_script/</guid>
      <description>&lt;p&gt;A simple one-liner to display your PATH variable with each directory on its own line, demonstrating bash parameter expansion for string manipulation.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-script&#34;&gt;The Script&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/bash&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Description: current path&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;PATH//:/&lt;span style=&#34;color:#e6db74&#34;&gt;$&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/usr/local/sbin&#xA;/usr/local/bin&#xA;/usr/sbin&#xA;/usr/bin&#xA;/sbin&#xA;/bin&#xA;/usr/games&#xA;/usr/local/games&#xA;/snap/bin&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;how-it-works&#34;&gt;How It Works&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;${PATH//:/$&amp;#39;\n&amp;#39;}&#xA;  │    ││ └─────── Replacement: $&amp;#39;\n&amp;#39; (newline)&#xA;  │    │└───────── Pattern: : (colon)&#xA;  │    └────────── // means &amp;#34;replace ALL occurrences&amp;#34;&#xA;  └─────────────── Variable: PATH&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;breakdown&#34;&gt;Breakdown&lt;/h3&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;PATH&lt;/code&gt;&lt;/strong&gt; - Environment variable containing colon-separated directories&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;//:&lt;/code&gt;&lt;/strong&gt; - Replace &lt;strong&gt;all&lt;/strong&gt; colons (&lt;code&gt;:&lt;/code&gt;) globally&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;$&#39;\n&#39;&lt;/code&gt;&lt;/strong&gt; - ANSI-C quoting for actual newline character&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Result&lt;/strong&gt; - Each directory appears on its own line&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;single-vs-double-slash&#34;&gt;Single vs Double Slash&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Single / - replaces FIRST occurrence only&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;PATH/:/&lt;span style=&#34;color:#e6db74&#34;&gt;$&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Output:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# /usr/local/sbin&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# /usr/local/bin:/usr/sbin:/usr/bin...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#                ↑ remaining colons unchanged&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Double // - replaces ALL occurrences&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;PATH//:/&lt;span style=&#34;color:#e6db74&#34;&gt;$&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Output: each directory on separate line ✓&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;parameter-expansion-basics&#34;&gt;Parameter Expansion Basics&lt;/h2&gt;&#xA;&lt;p&gt;The pattern &lt;code&gt;${variable//pattern/replacement}&lt;/code&gt; is called &lt;strong&gt;parameter expansion&lt;/strong&gt; - a built-in bash feature for string manipulation without external commands.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Building a Simple System Information Script in Bash</title>
      <link>https://uclab.dev/posts/sysinfo_bash_script/</link>
      <pubDate>Mon, 02 Feb 2026 18:43:54 +0100</pubDate>
      <guid>https://uclab.dev/posts/sysinfo_bash_script/</guid>
      <description>&lt;p&gt;Ever needed a quick way to check your system&amp;rsquo;s vital stats without memorizing a dozen different commands?&lt;br&gt;&#xA;I created a simple bash script that displays all the essential system information in one clean output.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-it-does&#34;&gt;What It Does&lt;/h2&gt;&#xA;&lt;p&gt;The script displays:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Hostname and current date&lt;/li&gt;&#xA;&lt;li&gt;System uptime&lt;/li&gt;&#xA;&lt;li&gt;Linux distribution and kernel version&lt;/li&gt;&#xA;&lt;li&gt;CPU model and core count&lt;/li&gt;&#xA;&lt;li&gt;Memory usage (total, used, free)&lt;/li&gt;&#xA;&lt;li&gt;Disk space utilization&lt;/li&gt;&#xA;&lt;li&gt;Network information (IPv4, MAC address, gateway, DNS)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;the-script&#34;&gt;The Script&lt;/h2&gt;&#xA;&lt;p&gt;Here&amp;rsquo;s the complete script:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Shebang bash security</title>
      <link>https://uclab.dev/posts/shebang_bash_security/</link>
      <pubDate>Mon, 02 Feb 2026 17:59:04 +0100</pubDate>
      <guid>https://uclab.dev/posts/shebang_bash_security/</guid>
      <description>&lt;p&gt;If you&amp;rsquo;ve written bash scripts, you&amp;rsquo;ve probably used a shebang line at the top.&lt;br&gt;&#xA;But which one should you use: &lt;code&gt;#!/bin/bash&lt;/code&gt; or &lt;code&gt;#!/usr/bin/env bash&lt;/code&gt;?&lt;br&gt;&#xA;And is there really a security risk with the latter?&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-two-approaches&#34;&gt;The Two Approaches&lt;/h2&gt;&#xA;&lt;h3 id=&#34;hardcoded-path-binbash&#34;&gt;Hardcoded Path: &lt;code&gt;#!/bin/bash&lt;/code&gt;&lt;/h3&gt;&#xA;&lt;p&gt;This shebang assumes bash is installed at &lt;code&gt;/bin/bash&lt;/code&gt;. It&amp;rsquo;s direct and predictable—you know exactly which interpreter will run your script.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Predictable execution path&lt;/li&gt;&#xA;&lt;li&gt;Works consistently on most Linux distributions&lt;/li&gt;&#xA;&lt;li&gt;Slightly faster (no PATH lookup needed)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ansible_vlans_playbook</title>
      <link>https://uclab.dev/posts/ansible_vlans_playbook/</link>
      <pubDate>Sat, 29 Nov 2025 17:21:16 +0000</pubDate>
      <guid>https://uclab.dev/posts/ansible_vlans_playbook/</guid>
      <description>&lt;h2 id=&#34;playbook&#34;&gt;Playbook&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#vlans.yaml&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;hosts&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;switches&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;tasks&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Create VLANs&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ios_vlans&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;config&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;vlan_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Printers&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;vlan_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Cameras&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;vlan_id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Guest&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;state&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;merged&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Save to startup-config&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ios_config&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;save_when&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;modified&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;inventory&#34;&gt;Inventory&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#site-a.ini&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;ios]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10.3.19.101&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10.3.19.102&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10.3.19.103&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10.3.19.104&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;ios:vars]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ansible_connection=network_cli&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ansible_network_os=ios&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ansible_user=admin&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ansible_password=automation&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;routers]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10.3.19.101&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10.3.19.102&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;switches]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10.3.19.103&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10.3.19.104&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;run-playbook&#34;&gt;Run Playbook&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible-playbook vlans.yaml -i site-a.ini&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Ansible_install</title>
      <link>https://uclab.dev/posts/ansible_install/</link>
      <pubDate>Sat, 29 Nov 2025 17:07:42 +0000</pubDate>
      <guid>https://uclab.dev/posts/ansible_install/</guid>
      <description>&lt;h2 id=&#34;install&#34;&gt;Install&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -LsSf https://astral.sh/uv/install.sh | sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Source the shell according to the installation output&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uv venv&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;source .venv/bin/activate&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uv pip install ansible-core==2.18 ansible-pylibssh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;module-collection-installation&#34;&gt;Module collection installation&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible-galaxy collection install cisco.ios cisco.nxos cisco.iosxr&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ansible-galaxy collection list | grep cisco&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Clipboard_devcontainer</title>
      <link>https://uclab.dev/posts/clipboard_devcontainer/</link>
      <pubDate>Sun, 23 Nov 2025 11:53:56 +0100</pubDate>
      <guid>https://uclab.dev/posts/clipboard_devcontainer/</guid>
      <description>&lt;p&gt;✂️ Enable Clipboard Copy/Paste in a DevContainer (Neovim + OSC52 + tmux)&lt;/p&gt;&#xA;&lt;p&gt;Clipboard support inside a DevContainer is not available by default, because the container cannot directly access the host clipboard.&lt;br&gt;&#xA;This guide enables seamless yank/copy/paste in Neovim, tmux, and VS Code DevContainers using:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;xclip / wl-clipboard (fallback tools)&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Neovim’s built-in OSC52 clipboard provider&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;tmux OSC52 forwarding&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;dockerfile&#34;&gt;Dockerfile&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#Dockerfile&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;COPY --from=jdxcode/mise /usr/local/bin/mise /usr/local/bin/&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install clipboard utilities&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;RUN apt-get update &amp;amp;&amp;amp; apt-get install -y xclip wl-clipboard &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# make sure mise is activated in both zsh and bash&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;RUN echo &amp;#39;eval &amp;#34;$(mise activate bash)&amp;#34;&amp;#39; &amp;gt;&amp;gt; /home/vscode/.bashrc &amp;amp;&amp;amp; \&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;echo &amp;#39;eval &amp;#34;$(mise activate zsh)&amp;#34;&amp;#39; &amp;gt;&amp;gt; /home/vscode/.zshrc&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;osc52-clipboard-support-in-neovim&#34;&gt;OSC52 Clipboard Support in Neovim&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#options.lua&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;vim.g.snacks_animate = false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;vim.g.lazyvim_check_order = false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;vim.opt.ignorecase = true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;vim.opt.number = false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;vim.opt.relativenumber = false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;vim.opt.scrolloff = 8&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-- &lt;span style=&#34;color:#ae81ff&#34;&gt;Explicitly use OSC 52 for clipboard (best for remote/container environments)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;vim.g.clipboard = {&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;name = &amp;#34;OSC 52&amp;#34;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;copy = {&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;+&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#ae81ff&#34;&gt;= require(&amp;#34;vim.ui.clipboard.osc52&amp;#34;).copy(&amp;#34;+&amp;#34;),&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#ae81ff&#34;&gt;= require(&amp;#34;vim.ui.clipboard.osc52&amp;#34;).copy(&amp;#34;*&amp;#34;),&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;paste = {&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;+&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#ae81ff&#34;&gt;= require(&amp;#34;vim.ui.clipboard.osc52&amp;#34;).paste(&amp;#34;+&amp;#34;),&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#ae81ff&#34;&gt;= require(&amp;#34;vim.ui.clipboard.osc52&amp;#34;).paste(&amp;#34;*&amp;#34;),&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-- &lt;span style=&#34;color:#ae81ff&#34;&gt;Use system clipboard for all yank/paste operations&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;vim.opt.clipboard = &amp;#34;unnamedplus&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;tmux&#34;&gt;Tmux&lt;/h2&gt;&#xA;&lt;p&gt;Add to ~/.tmux.conf&lt;/p&gt;</description>
    </item>
    <item>
      <title>Botkube</title>
      <link>https://uclab.dev/posts/botkube/</link>
      <pubDate>Sun, 23 Nov 2025 10:14:23 +0100</pubDate>
      <guid>https://uclab.dev/posts/botkube/</guid>
      <description>&lt;p&gt;Botkube Installation Guide&lt;/p&gt;&#xA;&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;&#xA;&lt;p&gt;This guide covers the installation of Botkube on a K3s Raspberry Pi 5 cluster with Slack integration, using HashiCorp Vault for secret management and FluxCD for GitOps deployment.&lt;/p&gt;&#xA;&lt;h2 id=&#34;architecture&#34;&gt;Architecture&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Cluster&lt;/strong&gt;: K3s on Raspberry Pi 5&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;GitOps&lt;/strong&gt;: FluxCD&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Secret Management&lt;/strong&gt;: HashiCorp Vault + External Secrets Operator&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Communication&lt;/strong&gt;: Slack (Socket Mode)&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Storage&lt;/strong&gt;: Persistent volume for plugin caching&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;K3s cluster running&lt;/li&gt;&#xA;&lt;li&gt;FluxCD installed and configured&lt;/li&gt;&#xA;&lt;li&gt;HashiCorp Vault deployed with KV secrets engine&lt;/li&gt;&#xA;&lt;li&gt;External Secrets Operator installed with ClusterSecretStore configured&lt;/li&gt;&#xA;&lt;li&gt;Slack workspace with admin access&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;directory-structure&#34;&gt;Directory Structure&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;infrastructure/&#xA;├── controllers/base/botkube/&#xA;│   ├── kustomization.yaml&#xA;│   ├── kustomizeconfig.yaml&#xA;│   ├── namespace.yaml&#xA;│   ├── pvc.yaml&#xA;│   ├── release.yaml&#xA;│   ├── repository.yaml&#xA;│   └── values.yaml&#xA;└── configs/base/botkube/&#xA;    ├── botkube-slack-secrets.yaml&#xA;    └── kustomization.yaml&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;step-1-create-slack-app&#34;&gt;Step 1: Create Slack App&lt;/h2&gt;&#xA;&lt;h3 id=&#34;11-create-the-app&#34;&gt;1.1 Create the App&lt;/h3&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Go to &lt;a href=&#34;https://api.slack.com/apps&#34;&gt;https://api.slack.com/apps&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;Click &lt;strong&gt;&amp;ldquo;Create New App&amp;rdquo;&lt;/strong&gt; → &lt;strong&gt;&amp;ldquo;From scratch&amp;rdquo;&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;Name it &amp;ldquo;Botkube&amp;rdquo; (or your preferred name)&lt;/li&gt;&#xA;&lt;li&gt;Select your workspace&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;12-configure-oauth-scopes&#34;&gt;1.2 Configure OAuth Scopes&lt;/h3&gt;&#xA;&lt;p&gt;Navigate to &lt;strong&gt;OAuth &amp;amp; Permissions&lt;/strong&gt; and add these &lt;strong&gt;Bot Token Scopes&lt;/strong&gt;:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Custom Root Ca Arch Linux</title>
      <link>https://uclab.dev/posts/custom-root-ca-arch-linux/</link>
      <pubDate>Sun, 16 Nov 2025 10:00:52 +0100</pubDate>
      <guid>https://uclab.dev/posts/custom-root-ca-arch-linux/</guid>
      <description>&lt;p&gt;This is my personal guide for installing the UCLab root CA certificate on Arch Linux, ensuring it&amp;rsquo;s trusted by the system and all major browsers including Microsoft Edge.&lt;/p&gt;&#xA;&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Root/sudo access&lt;/li&gt;&#xA;&lt;li&gt;The &lt;code&gt;uclab-root-ca.cer&lt;/code&gt; certificate file&lt;/li&gt;&#xA;&lt;li&gt;The certificate is already in PEM format (no conversion needed)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;step-1-install-certificate-system-wide&#34;&gt;Step 1: Install Certificate System-Wide&lt;/h2&gt;&#xA;&lt;p&gt;Copy the UCLab certificate to the system trust store:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo cp uclab-root-ca.cer /etc/ca-certificates/trust-source/anchors/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Update the system trust store:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo trust extract-compat&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Verify the certificate was added:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Archiving Files</title>
      <link>https://uclab.dev/posts/archive-files-linux/</link>
      <pubDate>Wed, 12 Nov 2025 10:38:48 +0100</pubDate>
      <guid>https://uclab.dev/posts/archive-files-linux/</guid>
      <description>&lt;p&gt;&lt;code&gt;tar&lt;/code&gt; is the Tape Archiver, a utility that was created long ago for backing up data to tape drives. Despite its age, it remains one of the most widely used archiving tools in Unix-like systems today.&lt;/p&gt;&#xA;&lt;h2 id=&#34;key-characteristics&#34;&gt;Key Characteristics&lt;/h2&gt;&#xA;&lt;p&gt;By default, &lt;code&gt;tar&lt;/code&gt; does &lt;strong&gt;not&lt;/strong&gt; compress data—it simply bundles multiple files and directories into a single archive file. Compression can be added as an optional step using various compression algorithms.&lt;/p&gt;&#xA;&lt;h2 id=&#34;basic-operations&#34;&gt;Basic Operations&lt;/h2&gt;&#xA;&lt;p&gt;The three fundamental operations you&amp;rsquo;ll perform with &lt;code&gt;tar&lt;/code&gt; are:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Cloudnativepg Plugin</title>
      <link>https://uclab.dev/posts/cloudnativepg-plugin/</link>
      <pubDate>Sun, 09 Nov 2025 21:19:44 +0100</pubDate>
      <guid>https://uclab.dev/posts/cloudnativepg-plugin/</guid>
      <description>&lt;p&gt;CloudNativePG provides a plugin for kubectl to manage a cluster in Kubernetes.&lt;/p&gt;&#xA;&lt;h2 id=&#34;install&#34;&gt;Install&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -sSfL &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  https://github.com/cloudnative-pg/cloudnative-pg/raw/main/hack/install-cnpg-plugin.sh | &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sudo sh -s -- -b /usr/local/bin&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;auto-completion&#34;&gt;Auto-completion&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat &amp;gt; kubectl_complete-cnpg &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;lt;&amp;lt;EOF&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;#!/usr/bin/env sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;# Call the __complete command passing it all arguments&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;kubectl cnpg __complete &amp;#34;\$@&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;EOF&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod +x kubectl_complete-cnpg&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Important: the following command may require superuser permission&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo mv kubectl_complete-cnpg /usr/local/bin&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;use&#34;&gt;Use&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kubectl cnpg COMMAND &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;ARGS...&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Onedrive Rclone</title>
      <link>https://uclab.dev/posts/onedrive-rclone/</link>
      <pubDate>Sun, 09 Nov 2025 19:30:09 +0100</pubDate>
      <guid>https://uclab.dev/posts/onedrive-rclone/</guid>
      <description>&lt;p&gt;This guide walks you through setting up Microsoft OneDrive on Linux using rclone.&lt;/p&gt;&#xA;&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;rclone installed on your Linux system&lt;/li&gt;&#xA;&lt;li&gt;A Microsoft OneDrive account&lt;/li&gt;&#xA;&lt;li&gt;A web browser for authentication&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo pacman -S rclone&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;configuration-steps&#34;&gt;Configuration Steps&lt;/h2&gt;&#xA;&lt;h3 id=&#34;1-start-rclone-configuration&#34;&gt;1. Start rclone Configuration&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rclone config&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;2-create-a-new-remote&#34;&gt;2. Create a New Remote&lt;/h3&gt;&#xA;&lt;p&gt;When prompted, select:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;n&lt;/code&gt; for New remote&lt;/li&gt;&#xA;&lt;li&gt;Enter a name for your remote (e.g., &lt;code&gt;OneDrive&lt;/code&gt;)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;3-select-storage-type&#34;&gt;3. Select Storage Type&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Choose option &lt;code&gt;38&lt;/code&gt; for Microsoft OneDrive&lt;/li&gt;&#xA;&lt;li&gt;Or type &lt;code&gt;onedrive&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;4-oauth-configuration&#34;&gt;4. OAuth Configuration&lt;/h3&gt;&#xA;&lt;p&gt;Leave the following blank (press Enter):&lt;/p&gt;</description>
    </item>
    <item>
      <title>Pass Store</title>
      <link>https://uclab.dev/posts/pass-store/</link>
      <pubDate>Sat, 08 Nov 2025 14:13:56 +0100</pubDate>
      <guid>https://uclab.dev/posts/pass-store/</guid>
      <description>&lt;p&gt;Complete Guide to pass: The Standard Unix Password Manager.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;pass&lt;/code&gt; is a simple, Unix-philosophy-based password manager that stores each password in a GPG-encrypted file. It uses standard Unix tools and can be version-controlled with Git, making it perfect for developers and anyone who appreciates simple, transparent tools.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-pass&#34;&gt;Why pass?&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Simple&lt;/strong&gt;: Just encrypted files in &lt;code&gt;~/.password-store/&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Transparent&lt;/strong&gt;: No proprietary formats, everything is GPG-encrypted text&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Version Controlled&lt;/strong&gt;: Built-in Git support for tracking changes&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Flexible&lt;/strong&gt;: Organize passwords however you want with folders&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Portable&lt;/strong&gt;: Sync across multiple machines using Git&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Scriptable&lt;/strong&gt;: Easy to integrate with other tools&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;Arch:&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Mount NFS Systemd</title>
      <link>https://uclab.dev/posts/mount-nfs-systemd/</link>
      <pubDate>Sat, 08 Nov 2025 14:00:24 +0100</pubDate>
      <guid>https://uclab.dev/posts/mount-nfs-systemd/</guid>
      <description>&lt;p&gt;This guide demonstrates how to mount an NFS share using systemd mount units instead of traditional &lt;code&gt;/etc/fstab&lt;/code&gt; entries. Systemd mount units provide better integration with the system&amp;rsquo;s dependency management and offer more control over mount behavior.&lt;/p&gt;&#xA;&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;NFS utilities installed on your system&lt;/li&gt;&#xA;&lt;li&gt;Access to an NFS server&lt;/li&gt;&#xA;&lt;li&gt;Root or sudo privileges&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;step-1-create-the-mount-point&#34;&gt;Step 1: Create the Mount Point&lt;/h2&gt;&#xA;&lt;p&gt;First, create the directory where the NFS share will be mounted:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo mkdir /mnt/vmnfs&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;step-2-generate-the-systemd-unit-name&#34;&gt;Step 2: Generate the Systemd Unit Name&lt;/h2&gt;&#xA;&lt;p&gt;Use &lt;code&gt;systemd-escape&lt;/code&gt; to generate the correct systemd unit name from your mount path:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Arch-Linux Fingerprint</title>
      <link>https://uclab.dev/posts/arch-linux-fingerprint/</link>
      <pubDate>Sat, 08 Nov 2025 13:34:27 +0100</pubDate>
      <guid>https://uclab.dev/posts/arch-linux-fingerprint/</guid>
      <description>&lt;h1 id=&#34;fingerprint-authentication-setup-for-arch-linux&#34;&gt;Fingerprint Authentication Setup for Arch Linux&lt;/h1&gt;&#xA;&lt;p&gt;Complete guide for setting up fingerprint authentication on Arch Linux with SDDM and Hyprland.&lt;/p&gt;&#xA;&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Arch Linux with SDDM display manager&lt;/li&gt;&#xA;&lt;li&gt;Hyprland window manager&lt;/li&gt;&#xA;&lt;li&gt;A working fingerprint reader&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;&#xA;&lt;h3 id=&#34;1-install-required-package&#34;&gt;1. Install Required Package&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo pacman -S fprintd&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;2-enroll-your-fingerprint&#34;&gt;2. Enroll Your Fingerprint&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Enroll your fingerprint (follow the prompts - scan multiple times)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fprintd-enroll antonis&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Verify it works&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fprintd-verify antonis&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Replace &lt;code&gt;antonis&lt;/code&gt; with your actual username.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Arch-Linux Webex</title>
      <link>https://uclab.dev/posts/arch-linux-webex/</link>
      <pubDate>Sat, 08 Nov 2025 12:16:41 +0100</pubDate>
      <guid>https://uclab.dev/posts/arch-linux-webex/</guid>
      <description>&lt;h2 id=&#34;how-to-get-cisco-webex-working-on-arch-linux-wayland--hyprland&#34;&gt;How to Get Cisco Webex Working on Arch Linux (Wayland / Hyprland).&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yay -S webex-bin&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;ndash;&#xA;Start the app via command line:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;env QT_QPA_PLATFORM&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;xcb /opt/Webex/bin/CiscoCollabHost&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Desktop Entry&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Version&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;45.10.0.33234&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Webex&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Comment&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Webex&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Exec&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;env QT_QPA_PLATFORM&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;xcb /opt/Webex/bin/CiscoCollabHost&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Icon&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/opt/Webex/bin/sparklogosmall.png&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Terminal&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;false&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Application&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Categories&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Utility;Application;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;MimeType&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;x-scheme-handler/webexteams;x-scheme-handler/ciscospark;x-scheme-handler/webex&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;It seems to fix the problem under Wayland, but doesn&amp;rsquo;t allow to share screen.&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Arch-Linux Secureboot</title>
      <link>https://uclab.dev/posts/arch-linux-secureboot/</link>
      <pubDate>Thu, 06 Nov 2025 14:12:28 +0100</pubDate>
      <guid>https://uclab.dev/posts/arch-linux-secureboot/</guid>
      <description>&lt;p&gt;Complete guide for setting up Arch Linux with Secure Boot using Ubuntu&amp;rsquo;s signed shim and systemd-boot on systems with locked BIOS (cannot disable Secure Boot or enroll custom keys).&lt;/p&gt;&#xA;&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Ventoy USB with Secure Boot support enabled&lt;/li&gt;&#xA;&lt;li&gt;Official Arch Linux ISO&lt;/li&gt;&#xA;&lt;li&gt;System with Secure Boot enabled (locked BIOS)&lt;/li&gt;&#xA;&lt;li&gt;Internet connection for AUR packages&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;&#xA;&lt;p&gt;This setup uses:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Ventoy&lt;/strong&gt; to boot the official Arch ISO with Secure Boot enabled&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Ubuntu&amp;rsquo;s signed shim&lt;/strong&gt; (trusted by Microsoft) as first-stage bootloader&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;systemd-boot&lt;/strong&gt; as second-stage bootloader (renamed to grubx64.efi)&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Personal MOK keys&lt;/strong&gt; to sign kernel and bootloader&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Pacman hooks&lt;/strong&gt; for automatic signing on updates&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;step-1-install-arch-linux&#34;&gt;Step 1: Install Arch Linux&lt;/h2&gt;&#xA;&lt;p&gt;Boot from Ventoy, select the Arch Linux ISO, and perform a standard Arch installation with systemd-boot as your bootloader.&lt;/p&gt;</description>
    </item>
    <item>
      <title>KEDA Autoscaling with Nginx</title>
      <link>https://uclab.dev/posts/nginx-auto-scaling-keda/</link>
      <pubDate>Tue, 04 Nov 2025 15:24:21 +0100</pubDate>
      <guid>https://uclab.dev/posts/nginx-auto-scaling-keda/</guid>
      <description>&lt;p&gt;A demonstration of Kubernetes Event-Driven Autoscaling (KEDA) with Nginx deployment, featuring automated load testing and real-time scaling monitoring.&lt;/p&gt;&#xA;&lt;h2 id=&#34;-overview&#34;&gt;📋 Overview&lt;/h2&gt;&#xA;&lt;p&gt;This project demonstrates horizontal pod autoscaling using KEDA based on CPU utilization. The setup automatically scales an Nginx deployment between 3-10 replicas when CPU usage exceeds 40%.&lt;/p&gt;&#xA;&lt;h2 id=&#34;-features&#34;&gt;🚀 Features&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;CPU-Based Autoscaling&lt;/strong&gt;: Scales based on 40% CPU utilization threshold&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Configurable Replica Range&lt;/strong&gt;: 3 minimum, 10 maximum pods&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Intelligent Cooldown&lt;/strong&gt;: 30-second cooldown period between scaling events&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Load Testing Script&lt;/strong&gt;: Python-based concurrent load generator&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Real-Time Monitoring&lt;/strong&gt;: Live pod count and request distribution tracking&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Even Load Distribution&lt;/strong&gt;: Kubernetes service ensures balanced traffic across pods&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;-configuration&#34;&gt;📁 Configuration&lt;/h2&gt;&#xA;&lt;h2 id=&#34;keda-scaledobject-nginx-scaleryaml&#34;&gt;KEDA ScaledObject (&lt;code&gt;nginx-scaler.yaml&lt;/code&gt;)&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;keda.sh/v1alpha1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ScaledObject&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nginx-scaler&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;scaleTargetRef&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nginx&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;minReplicaCount&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;maxReplicaCount&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;cooldownPeriod&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;pollingInterval&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;triggers&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;type&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;cpu&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;metricType&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Utilization&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;value&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;40&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;key-parameters&#34;&gt;Key Parameters&lt;/h3&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Parameter&lt;/th&gt;&#xA;          &lt;th&gt;Value&lt;/th&gt;&#xA;          &lt;th&gt;Description&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;minReplicaCount&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;3&lt;/td&gt;&#xA;          &lt;td&gt;Minimum number of pods&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;maxReplicaCount&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;10&lt;/td&gt;&#xA;          &lt;td&gt;Maximum number of pods&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;cooldownPeriod&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;30s&lt;/td&gt;&#xA;          &lt;td&gt;Wait time before scaling down&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;pollingInterval&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;10s&lt;/td&gt;&#xA;          &lt;td&gt;Frequency of metric checks&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;cpu.value&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;40%&lt;/td&gt;&#xA;          &lt;td&gt;CPU threshold for scaling&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;-baseline-setup&#34;&gt;📦 Baseline Setup&lt;/h2&gt;&#xA;&lt;h3 id=&#34;initial-deployment-state&#34;&gt;Initial Deployment State&lt;/h3&gt;&#xA;&lt;p&gt;Before load testing, the environment was configured with:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Webex Twilio</title>
      <link>https://uclab.dev/posts/webex-twilio/</link>
      <pubDate>Mon, 03 Nov 2025 21:32:36 +0100</pubDate>
      <guid>https://uclab.dev/posts/webex-twilio/</guid>
      <description>&lt;p&gt;🚀 Homelab Project: Certificate-based Local Gateway (CUBE) integration between Webex Calling and Twilio.&lt;/p&gt;&#xA;&lt;p&gt;I recently built a full voice integration lab combining:&lt;/p&gt;&#xA;&lt;p&gt;🔹 Cisco Catalyst 8000V as CUBE (Local Gateway)&lt;br&gt;&#xA;🔹 Webex Calling (sandbox trial)&lt;br&gt;&#xA;🔹 Twilio Elastic SIP Trunk (free account)&lt;/p&gt;&#xA;&lt;p&gt;The setup uses SIP/TLS and SRTP to ensure secure end-to-end communication between Webex Calling and Twilio.&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;details&gt;&#xA;&lt;summary&gt;&lt;code&gt;cube-config.md&lt;/code&gt;&lt;/summary&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-md&#34; data-lang=&#34;md&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;##  Baseline configuration&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hostname cube1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip name-server 1.1.1.1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip domain name example.com&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;interface GigabitEthernet1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ip address 10.10.10.5 255.255.255.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip route 0.0.0.0 0.0.0.0 10.10.10.1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;line vty 0 4&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exec-timeout 30 0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; logging synchronous&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; login local&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; transport input ssh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ntp server de.pool.ntp.org&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## License Configuration&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;license boot level network-premier addon dna-premier&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;platform hardware throughput level MB 1000&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## Protect STUN Credentials&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;key config-key password-encrypt PASSWORD&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;password encryption aes&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## Certificate Configuration&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!! Create an RSA key pair&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;crypto key generate rsa general-keys exportable label lgw-key modulus 4096&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!! Create a trustpoint for the certificate&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;crypto pki trustpoint LGW_CERT&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; enrollment terminal pem&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; fqdn none&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; subject-name cn=cube1.example.com&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; subject-alt-name cube1.example.com&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; revocation-check none&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rsakeypair lgw-key&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; hash sha256 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!! Generate CSR&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;crypto pki enroll LGW_CERT&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!! Paste Intermediate X.509 base64 certificate here&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;crypto pki authenticate LGW_CERT&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!! Paste CUBE host certificate here&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;crypto pki import LGW_CERT certificate&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!! Enable TLS 1.2&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sip-ua&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; crypto signaling default trustpoint LGW_CERT&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; transport tcp tls v1.2&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!! Install Cisco root CA bundle&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip http client source-interface GigabitEthernet1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;crypto pki trustpool import clean url http://www.cisco.com/security/pki/trs/ios_core.p7b&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!! Install Digicert global root CA (for Twilio SIP trunk)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;crypto pki trustpoint twilio&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; enrollment terminal&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; revocation-check none&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;crypto pki authenticate twilio&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;paste Digicert global root CA certificate here&amp;gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## Global SIP Configuration&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice service voip&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ip address trusted list&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 23.89.0.0 255.255.0.0  !Webex Calling IPs&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 62.109.192.0 255.255.192.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 85.119.56.0 255.255.254.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 128.177.14.0 255.255.255.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 128.177.36.0 255.255.255.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 135.84.168.0 255.255.248.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 139.177.64.0 255.255.248.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 139.177.72.0 255.255.254.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 144.196.0.0 255.255.0.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 150.253.128.0 255.255.128.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 163.129.0.0 255.255.128.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 170.72.0.0 255.255.0.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 170.133.128.0 255.255.192.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 185.115.196.0 255.255.252.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 199.19.196.0 255.255.254.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 199.19.199.0 255.255.255.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 199.59.64.0 255.255.248.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 54.171.127.192 255.255.255.192 !Twilio Service Provider IPs&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 54.171.127.192 255.255.255.192&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 54.244.51.0 255.255.255.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 54.172.60.0 255.255.254.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 54.172.60.0 255.255.255.252&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 54.244.51.0 255.255.255.252&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 54.171.127.192 255.255.255.252&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 35.156.191.128 255.255.255.252&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 54.65.63.192 255.255.255.252&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 54.169.127.128 255.255.255.252&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 54.252.254.64 255.255.255.252&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ipv4 177.71.206.192 255.255.255.252&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  exit&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exit&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## SIP Global Commands&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice service voip&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; address-hiding&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; mode border-element&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; allow-connections sip to sip&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; no supplementary-service sip refer&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; trace&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; media statistics&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; stun&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  stun flowdata agent-id 1 boot-count 4&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  stun flowdata shared-secret 0 Password123$&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  exit&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; sip&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  asymmetric payload full&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  early-offer forced&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sip-profiles inbound&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  exit&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## SIP Profiles&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;### Webex Calling (Outbound)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!! SIP profiles for outbound messages to Webex Calling; vCube behind NAT, internal ipv4 10.10.10.5 , NAT public ipv4 192.65.79.20&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class sip-profiles 100&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 10 request ANY sip-header Contact modify &amp;#34;@.*:&amp;#34; &amp;#34;@cube1.example.com:&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 20 response ANY sip-header Contact modify &amp;#34;@.*:&amp;#34; &amp;#34;@cube1.example.com:&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 30 response ANY sdp-header Audio-Attribute modify &amp;#34;(a=candidate:1 1.*) 10.10.10.5&amp;#34; &amp;#34;\1 192.65.79.20&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 31 response ANY sdp-header Audio-Attribute modify &amp;#34;(a=candidate:1 2.*) 10.10.10.5&amp;#34; &amp;#34;\1 192.65.79.20&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 40 response ANY sdp-header Audio-Connection-Info modify &amp;#34;IN IP4 10.10.10.5&amp;#34; &amp;#34;IN IP4 192.65.79.20&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 41 request ANY sdp-header Audio-Connection-Info modify &amp;#34;IN IP4 10.10.10.5&amp;#34; &amp;#34;IN IP4 192.65.79.20&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 50 request ANY sdp-header Connection-Info modify &amp;#34;IN IP4 10.10.10.5&amp;#34; &amp;#34;IN IP4 192.65.79.20&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 51 response ANY sdp-header Connection-Info modify &amp;#34;IN IP4 10.10.10.5&amp;#34; &amp;#34;IN IP4 192.65.79.20&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 60 response ANY sdp-header Session-Owner modify &amp;#34;IN IP4 10.10.10.5&amp;#34; &amp;#34;IN IP4 192.65.79.20&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 61 request ANY sdp-header Session-Owner modify &amp;#34;IN IP4 10.10.10.5&amp;#34; &amp;#34;IN IP4 192.65.79.20&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 70 request ANY sdp-header Audio-Attribute modify &amp;#34;(a=rtcp:.*) 10.10.10.5&amp;#34; &amp;#34;\1 192.65.79.20&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 71 response ANY sdp-header Audio-Attribute modify &amp;#34;(a=rtcp:.*) 10.10.10.5&amp;#34; &amp;#34;\1 192.65.79.20&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 80 request ANY sdp-header Audio-Attribute modify &amp;#34;(a=candidate:1 1.*) 10.10.10.5&amp;#34; &amp;#34;\1 192.65.79.20&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 81 request ANY sdp-header Audio-Attribute modify &amp;#34;(a=candidate:1 2.*) 10.10.10.5&amp;#34; &amp;#34;\1 192.65.79.20&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;### Webex Calling (Inbound)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class sip-profiles 110&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 10 response ANY sdp-header Video-Connection-Info modify &amp;#34;192.65.79.20&amp;#34; &amp;#34;10.10.10.5&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 20 response ANY sip-header Contact modify &amp;#34;@.*:&amp;#34; &amp;#34;@cube1.example.com:&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 30 response ANY sdp-header Connection-Info modify &amp;#34;192.65.79.20&amp;#34; &amp;#34;10.10.10.5&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 40 response ANY sdp-header Audio-Connection-Info modify &amp;#34;192.65.79.20&amp;#34; &amp;#34;10.10.10.5&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 50 response ANY sdp-header Session-Owner modify &amp;#34;192.65.79.20&amp;#34; &amp;#34;10.10.10.5&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 60 response ANY sdp-header Audio-Attribute modify &amp;#34;(a=candidate:1 1.*) 192.65.79.20&amp;#34; &amp;#34;\1 10.10.10.5&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 70 response ANY sdp-header Audio-Attribute modify &amp;#34;(a=candidate:1 2.*) 192.65.79.20&amp;#34; &amp;#34;\1 10.10.10.5&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 80 response ANY sdp-header Audio-Attribute modify &amp;#34;(a=rtcp:.*) 192.65.79.20&amp;#34; &amp;#34;\1 10.10.10.5&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;### SIP Options Keepalive&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class sip-profiles 115&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 10 request OPTIONS sip-header Contact modify &amp;#34;&amp;lt;sip:.*:&amp;#34; &amp;#34;&amp;lt;sip:cube1.example.com:&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 30 request ANY sip-header Via modify &amp;#34;(SIP.*) 10.10.10.5&amp;#34; &amp;#34;\1 192.65.79.20&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 40 response ANY sdp-header Connection-Info modify &amp;#34;10.10.10.5&amp;#34; &amp;#34;192.65.79.20&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rule 50 response ANY sdp-header Audio-Connection-Info modify &amp;#34;10.10.10.5&amp;#34; &amp;#34;192.65.79.20&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;### Twilio&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class sip-profiles 200&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; request REINVITE sip-header From modify &amp;#34;(&amp;lt;.*:.*)(@.*&amp;gt;)&amp;#34; &amp;#34;\1@example.pstn.twilio.com&amp;gt;&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; request CANCEL sip-header From modify &amp;#34;(&amp;lt;.*:.*)(@.*&amp;gt;)&amp;#34; &amp;#34;\1@example.pstn.twilio.com&amp;gt;&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; request INVITE sip-header To modify &amp;#34;(&amp;lt;.*:.*)(@.*&amp;gt;)&amp;#34; &amp;#34;\1@example.pstn.twilio.com&amp;gt;&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; request REINVITE sip-header To modify &amp;#34;(&amp;lt;.*:.*)(@.*&amp;gt;)&amp;#34; &amp;#34;\1@example.pstn.twilio.com&amp;gt;&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; request INVITE sip-header From modify &amp;#34;(&amp;lt;.*:.*)(@.*&amp;gt;)&amp;#34; &amp;#34;\1@example.pstn.twilio.com;user=phone&amp;gt;&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; request INVITE sip-header P-Asserted-Identity modify &amp;#34;(&amp;lt;.*:.*)(@.*&amp;gt;)&amp;#34; &amp;#34;\1@example.pstn.twilio.com;user=phone&amp;gt;&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; request ANY sip-header Contact modify &amp;#34;@.*:&amp;#34; &amp;#34;@192.65.79.20:&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; response ANY sip-header Contact modify &amp;#34;@.*:&amp;#34; &amp;#34;@192.65.79.20:&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## SIP config&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class uri 100 sip&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; pattern cube1.example.com:5062&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class uri 200 sip&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; pattern cube1.example.com:5061&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class codec 100&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; codec preference 1 g711ulaw&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; codec preference 2 g711alaw&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class codec 200&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; codec preference 1 g711ulaw&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; codec preference 2 g711alaw&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class stun-usage 100&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; stun usage firewall-traversal flowdata&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; stun usage ice lite&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class dpg 100&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; description TWILIO PSTN to Webex Calling&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; dial-peer 100&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class dpg 200&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; description Webex Calling to TWILIO PSTN&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; dial-peer 200&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class sip-options-keepalive 100&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; description Keepalive for Webex Calling&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; up-interval 5&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; transport tcp tls&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; sip-profiles 115&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class sip-options-keepalive 200&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; description Keepalive for Twilio Calling&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; up-interval 5&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; transport tcp tls&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; sip-profiles 115&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class srtp-crypto 100&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; crypto 1 AES_CM_128_HMAC_SHA1_80&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class srtp-crypto 200&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; crypto 1 AES_CM_128_HMAC_SHA1_80&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## Local Gateway Tenant (Webex Calling)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class tenant 100&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  listen-port secure 5062&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  no remote-party-id&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sip-server dns:eun01.sipconnect.bcld.webex.com&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  srtp-crypto 100&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  localhost dns:cube1.example.com&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  session transport tcp tls&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  no session refresh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  error-passthru&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  rel1xx disable&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  asserted-id pai&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  bind control source-interface GigabitEthernet1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  bind media source-interface GigabitEthernet1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  no pass-thru content custom-sdp&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sip-profiles 100&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sip-profiles 110 inbound&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  privacy-policy passthru&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## Twilio PSTN Tenant&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;voice class tenant 200&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sip-server dns:example.pstn.twilio.com&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  srtp-crypto 200&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  localhost dns:cube1.example.com&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  session transport tcp tls&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  asserted-id pai&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  bind control source-interface GigabitEthernet1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  bind media source-interface GigabitEthernet1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sip-profiles 200&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  early-offer forced&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;## Dial-Peers&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dial-peer voice 100 voip&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; description Inbound/Outbound Webex Calling&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; destination-pattern BAD.BAD&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; session protocol sipv2&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; session target sip-server&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; session transport tcp tls&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; destination dpg 200&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; incoming uri request 100&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; voice-class codec 100&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; voice-class stun-usage 100&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; voice-class sip tenant 100&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; voice-class sip options-keepalive profile 100&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; dtmf-relay rtp-nte&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; srtp&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; no vad&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dial-peer voice 200 voip  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; description Inbound/Outbound TWILIO PSTN&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; destination-pattern BAD.BAD&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; session protocol sipv2&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; session target sip-server&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; session transport tcp tls&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; destination dpg 100&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; incoming uri request 200&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; voice-class codec 200&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; voice-class sip tenant 200&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; voice-class sip options-keepalive profile 200&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; dtmf-relay rtp-nte&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; srtp&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; no vad&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;&#xA;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Arch-Linux Install</title>
      <link>https://uclab.dev/posts/archlinux-install/</link>
      <pubDate>Mon, 03 Nov 2025 20:07:53 +0100</pubDate>
      <guid>https://uclab.dev/posts/archlinux-install/</guid>
      <description>&lt;h2 id=&#34;environment-details&#34;&gt;Environment Details&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Boot Image: archlinux-2025.10.01-x86_64.iso&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Virtualization Platform:  VMware ESXi&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Virtual Machine Configuration:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CPU: &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; cores&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RAM: &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; GB&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Storage: &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt; GB HDD&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;boot-the-live-environment&#34;&gt;Boot the live environment&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Arch Linux installation images &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; not support Secure Boot. You will need to disable Secure Boot to boot the installation medium.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Console fonts are located in /usr/share/kbd/consolefonts/ and can likewise be set with setfont&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;8&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; omitting the path and file extension. &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;For example, to use one of the largest fonts suitable &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; HiDPI screens, run:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;root@archiso ~ &lt;span style=&#34;color:#75715e&#34;&gt;# setfont ter-132b&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Verify the boot mode&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Arch-Linux Chroot</title>
      <link>https://uclab.dev/posts/archlinux-chroot/</link>
      <pubDate>Sun, 02 Nov 2025 13:25:46 +0100</pubDate>
      <guid>https://uclab.dev/posts/archlinux-chroot/</guid>
      <description>&lt;p&gt;There&amp;rsquo;s a significant difference between &lt;code&gt;arch-chroot&lt;/code&gt; and &lt;code&gt;chroot&lt;/code&gt; that&amp;rsquo;s important to understand when working with Arch Linux installations.&lt;/p&gt;&#xA;&lt;h2 id=&#34;arch-chroot-mnt&#34;&gt;&lt;code&gt;arch-chroot /mnt&lt;/code&gt;&lt;/h2&gt;&#xA;&lt;p&gt;This is a wrapper script provided by the Arch installation ISO that does much more than just chroot. It&amp;rsquo;s the preferred method during Arch Linux installation.&lt;/p&gt;&#xA;&lt;h3 id=&#34;what-it-does-automatically&#34;&gt;What it does automatically:&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Mounts important filesystems (&lt;code&gt;/proc&lt;/code&gt;, &lt;code&gt;/sys&lt;/code&gt;, &lt;code&gt;/dev&lt;/code&gt;, &lt;code&gt;/dev/pts&lt;/code&gt;, &lt;code&gt;/run&lt;/code&gt;)&lt;/li&gt;&#xA;&lt;li&gt;Copies DNS configuration (&lt;code&gt;/etc/resolv.conf&lt;/code&gt;) so networking works&lt;/li&gt;&#xA;&lt;li&gt;Sets up the chroot environment properly&lt;/li&gt;&#xA;&lt;li&gt;Uses bash by default (ignoring the shell specified in &lt;code&gt;/etc/passwd&lt;/code&gt;)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;usage&#34;&gt;Usage:&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;arch-chroot /mnt&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Use this during Arch installation&lt;/strong&gt; - it&amp;rsquo;s designed specifically for this purpose and handles all the tedious setup work for you.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Vault Install</title>
      <link>https://uclab.dev/posts/vault-install/</link>
      <pubDate>Sun, 02 Nov 2025 12:21:27 +0100</pubDate>
      <guid>https://uclab.dev/posts/vault-install/</guid>
      <description>&lt;p&gt;This guide documents the process of installing and configuring vault to safely manage secrets/sensitive data.&lt;/p&gt;&#xA;&lt;h2 id=&#34;system&#34;&gt;System&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# System version&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ubuntu@vault:~$ uname -a&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Linux vault 6.8.0-86-generic&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#87-Ubuntu SMP PREEMPT_DYNAMIC Mon Sep 22 18:03:36 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ubuntu@vault:~$&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ubuntu@vault:~$ cat /etc/os-release&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;PRETTY_NAME=&amp;#34;Ubuntu 24.04.3 LTS&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;NAME=&amp;#34;Ubuntu&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;VERSION_ID=&amp;#34;24.04&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;VERSION=&amp;#34;24.04.3 LTS (Noble Numbat)&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;VERSION_CODENAME=noble&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ID=ubuntu&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ID_LIKE=debian&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;HOME_URL=&amp;#34;https://www.ubuntu.com/&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;SUPPORT_URL=&amp;#34;https://help.ubuntu.com/&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;BUG_REPORT_URL=&amp;#34;https://bugs.launchpad.net/ubuntu/&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;PRIVACY_POLICY_URL=&amp;#34;https://www.ubuntu.com/legal/terms-and-policies/privacy-policy&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;UBUNTU_CODENAME=noble&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;LOGO=ubuntu-logo&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ubuntu@vault:~$&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;install&#34;&gt;Install&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Install Vault&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;sudo apt update &amp;amp;&amp;amp; sudo apt upgrade -y&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;echo &amp;#34;deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(grep -oP &amp;#39;(?&amp;lt;=UBUNTU_CODENAME=).*&amp;#39; /etc/os-release || lsb_release -cs) main&amp;#34; | sudo tee /etc/apt/sources.list.d/hashicorp.list&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;sudo apt update &amp;amp;&amp;amp; sudo apt install vault&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# verify version&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ubuntu@vault:~$ vault --version&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;Vault v1.21.0 (818ca8b3575ea937ca48b640baf35e1b2ede1833), built 2025-10-21T19:33:18Z&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ubuntu@vault:~$&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;configuration&#34;&gt;Configuration&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# vault configuration file&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;cat /etc/vault.d/vault.hcl&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Copyright IBM Corp. 2016, 2025&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# SPDX-License-Identifier: BUSL-1.1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Full configuration options can be found at https://developer.hashicorp.com/vault/docs/configuration&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ui = true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#mlock = true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#disable_mlock = true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;storage &amp;#34;file&amp;#34; {&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;path = &amp;#34;/opt/vault/data&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#storage &amp;#34;consul&amp;#34; {&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  address = &amp;#34;127.0.0.1:8500&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  path    = &amp;#34;vault&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# HTTP listener&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#listener &amp;#34;tcp&amp;#34; {&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  address = &amp;#34;127.0.0.1:8200&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  tls_disable = 1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# HTTPS listener&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;listener &amp;#34;tcp&amp;#34; {&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;address       = &amp;#34;0.0.0.0:8200&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;tls_cert_file = &amp;#34;/opt/vault/tls/tls.crt&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;tls_key_file  = &amp;#34;/opt/vault/tls/tls.key&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# API address for cluster communication&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;api_addr = &amp;#34;https://vault.uclab8.net:8200&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Enterprise license_path&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# This will be required for enterprise as of v1.8&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#license_path = &amp;#34;/etc/vault.d/vault.hclic&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Example AWS KMS auto unseal&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#seal &amp;#34;awskms&amp;#34; {&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  region = &amp;#34;us-east-1&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  kms_key_id = &amp;#34;REPLACE-ME&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Example HSM auto unseal&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#seal &amp;#34;pkcs11&amp;#34; {&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  lib            = &amp;#34;/usr/vault/lib/libCryptoki2_64.so&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  slot           = &amp;#34;0&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  pin            = &amp;#34;AAAA-BBBB-CCCC-DDDD&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  key_label      = &amp;#34;vault-hsm-key&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  hmac_key_label = &amp;#34;vault-hsm-hmac-key&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# enable vault service&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;systemctl enable --now vault.service&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;status&#34;&gt;Status&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# verify service status&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;ubuntu@vault:~$ systemctl status vault.service&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;● vault.service - &amp;#34;HashiCorp Vault - A tool for managing secrets&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#f92672&#34;&gt;Loaded: loaded (/usr/lib/systemd/system/vault.service; enabled; preset&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;enabled)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#f92672&#34;&gt;Active&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;active (running) since Sat 2025-10-25 11:01:03 UTC; 1 week 1 day ago&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#f92672&#34;&gt;Docs&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;https://developer.hashicorp.com/vault/docs&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#f92672&#34;&gt;Main PID&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2142&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;(vault)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;Tasks: 9 (limit&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;7065&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#f92672&#34;&gt;Memory: 98.5M (peak&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;99.&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2M)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;CPU&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1h 56min 41.603s&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#f92672&#34;&gt;CGroup&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/system.slice/vault.service&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#ae81ff&#34;&gt;└─2142 /usr/bin/vault server -config=/etc/vault.d/vault.hcl&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;certificates&#34;&gt;Certificates&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# generate certificates&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;certbot certonly --preferred-challenges=dns --manual -d vault.uclab8.net&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# set new certificates&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;cp /etc/letsencrypt/live/vault.uclab8.net/fullchain.pem /opt/vault/tls/tls.crt&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;cp /etc/letsencrypt/live/vault.uclab8.net/privkey.pem /opt/vault/tls/tls.key&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# set permissions&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;chown vault:vault /opt/vault/tls/tls.crt /opt/vault/tls/tls.key&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;chmod 600 /opt/vault/tls/tls.crt /opt/vault/tls/tls.key&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# export vault url&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;echo &amp;#39;export VAULT_ADDR=&amp;#34;https://vault.uclab8.net:8200&amp;#34;&amp;#39; &amp;gt;&amp;gt; ~/.bashrc&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# restart service&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;systemctl restart vault&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;initialize-vault&#34;&gt;Initialize vault&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# initialize and setup vault&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;vault operator init&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;vault operator unseal&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;vault login&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;vault secrets enable -path=apps kv-v2&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;vault auth enable userpass&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;cat &amp;lt;&amp;lt;EOF | vault policy write apps-manager -&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Allow full access to apps/ path (KV v2)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;path &amp;#34;apps/data/*&amp;#34; {&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;capabilities = [&amp;#34;create&amp;#34;, &amp;#34;read&amp;#34;, &amp;#34;update&amp;#34;, &amp;#34;delete&amp;#34;, &amp;#34;list&amp;#34;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;path &amp;#34;apps/metadata/*&amp;#34; {&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;capabilities = [&amp;#34;list&amp;#34;, &amp;#34;read&amp;#34;, &amp;#34;delete&amp;#34;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;path &amp;#34;apps/*&amp;#34; {&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;capabilities = [&amp;#34;list&amp;#34;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;EOF&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;vault write auth/userpass/users/affragak   password=supersecretpassword   policies=apps-manager&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;vault write auth/userpass/users/affragak   password=supersecretpassword   policies=apps-manager&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;login&#34;&gt;Login&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# vault login&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;vault login -method=userpass \&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;username=affragak  \&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;password=supersecretpassword&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Vault</title>
      <link>https://uclab.dev/posts/vault/</link>
      <pubDate>Sun, 02 Nov 2025 12:10:33 +0100</pubDate>
      <guid>https://uclab.dev/posts/vault/</guid>
      <description>&lt;p&gt;Steps to use vault; login , add and retrieve a secret.&lt;/p&gt;&#xA;&lt;h2 id=&#34;vault-environment&#34;&gt;Vault Environment&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;export VAULT_ADDR=&amp;#39;https://vault.uclab8.net:8200&amp;#39;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;authentication&#34;&gt;Authentication&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;vault login -method=userpass \&#xA;    username=&amp;lt;username&amp;gt; \&#xA;    password=&amp;lt;password&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;status&#34;&gt;Status&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;❯ vault status&#xA;Key             Value&#xA;---             -----&#xA;Seal Type       shamir&#xA;Initialized     true&#xA;Sealed          false&#xA;Total Shares    5&#xA;Threshold       3&#xA;Version         1.18.4&#xA;Build Date      2025-01-29T13:57:54Z&#xA;Storage Type    file&#xA;Cluster Name    vault-cluster-5c71a2e8&#xA;Cluster ID      1cdb3cce-a97a-c3ef-dc33-9385e1eae1b3&#xA;HA Enabled      false&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;store-a-secret&#34;&gt;Store a secret&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# Put the kubeconfig from a file&#xA;vault kv put apps/k3s kubeconfig=@/path/to/your/kubeconfig&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;retrieve-a-secret&#34;&gt;Retrieve a secret&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# Retrieve the kubeconfig from a file&#xA;vault kv get -field=kubeconfig apps/k3s &amp;gt; kubeconfig&#xA;&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>Arch-Linux Font installation</title>
      <link>https://uclab.dev/posts/arch-linux-font-install/</link>
      <pubDate>Sun, 02 Nov 2025 10:34:22 +0100</pubDate>
      <guid>https://uclab.dev/posts/arch-linux-font-install/</guid>
      <description>&lt;p&gt;This guide covers user-level installation of Departure Mono fonts on Arch Linux.&lt;/p&gt;&#xA;&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;wget&lt;/code&gt; and &lt;code&gt;unzip&lt;/code&gt; packages installed&lt;/li&gt;&#xA;&lt;li&gt;Internet connection&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;installation-steps&#34;&gt;Installation Steps&lt;/h2&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Download the Font&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://departuremono.com/assets/DepartureMono-1.422.zip&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;2&#34;&gt;&#xA;&lt;li&gt;Create Fonts Directory&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Create the local fonts directory if it doesn&amp;rsquo;t already exist:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p ~/.local/share/fonts&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;3&#34;&gt;&#xA;&lt;li&gt;Extract the Fonts&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Unzip the font files to your local fonts directory:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;unzip DepartureMono-1.422.zip -d ~/.local/share/fonts/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;4&#34;&gt;&#xA;&lt;li&gt;Update Font Cache&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Refresh the font cache so your system recognizes the new fonts:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Migrating /home to a new encrypted drive</title>
      <link>https://uclab.dev/posts/luks_arch_linux_migration/</link>
      <pubDate>Sun, 02 Nov 2025 09:11:25 +0100</pubDate>
      <guid>https://uclab.dev/posts/luks_arch_linux_migration/</guid>
      <description>&lt;p&gt;&lt;strong&gt;System:&lt;/strong&gt; Arch Linux with LUKS + LVM&lt;/p&gt;&#xA;&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;&#xA;&lt;p&gt;This guide documents the process of migrating &lt;code&gt;/home&lt;/code&gt; from an existing LUKS+LVM setup to a new encrypted drive while maintaining the same security architecture (LVM on LUKS).&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;System Configuration:&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Arch Linux&lt;/li&gt;&#xA;&lt;li&gt;LUKS encryption&lt;/li&gt;&#xA;&lt;li&gt;LVM for volume management&lt;/li&gt;&#xA;&lt;li&gt;Existing setup: &lt;code&gt;/dev/sda2&lt;/code&gt; → LUKS → LVM (root, swap, home)&lt;/li&gt;&#xA;&lt;li&gt;Goal: Move home to new &lt;code&gt;/dev/sdb1&lt;/code&gt; → LUKS → LVM&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Root access (SSH as root enabled)&lt;/li&gt;&#xA;&lt;li&gt;New disk added to VM/system&lt;/li&gt;&#xA;&lt;li&gt;Existing data backed up (recommended)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;step-1-prepare-the-new-disk&#34;&gt;Step 1: Prepare the New Disk&lt;/h2&gt;&#xA;&lt;h3 id=&#34;11-verify-new-disk&#34;&gt;1.1 Verify New Disk&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lsblk&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected output shows new disk (e.g., &lt;code&gt;/dev/sdb&lt;/code&gt;).&lt;/p&gt;</description>
    </item>
    <item>
      <title>External Dns</title>
      <link>https://uclab.dev/posts/external-dns/</link>
      <pubDate>Tue, 28 Oct 2025 10:41:42 +0100</pubDate>
      <guid>https://uclab.dev/posts/external-dns/</guid>
      <description>&lt;h2 id=&#34;gateway-api-support&#34;&gt;Gateway API Support&lt;/h2&gt;&#xA;&lt;p&gt;Gateways labeled with external-dns: enabled, creates DNS records for hostnames in HTTPRoutes.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;provider&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;pihole&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;policy&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;sync&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;env&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;EXTERNAL_DNS_PIHOLE_PASSWORD&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;valueFrom&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;secretKeyRef&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;pihole-password&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;key&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;EXTERNAL_DNS_PIHOLE_PASSWORD&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;extraArgs&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - --&lt;span style=&#34;color:#ae81ff&#34;&gt;pihole-server=http://pihole.pihole.svc.cluster.local&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - --&lt;span style=&#34;color:#ae81ff&#34;&gt;pihole-api-version=6&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - --&lt;span style=&#34;color:#ae81ff&#34;&gt;gateway-label-filter=external-dns==enabled&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;sources&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#ae81ff&#34;&gt;gateway-httproute&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;ingressClassFilters&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#ae81ff&#34;&gt;cilium&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;gateway-example&#34;&gt;Gateway Example&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;gateway.networking.k8s.io/v1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Gateway&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;blog&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;namespace&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;blog&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;annotations&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;cert-manager.io/cluster-issuer&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;letsencrypt-production&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# Specify the name of your issuer resource&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;labels&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;external-dns&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;enabled&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;gatewayClassName&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;cilium&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;listeners&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;hostname&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;blog.uclab8.net&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# Specify a valid domain to reach your application&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;blog-uclab8-net-http&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;protocol&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;HTTP&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;hostname&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;blog.uclab8.net&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# Specify a valid domain to reach your application&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;blog-uclab8-net-https&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;443&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;protocol&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;HTTPS&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;tls&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Terminate&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;certificateRefs&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Secret&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;blog-uclab8-tls&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# Specify the secret name to be used with your application&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;allowedRoutes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;namespaces&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;All&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Mikrotik Logs</title>
      <link>https://uclab.dev/posts/mikrotik-logs/</link>
      <pubDate>Sun, 29 Jun 2025 16:59:03 +0200</pubDate>
      <guid>https://uclab.dev/posts/mikrotik-logs/</guid>
      <description>&lt;p&gt;Complementary to MKTXP, this project also adds some extra capabilities such an centralized Mikrotik log processing based on a syslog-ng / promtail / Loki stack.&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://uclab.dev/posts/mikrotik-logs/images/mktxplogs.png&#34;&#xA;    alt=&#34;Alt text&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;h2 id=&#34;syslog-ng&#34;&gt;Syslog-ng&lt;/h2&gt;&#xA;&lt;p&gt;&#xA;&lt;details&gt;&#xA;&lt;summary&gt;&lt;code&gt;deployment.yaml&lt;/code&gt;&lt;/summary&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;apps/v1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Deployment&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;syslog-ng&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;replicas&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;selector&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;matchLabels&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;app&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;syslog-ng&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;template&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;labels&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;app&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;syslog-ng&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;containers&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;syslog-ng&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;balabit/syslog-ng:4.8.0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#f92672&#34;&gt;containerPort&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;601&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;protocol&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;TCP&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#f92672&#34;&gt;containerPort&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;514&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;protocol&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;UDP&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;volumeMounts&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;config-volume&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;mountPath&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/syslog-ng/syslog-ng.conf&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;subPath&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;syslog-ng.conf&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;syslog-ng-logs&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;mountPath&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/var/log&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# Syslog-NG will write logs here&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;config-volume&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;configMap&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;syslog-ng-config&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;syslog-ng-logs&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;persistentVolumeClaim&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;claimName&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;syslog-ng-logs-pvc&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;&#xA;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Mikrotik Monitoring</title>
      <link>https://uclab.dev/posts/mikrotik-monitoring/</link>
      <pubDate>Sun, 29 Jun 2025 16:38:17 +0200</pubDate>
      <guid>https://uclab.dev/posts/mikrotik-monitoring/</guid>
      <description>&lt;p&gt;Mikrotik Router Monitoring with Grafana/Prometheus.&lt;/p&gt;&#xA;&lt;h2 id=&#34;mktxp-exporter&#34;&gt;MKTXP Exporter&lt;/h2&gt;&#xA;&lt;p&gt;source: &lt;a href=&#34;https://github.com/akpw/mktxp&#34;&gt;https://github.com/akpw/mktxp&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;MKTXP is a Prometheus Exporter for Mikrotik RouterOS devices.&lt;br&gt;&#xA;It gathers and exports a rich set of metrics across multiple routers, all easily configurable via built-in CLI interface.&lt;/p&gt;&#xA;&lt;p&gt;Grafana Dashboard: &lt;a href=&#34;https://grafana.com/grafana/dashboards/13679-mikrotik-mktxp-exporter/&#34;&gt;https://grafana.com/grafana/dashboards/13679-mikrotik-mktxp-exporter/&lt;/a&gt;&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://uclab.dev/posts/mikrotik-monitoring/images/mktxp.png&#34;&#xA;    alt=&#34;Alt text&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;h2 id=&#34;deployment&#34;&gt;Deployment&lt;/h2&gt;&#xA;&lt;p&gt;&#xA;&lt;details&gt;&#xA;&lt;summary&gt;&lt;code&gt;deployment.yaml&lt;/code&gt;&lt;/summary&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;apps/v1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Deployment&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mktxp-exporter&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;selector&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;matchLabels&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;app&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mktxp-exporter&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;template&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;labels&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;app&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mktxp-exporter&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;containers&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mktxp-exporter&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ghcr.io/akpw/mktxp:1.2.10&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;args&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - --&lt;span style=&#34;color:#ae81ff&#34;&gt;cfg-dir&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;/mktxp_config&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#ae81ff&#34;&gt;export&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;resources&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;limits&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;memory&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;256Mi&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;cpu&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;200m&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;volumeMounts&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mktxp-credentials&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#f92672&#34;&gt;mountPath&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/mktxp_config&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#f92672&#34;&gt;containerPort&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;49090&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mktxp-credentials&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;secret&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;secretName&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mktxp-credentials&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;&#xA;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Devcontainer Build</title>
      <link>https://uclab.dev/posts/devcontainer-build/</link>
      <pubDate>Sat, 14 Jun 2025 19:44:51 +0200</pubDate>
      <guid>https://uclab.dev/posts/devcontainer-build/</guid>
      <description>&lt;p&gt;A streamlined approach to building development containers with Mise for tool version management and chezmoi for dotfiles synchronization, featuring automated setup and DevPod integration for portable development environments.&lt;/p&gt;&#xA;&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Docker installed and running&lt;/li&gt;&#xA;&lt;li&gt;DevPod CLI installed&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# Configure DevPod for terminal-based workflow (Neovim)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  devpod ide use none&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  devpod provider add docker&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;directory-structure&#34;&gt;Directory Structure&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.devcontainer/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── devcontainer.json&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── Dockerfile&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└── scripts&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    └── setup&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;dockerfile&#34;&gt;Dockerfile&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Dockerfile&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;COPY --from=jdxcode/mise /usr/local/bin/mise /usr/local/bin/&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# make sure mise is activated in both zsh and bash. Might be overridden by a user&amp;#39;s dotfiles.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;RUN echo &amp;#39;eval &amp;#34;$(mise activate bash)&amp;#34;&amp;#39; &amp;gt;&amp;gt; /home/vscode/.bashrc &amp;amp;&amp;amp; \&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;echo &amp;#39;eval &amp;#34;$(mise activate zsh)&amp;#34;&amp;#39; &amp;gt;&amp;gt; /home/vscode/.zshrc&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;devcontainer&#34;&gt;Devcontainer&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# devcontainer.json&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;build&amp;#34;: &lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;context&amp;#34;: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;..&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;dockerfile&amp;#34;: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Dockerfile&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;remoteEnv&amp;#34;: &lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;MISE_GITHUB_TOKEN&amp;#34;: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;${localEnv:MISE_GITHUB_TOKEN}&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;postCreateCommand&amp;#34;: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.devcontainer/scripts/setup&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;forwardPorts&amp;#34;: &lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;8000&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;scriptsetup&#34;&gt;Script/setup&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/bash&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/usr/local/bin/mise trust /workspaces/&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$DEVPOD_WORKSPACE_ID&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;/mise.toml &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; /usr/local/bin/mise install&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;build&#34;&gt;Build&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;devpod up . --dotfiles git@github.com:affragak/dotfiles-devpod.git&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;connect&#34;&gt;Connect&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;devpod ssh .&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Flux Upgrade</title>
      <link>https://uclab.dev/posts/flux-upgrade/</link>
      <pubDate>Mon, 07 Apr 2025 14:24:59 +0200</pubDate>
      <guid>https://uclab.dev/posts/flux-upgrade/</guid>
      <description>&lt;p&gt;Create a new workflow in GitHub repo under Actions.&lt;br&gt;&#xA;Generate a classic PAT and create a secret.&lt;br&gt;&#xA;Then use the below code.&lt;br&gt;&#xA;That will create a pull-request in GitHub.&lt;/p&gt;&#xA;&lt;h2 id=&#34;flux-upgrade-with-with-github-actions&#34;&gt;Flux Upgrade with with GitHub Actions.&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# flux-upgrade.yaml&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;update-flux&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;on&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;workflow_dispatch&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;schedule&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;cron&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0 0 1 * *&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;permissions&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;contents&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;write&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;pull-requests&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;write&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;jobs&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;components&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;runs-on&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ubuntu-latest&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;steps&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Check out code&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;uses&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;actions/checkout@v4&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Setup Flux CLI&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;uses&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;fluxcd/flux2/action@main&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Check for updates&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;update&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;run&lt;/span&gt;: |&lt;span style=&#34;color:#e6db74&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          flux install \&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            --export &amp;gt; ./clusters/athena/flux-system/gotk-components.yaml&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          VERSION=&amp;#34;$(flux -v)&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          echo &amp;#34;flux_version=$VERSION&amp;#34; &amp;gt;&amp;gt; $GITHUB_OUTPUT&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Create Pull Request&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;uses&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;peter-evans/create-pull-request@v7&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;with&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;token&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${{ secrets.FLUX_UPDATE_PAT }}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;branch&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;update-flux&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;commit-message&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Update to ${{ steps.update.outputs.flux_version }}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;title&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Update to ${{ steps.update.outputs.flux_version }}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;body&lt;/span&gt;: |&lt;span style=&#34;color:#e6db74&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;              ${{ steps.update.outputs.flux_version }}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>K3s Home Lab</title>
      <link>https://uclab.dev/posts/k8s-home-lab/</link>
      <pubDate>Sun, 12 Jan 2025 16:41:31 +0100</pubDate>
      <guid>https://uclab.dev/posts/k8s-home-lab/</guid>
      <description>&lt;p&gt;my kubernetes homelab&lt;/p&gt;&#xA;&lt;p&gt;this is a post for my home lab kubernetes cluster.&lt;br&gt;&#xA;main purpose of lab is to learn and have fun.&lt;/p&gt;&#xA;&lt;h2 id=&#34;cluster-provisioning&#34;&gt;Cluster provisioning&lt;/h2&gt;&#xA;&lt;p&gt;K3s: Lightweight Kubernetes distribution running on mixed ARM/x86 architecture.&lt;/p&gt;&#xA;&lt;h2 id=&#34;hardware&#34;&gt;Hardware&lt;/h2&gt;&#xA;&lt;p&gt;i use one Raspberry Pi 5 control plane and two Intel NUC8i7 worker nodes.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;❯ k get nodes&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;NAME     STATUS   ROLES                  AGE     VERSION&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;athena   Ready    control-plane,master   8d      v1.33.4+k3s1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;nuc242   Ready    &amp;lt;none&amp;gt;                 7d23h   v1.33.4+k3s1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;nuc243   Ready    &amp;lt;none&amp;gt;                 7d18h   v1.33.4+k3s1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;features&#34;&gt;Features&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Advanced networking&lt;/strong&gt; - Cilium CNI with eBPF for high-performance networking&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;GitOps workflow&lt;/strong&gt; - All configurations managed through Git&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Encrypted secrets&lt;/strong&gt; - External Secrets Operator with HashiCorp Vault for secure secret management&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Database management&lt;/strong&gt; - PostgreSQL clusters via CloudNative-PG operator&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Complete observability&lt;/strong&gt; - Grafana dashboards with Prometheus metrics&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Automated TLS&lt;/strong&gt; - Let&amp;rsquo;s Encrypt certificates via cert-manager&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Zero-config internet access&lt;/strong&gt; - Cloudflare Tunnels without firewall changes&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Automatic dependency updates&lt;/strong&gt; - Renovate bot for keeping applications current&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Development ready&lt;/strong&gt; - Preconfigured dev container for immediate productivity&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;No pods are allowed to be scheduled on the control plane.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Hugo on K3s</title>
      <link>https://uclab.dev/posts/hugo-on-k8s/</link>
      <pubDate>Sun, 12 Jan 2025 11:10:25 +0100</pubDate>
      <guid>https://uclab.dev/posts/hugo-on-k8s/</guid>
      <description>&lt;p&gt;i decided to make a website. a static one. this one. with Hugo.&lt;br&gt;&#xA;the main reason i have for needing a website is as a learning project, so i have some stuff to host in a Kubernetes cluster i&amp;rsquo;m running. the k3s cluster is also a learning project.&lt;br&gt;&#xA;k3s running in Raspberry Pi 5 control plane and two Intel NUC8i7 worker nodes.&lt;br&gt;&#xA;Cilium as cni. Flux as continuous delivery.&lt;br&gt;&#xA;gitlab runs as selfhosted in a separate vm.&lt;br&gt;&#xA;my repo structure according to &lt;a href=&#34;https://fluxcd.io/flux/guides/repository-structure/&#34;&gt;fluxcd best practices&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Search</title>
      <link>https://uclab.dev/search/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://uclab.dev/search/</guid>
      <description></description>
    </item>
  </channel>
</rss>
