<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Homelab &amp; Infrastructure | Derek Armstrong — Software Engineer · AI · Infrastructure</title><link>https://derekarmstrong.dev/series/homelab--infrastructure/</link><atom:link href="https://derekarmstrong.dev/series/homelab--infrastructure/index.xml" rel="self" type="application/rss+xml"/><description>Homelab &amp; Infrastructure</description><generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Sat, 23 May 2026 00:00:00 +0000</lastBuildDate><image><url>https://derekarmstrong.dev/media/sharing.png</url><title>Homelab &amp; Infrastructure</title><link>https://derekarmstrong.dev/series/homelab--infrastructure/</link></image><item><title>Self-Hosting Plausible Analytics with Podman and Cloudflare Tunnels</title><link>https://derekarmstrong.dev/blog/self-hosting-plausible-analytics/</link><pubDate>Sat, 23 May 2026 00:00:00 +0000</pubDate><guid>https://derekarmstrong.dev/blog/self-hosting-plausible-analytics/</guid><description>&lt;p&gt;I needed website analytics for my blog. Not Google Analytics — I don&amp;rsquo;t want user data leaving my control, I don&amp;rsquo;t want the ads ecosystem, and I don&amp;rsquo;t need per-user behavioral tracking for a personal site. I needed something that tells me which posts show up in search and which ones I should stop writing. Plausible fills that gap.&lt;/p&gt;
&lt;p&gt;The open-source Community Edition is free, runs on commodity hardware, and has been supported by the Plausible team for years. The stack runs PostgreSQL, ClickHouse, and the application. Not hard, but enough infrastructure that it&amp;rsquo;s worth writing down how I set it up, what broke, and how I make sure I don&amp;rsquo;t lose data.&lt;/p&gt;
&lt;h2 id="the-stack"&gt;The Stack&lt;/h2&gt;
&lt;p&gt;Three containers, two databases, one app:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PostgreSQL 16&lt;/strong&gt; — application metadata: sites, users, event configuration, settings&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ClickHouse 24.12&lt;/strong&gt; — time-series event data: page views, referrers, exit pages, browser data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plausible App v3.2.1&lt;/strong&gt; — the web UI and tracking endpoint that serves the script tag&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Plausible team provides a docker-compose file you can copy. The modifications for podman were minimal.&lt;/p&gt;
&lt;h2 id="podman-quirks-on-rocky-linux"&gt;Podman Quirks on Rocky Linux&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s supposed to be a drop-in replacement for docker-compose. Same YAML, same commands, just swap the container engine. The issue is rootless pods.&lt;/p&gt;
&lt;p&gt;Rocky Linux&amp;rsquo;s podman doesn&amp;rsquo;t handle rootless pods well. I hit two issues:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Pod lifecycle crashes&lt;/strong&gt; — pods would create successfully, but the containers inside would crash immediately with &lt;code&gt;SIGTERM&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network mode host conflicts&lt;/strong&gt; — &lt;code&gt;network_mode: host&lt;/code&gt; caused port binding failures because the containers competed for the same ports&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The solution for the pod issue is &lt;code&gt;podman-compose up --in-pod=false&lt;/code&gt;, which tells podman to run the containers without grouping them into a pod. Each container runs independently, shares the network via a standard user-defined bridge. Same networking, no pod bugs.&lt;/p&gt;
&lt;p&gt;The solution for the network issue is a named bridge network defined in the compose file, with explicit port mappings. No host mode.&lt;/p&gt;
&lt;h2 id="the-setup"&gt;The Setup&lt;/h2&gt;
&lt;p&gt;The deployment lives in a subdirectory on prodweb. The compose file defines three services, four named volumes for each database, and one bridge network. The app container publishes port 8000, which Cloudflare&amp;rsquo;s tunnel connects to.&lt;/p&gt;
&lt;p&gt;The environment file handles the sensitive bits: &lt;code&gt;SECRET_KEY_BASE&lt;/code&gt;, &lt;code&gt;BASE_URL&lt;/code&gt;, and &lt;code&gt;DISABLE_REGISTRATION&lt;/code&gt;. The secret key is generated on first deploy with &lt;code&gt;openssl rand -base64 48&lt;/code&gt;. Registration is disabled after the initial admin account is created.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s it. No secrets management, no TLS certificates to maintain, no nginx or traefik layer. Cloudflare&amp;rsquo;s tunnel handles HTTPS termination and routing. I prefer the dashboard for the tunnel config.&lt;/p&gt;
&lt;h2 id="integration-with-hugo"&gt;Integration with Hugo&lt;/h2&gt;
&lt;p&gt;The Hugo site uses a theme that supports Plausible out of the box — the Blox theme has a built-in Plausible integration that lets you set the domain and it loads from your self-hosted instance. I changed the script source to point to my Plausible instance and updated the CSP content security policy to allow the tracking script to load from &lt;code&gt;analytics.derekarmstrong.dev&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The tracking script is minimal:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt; &lt;span class="na"&gt;async&lt;/span&gt; &lt;span class="na"&gt;defer&lt;/span&gt; &lt;span class="na"&gt;data-domain&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;derekarmstrong.dev&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;https://analytics.derekarmstrong.dev/js/script.js&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That goes in the head, and that&amp;rsquo;s it. Plausible handles the rest. No cookies, no GDPR notices, no dark pattern consent banners. It&amp;rsquo;s just page views.&lt;/p&gt;
&lt;h2 id="privacy-first"&gt;Privacy First&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;DISABLE_REGISTRATION=true&lt;/code&gt; flag is non-negotiable. Access is restricted to anyone with an account and a valid session token. Plausible scrubs IP addresses by default, storing only a cryptographic hash. The only identifiable data is the domain name and referrer. No user-level tracking, no behavioral analytics. Just aggregate counts.&lt;/p&gt;
&lt;h2 id="backing-up"&gt;Backing Up&lt;/h2&gt;
&lt;p&gt;This is the part most guides skip. Boring but important. There&amp;rsquo;s two databases, five podman volumes, one compose file, and one &lt;code&gt;.env&lt;/code&gt; file. All of it matters. As long as the PostgreSQL and ClickHouse data stays consistent, restoring is straightforward: export the volumes, copy the files, restore on a new server, start the containers, done.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;backup.sh&lt;/code&gt; script handles this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Stops the containers (so the database writes are durable)&lt;/li&gt;
&lt;li&gt;Exports each podman volume to a tar archive&lt;/li&gt;
&lt;li&gt;Copies &lt;code&gt;.env&lt;/code&gt; and &lt;code&gt;compose.yml&lt;/code&gt; to the backup&lt;/li&gt;
&lt;li&gt;Streams the backup off the host to a local machine&lt;/li&gt;
&lt;li&gt;Restarts the containers&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;code&gt;restore.sh&lt;/code&gt; script reverses the process: extract the backup, import the volumes, copy the config, start the containers.&lt;/p&gt;
&lt;p&gt;Both scripts are idempotent. The backup completes in under 2 minutes for my site. If you&amp;rsquo;re running a high-traffic site with large event tables, you might want to adjust the &lt;code&gt;STALE_DAYS&lt;/code&gt; variable to keep more recent backups around.&lt;/p&gt;
&lt;h2 id="running-it"&gt;Running It&lt;/h2&gt;
&lt;p&gt;The workflow is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Fresh deploy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./deploy.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Backup to local machine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./backup.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Restore from backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./restore.sh backup-20260523.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it. Deploy once, back up regularly, restore when needed.&lt;/p&gt;
&lt;h2 id="what-i-learned"&gt;What I Learned&lt;/h2&gt;
&lt;p&gt;The Podman rootless pod bugs on Rocky Linux were a real blocker. The ClickHouse config volume mounts don&amp;rsquo;t work with rootless podman — the workaround is to not mount external configs for ClickHouse at all. Less customization, but it works.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;.env&lt;/code&gt; file is the single point of failure for the deployment. If you lose the &lt;code&gt;.env&lt;/code&gt;, you lose the installation. The volume data exists on prodweb, but you can&amp;rsquo;t authenticate to the UI without the config. Every deploy script I&amp;rsquo;ve written since then backs up &lt;code&gt;.env&lt;/code&gt; explicitly. Back it up separately from the volume data.&lt;/p&gt;
&lt;p&gt;Plausible itself is solid. The UI is clean, the data is useful, and the privacy-first approach feels right for a personal blog. I&amp;rsquo;ve been running it for months and it hasn&amp;rsquo;t given me any trouble.&lt;/p&gt;
&lt;h2 id="key-takeaways"&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Plausible CE is privacy-first analytics: no cookies, no GDPR banners, no user-level tracking — just aggregate page view counts&lt;/li&gt;
&lt;li&gt;Podman rootless pods on Rocky Linux crash; run containers with &lt;code&gt;--in-pod=false&lt;/code&gt; to avoid the bug&lt;/li&gt;
&lt;li&gt;ClickHouse config volume mounts don&amp;rsquo;t work with rootless podman — skip external config mounts for ClickHouse&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;.env&lt;/code&gt; file is the single point of failure; back it up separately and explicitly on every deploy&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="next"&gt;Next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
— self-hosted AI infrastructure on the same homelab&lt;/li&gt;
&lt;li&gt;
— quick reference for managing containers with Podman&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;This is a personal blog post about my homelab and self-hosted infrastructure. It reflects what I&amp;rsquo;ve actually deployed and what has worked in production.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>The Proxmox Utility Toolkit: Stop Cloning That VM by Hand</title><link>https://derekarmstrong.dev/blog/proxmox-utility-toolkit/</link><pubDate>Thu, 09 Apr 2026 00:00:00 +0000</pubDate><guid>https://derekarmstrong.dev/blog/proxmox-utility-toolkit/</guid><description>&lt;p&gt;If you&amp;rsquo;ve been running Proxmox for more than six months, you&amp;rsquo;ve typed some version of &lt;code&gt;qm clone&lt;/code&gt; followed by a bunch of flags you half-remember from the last time, missed a step, and spent twenty minutes wondering why cloud-init isn&amp;rsquo;t picking up your IP. You&amp;rsquo;re not alone. I&amp;rsquo;ve done it enough times that I considered making it a cardio routine.&lt;/p&gt;
&lt;p&gt;After enough repetitions, the sensible answer isn&amp;rsquo;t &amp;ldquo;memorize the flags better.&amp;rdquo; It&amp;rsquo;s to build a toolkit, document it properly, and stop trusting your past self&amp;rsquo;s memory. So that&amp;rsquo;s what I did — and now it lives at
.&lt;/p&gt;
&lt;h2 id="what-the-repository-actually-is"&gt;What the Repository Actually Is&lt;/h2&gt;
&lt;p&gt;The
is a collection of shell scripts and documentation targeting Proxmox VE 8.x on Debian 12. It isn&amp;rsquo;t an abstraction layer, and it isn&amp;rsquo;t trying to replace the Proxmox web UI. It&amp;rsquo;s a set of opinionated scripts that handle the tedious parts — templating, cloning, backups, network reporting — so you can focus on what you&amp;rsquo;re actually trying to learn or build.&lt;/p&gt;
&lt;p&gt;The structure follows a clear division: &lt;code&gt;scripts/&lt;/code&gt; is where the automation lives, and the top-level directories (&lt;code&gt;backup/&lt;/code&gt;, &lt;code&gt;gpu-passthrough/&lt;/code&gt;, &lt;code&gt;networking/&lt;/code&gt;, &lt;code&gt;security/&lt;/code&gt;, &lt;code&gt;automation/&lt;/code&gt;) are documentation bundles that explain the &lt;em&gt;why&lt;/em&gt; behind the &lt;em&gt;how&lt;/em&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;proxmox/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── scripts/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── vm/ # Cloud-init templates, clone, snapshot, destroy, console
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── containers/ # LXC creation and management
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── backup/ # Single-VM, bulk, pruning, status reports
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── k8s/ # Oracle Linux Kubernetes cluster deployment
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── api/ # API token creation, curl wrappers
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── network/ # Network config reporting across VMs/containers
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── storage/ # Disk usage and cleanup
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── backup/ # Strategy docs: 3-2-1, GFS retention, PBS setup, verification
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── gpu-passthrough/ # NVIDIA CUDA, AMD ROCm, gaming VMs, troubleshooting
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── networking/ # VLAN, firewall rules, SDN configuration guides
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── automation/ # Ansible playbooks, Terraform configs, learning path
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── security/ # Zero trust, CIS benchmarks, auditing, incident response
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── learning-paths/ # Skill progression from &amp;#34;create a VM&amp;#34; to &amp;#34;zero trust&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One config file drives everything. Copy &lt;code&gt;config.example.sh&lt;/code&gt; to &lt;code&gt;config.sh&lt;/code&gt;, fill in your storage pool, bridge interface, SSH key path, template IDs, and backup retention settings. Set it once, use it across every script.&lt;/p&gt;
&lt;h2 id="vm-templates-and-cloning"&gt;VM Templates and Cloning&lt;/h2&gt;
&lt;p&gt;This is where most people spend the most time repeating themselves. Two cloud-init flavors are supported out of the box:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Ubuntu 24.04 — pull the SHA256 from the Ubuntu cloud images page&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash scripts/vm/create_cloud_init_template.sh -i &lt;span class="m"&gt;9000&lt;/span&gt; --sha256 &amp;lt;ubuntu_sha&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Oracle Linux 9 — checksum is bundled; this one just works&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash scripts/vm/create_cloud_init_template.sh -i &lt;span class="m"&gt;9100&lt;/span&gt; --os ol9
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once you have a template, cloning is one line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash scripts/vm/clone_vm.sh -s &lt;span class="m"&gt;9000&lt;/span&gt; -d &lt;span class="m"&gt;150&lt;/span&gt; -n web01 -i 192.168.1.60/24 -g 192.168.1.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Source template, destination ID, hostname, IP/mask, gateway. Your static IP and SSH key are baked into the VM before it boots. This is the &amp;ldquo;set it up correctly once and never think about it again&amp;rdquo; approach to ops. The rest of the VM scripts handle the supporting cast: &lt;code&gt;snapshot.sh&lt;/code&gt; for point-in-time recovery, &lt;code&gt;destroy_vm.sh&lt;/code&gt; when you&amp;rsquo;re done, &lt;code&gt;console.sh&lt;/code&gt; for quick access, and &lt;code&gt;find_ip.sh&lt;/code&gt; for when you can&amp;rsquo;t remember which IP you assigned to what.&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;&lt;strong&gt;Aside:&lt;/strong&gt; Cloud-init is one of those technologies that makes complete sense once you understand it and is maddening until you do. The most common trap is expecting cloud-init to re-run after the VM has already booted once — it won&amp;rsquo;t without being told to. If your config isn&amp;rsquo;t applying, &lt;code&gt;cloud-init clean&lt;/code&gt; followed by a reboot will save you a significant amount of frustrated tab-completion.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There&amp;rsquo;s also &lt;code&gt;check_template.sh&lt;/code&gt; to validate your template before you clone twenty VMs from it. Speaking from personal experience: validate the template.&lt;/p&gt;
&lt;h2 id="backups-youll-actually-verify"&gt;Backups You&amp;rsquo;ll Actually Verify&lt;/h2&gt;
&lt;p&gt;Backups are one of those things everyone &lt;em&gt;says&lt;/em&gt; they have until the moment they actually need one. The toolkit handles the whole lifecycle:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Single VM or container&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash scripts/backup/backup_vm.sh --vmid &lt;span class="m"&gt;150&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Everything on the node&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash scripts/backup/backup_all.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Prune per your retention policy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash scripts/backup/prune_backups.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Report on what&amp;#39;s actually protected&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash scripts/backup/report.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The backup strategy documentation covers the 3-2-1 approach (local backup, offsite copy, one offline or air-gapped) and GFS retention — Grandfather-Father-Son — which defines exactly how long daily, weekly, monthly, and yearly backups survive before pruning. It&amp;rsquo;s the structure commercial backup products charge extra to explain.&lt;/p&gt;
&lt;p&gt;The piece I&amp;rsquo;d read first, though, is &lt;code&gt;backup/verification.md&lt;/code&gt;. It covers how to confirm a backup is actually usable before you&amp;rsquo;re under pressure to find out. &amp;ldquo;I think it ran&amp;rdquo; is not a backup strategy. Running a restore drill in a test environment once and confirming it succeeds is.&lt;/p&gt;
&lt;h2 id="gpu-passthrough-without-the-three-hour-research-session"&gt;GPU Passthrough Without the Three-Hour Research Session&lt;/h2&gt;
&lt;p&gt;GPU passthrough in Proxmox has a well-earned reputation for being complicated. The gap between &amp;ldquo;works in theory&amp;rdquo; and &amp;ldquo;works for my specific GPU and motherboard combo&amp;rdquo; is where most people give up and just run the GPU on bare metal. The documentation in the toolkit covers both major paths:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;NVIDIA + CUDA&lt;/strong&gt; — for AI/ML workloads on a dedicated GPU inside a VM, with the driver configuration that actually sticks&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AMD + ROCm&lt;/strong&gt; — the open-source path for inference and compute work, including ROCm setup inside the guest&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gaming VMs&lt;/strong&gt; — single GPU passthrough for a Windows gaming VM is a completely reasonable use of hardware you own, and there&amp;rsquo;s a dedicated guide for it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&amp;rsquo;s a troubleshooting guide for when IOMMU groupings don&amp;rsquo;t cooperate, which on consumer hardware is more of a &amp;ldquo;when&amp;rdquo; than an &amp;ldquo;if.&amp;rdquo; ACS override options, VFIO binding order, and the usual suspects are all covered.&lt;/p&gt;
&lt;h2 id="kubernetes-on-top-of-proxmox"&gt;Kubernetes on Top of Proxmox&lt;/h2&gt;
&lt;p&gt;One script deploys a full Oracle Linux Kubernetes cluster:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash scripts/k8s/deploy_ol_k8s_cluster.sh --config config.k8s.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It targets the &lt;code&gt;192.168.1.50-99&lt;/code&gt; homelab IP range by default, handles VM provisioning, and walks through the Kubernetes bootstrapping sequence. This is explicitly a learning-path feature — it&amp;rsquo;s not production-hardened, and it doesn&amp;rsquo;t pretend to be. What it &lt;em&gt;is&lt;/em&gt; good for is understanding how Kubernetes actually comes together piece by piece, without a managed service abstracting away the interesting parts.&lt;/p&gt;
&lt;p&gt;If your goal is to understand what &lt;code&gt;kubeadm init&lt;/code&gt; is doing and why, this is a faster path to that knowledge than starting from scratch.&lt;/p&gt;
&lt;h2 id="security-worth-taking-seriously"&gt;Security Worth Taking Seriously&lt;/h2&gt;
&lt;p&gt;Security docs in most homelab repos are an afterthought dropped in because someone mentioned it in a pull request. This one treats security as first-class content:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Document&lt;/th&gt;
&lt;th&gt;Coverage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;security/zero-trust.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Network segmentation, identity verification, least-privilege access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;security/cis-benchmarks.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Host hardening guidelines for the Proxmox node itself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;security/auditing.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;What to check, how often, and what to do with the results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;security/incident-response.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;What to do when something actually goes sideways&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The honest caveat: these are guides, not automation. The expectation is that you read them, understand the reasoning, and implement with intention — not apply them blindly and assume you&amp;rsquo;re done. Security posture is a continuous practice, not a one-time configuration.&lt;/p&gt;
&lt;h2 id="automation-ansible-terraform-and-api-access"&gt;Automation: Ansible, Terraform, and API Access&lt;/h2&gt;
&lt;p&gt;Once you&amp;rsquo;re past one-off scripts and want repeatable, idempotent infrastructure, the toolkit has an on-ramp:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ansible playbooks&lt;/strong&gt; — configuration management for Proxmox nodes and the VMs running on them&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Terraform + HCL&lt;/strong&gt; — infrastructure-as-code for provisioning, with a &lt;code&gt;main.tf&lt;/code&gt; and example patterns to build from&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API helpers&lt;/strong&gt; — &lt;code&gt;create_api_token.sh&lt;/code&gt; and a minimal curl wrapper for the Proxmox API, useful when you&amp;rsquo;re scripting against the REST interface and don&amp;rsquo;t want to build that boilerplate yourself&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;automation/learning-path.md&lt;/code&gt; lays out the progression: scripts first, Ansible when you need repeatability across multiple nodes, Terraform when you&amp;rsquo;re ready to think declaratively about what infrastructure should exist. That order matters — jumping straight to Terraform before you understand what it&amp;rsquo;s abstracting will bite you.&lt;/p&gt;
&lt;h2 id="learning-paths-theres-an-on-ramp-for-everyone"&gt;Learning Paths: There&amp;rsquo;s an On-Ramp for Everyone&lt;/h2&gt;
&lt;p&gt;This is the part that makes the toolkit useful across experience levels rather than just to people who already know what they&amp;rsquo;re doing:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;What You&amp;rsquo;re Building&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Beginner&lt;/td&gt;
&lt;td&gt;VM and container basics, simple backups, basic networking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intermediate&lt;/td&gt;
&lt;td&gt;VLANs, firewall rules, automated backup retention, Ansible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Advanced&lt;/td&gt;
&lt;td&gt;Proxmox Backup Server, GPU passthrough, Terraform IaC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expert&lt;/td&gt;
&lt;td&gt;Zero trust architecture, CIS benchmark compliance, automated incident response&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Most resources assume you&amp;rsquo;re either totally new or already building production clusters. The learning paths here acknowledge that the interesting ground is in between — where you understand enough to ask the right questions but haven&amp;rsquo;t yet built the muscle memory for the complex stuff.&lt;/p&gt;
&lt;h2 id="getting-started"&gt;Getting Started&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/dereklarmstrong/proxmox.git
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; proxmox
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cp config.example.sh config.sh &lt;span class="c1"&gt;# Edit with your storage pool, bridge, SSH key path&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./scripts/test.sh &lt;span class="c1"&gt;# Run the test suite — worth doing before you rely on any of this&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The logical starting point from there is enabling the community repository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash scripts/setup/pve_community_repo.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then &lt;code&gt;create_cloud_init_template.sh&lt;/code&gt; to build your first template. Everything else in the toolkit follows from having a good, verified base template to clone from.&lt;/p&gt;
&lt;h2 id="key-takeaways"&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Clone any cloud-init VM — Ubuntu 24.04, Oracle Linux 9 — with a single command&lt;/strong&gt;, static IP and SSH key pre-configured, no copy-paste required.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Full backup coverage out of the box&lt;/strong&gt;: per-VM, bulk, GFS retention policies, and a status report so you actually know what&amp;rsquo;s protected.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPU passthrough documentation for NVIDIA CUDA and AMD ROCm&lt;/strong&gt; in one place — AI/ML and gaming paths covered.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Structured learning paths from beginner to expert&lt;/strong&gt; so the toolkit grows with you rather than overwhelming you on day one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;This is a learning playground, not a production blueprint.&lt;/strong&gt; Complexity is a liability. The scripts exist to build skills, not to run your business.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="next"&gt;Next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
— Once your VMs are provisioned, you need databases. This post covers picking and securing stores that stay boring (in a good way).&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Nagios: A 10-Year Retrospective on Infrastructure Monitoring</title><link>https://derekarmstrong.dev/blog/nagios-10-year-retrospective/</link><pubDate>Wed, 05 Nov 2025 00:00:00 +0000</pubDate><guid>https://derekarmstrong.dev/blog/nagios-10-year-retrospective/</guid><description>&lt;p&gt;Back in 2015 I installed Nagios in my homelab and pushed it out to a few servers at work. That was ten years ago, and even then Nagios felt like an OG, a little venerable. But the thing about Nagios is simple: it tells you when stuff is broken, loudly and reliably. It&amp;rsquo;s the tape measure of monitoring, not flashy, but it does the job.&lt;/p&gt;
&lt;h2 id="the-strategic-validation-approach"&gt;The Strategic Validation Approach&lt;/h2&gt;
&lt;p&gt;I first deployed Nagios in my homelab to validate it as a viable enterprise solution before proposing it for production use. This homelab-to-production pipeline became a pattern I&amp;rsquo;d use throughout my career, prove the concept in a controlled environment, demonstrate value, then scale to production.&lt;/p&gt;
&lt;p&gt;The homelab deployment served multiple purposes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Risk mitigation&lt;/strong&gt;: Test configurations and failure scenarios without production impact&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Knowledge building&lt;/strong&gt;: Understand operational characteristics and maintenance requirements&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Documentation creation&lt;/strong&gt;: Build runbooks and procedures before production deployment&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stakeholder confidence&lt;/strong&gt;: Demonstrate concrete results to secure buy-in&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This validation approach proved invaluable when it came time to deploy at scale.&lt;/p&gt;
&lt;h2 id="production-deployment-transforming-it-operations"&gt;Production Deployment: Transforming IT Operations&lt;/h2&gt;
&lt;p&gt;In 2015, I implemented Nagios Core for a multi-location restaurant chain&amp;rsquo;s enterprise infrastructure, monitoring mission-critical systems supporting Marketing, Accounting, Operations, and IT departments. With on-premises rack infrastructure hosting critical business applications, visibility and rapid incident response were non-negotiable.&lt;/p&gt;
&lt;h3 id="architecture-and-scale"&gt;Architecture and Scale&lt;/h3&gt;
&lt;p&gt;The deployment monitored:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Physical infrastructure&lt;/strong&gt;: Network switches, routers, and edge devices across multiple locations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Virtualization platform&lt;/strong&gt;: VMware ESXi hosts and guest VMs running core business services&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application services&lt;/strong&gt;: Payment processing, point-of-sale integration, inventory management, and business intelligence platforms&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network health&lt;/strong&gt;: Bandwidth utilization, latency metrics, and connectivity monitoring&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="business-impact-from-reactive-to-proactive"&gt;Business Impact: From Reactive to Proactive&lt;/h3&gt;
&lt;p&gt;The transformation was measurable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mean Time to Detection (MTTD)&lt;/strong&gt;: Reduced from hours (waiting for user reports) to minutes (automated alerts)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mean Time to Resolution (MTTR)&lt;/strong&gt;: Improved significantly through early problem detection and automated escalation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IT team efficiency&lt;/strong&gt;: Support team shifted from constant firefighting to proactive maintenance and strategic projects&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Business continuity&lt;/strong&gt;: Critical application downtime decreased substantially through early intervention&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key insight: &lt;strong&gt;Monitoring isn&amp;rsquo;t just about knowing when things break, it&amp;rsquo;s about preventing disruptions before they impact business operations.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="quick-personal-setup"&gt;Quick Personal Setup&lt;/h2&gt;
&lt;p&gt;My homelab configuration provided the foundation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nagios Core on a small VM (2 vCPU, 4GB RAM, remarkably lightweight)&lt;/li&gt;
&lt;li&gt;NRPE (Nagios Remote Plugin Executor) on Linux servers for remote checks&lt;/li&gt;
&lt;li&gt;SNMP monitoring for network switches and printers&lt;/li&gt;
&lt;li&gt;Host/service groups, email alerts, basic escalation rules&lt;/li&gt;
&lt;li&gt;Stable, low-maintenance, perfect for static infrastructure&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This same architecture scaled to production with minimal modifications, a testament to Nagios&amp;rsquo;s solid foundation.&lt;/p&gt;
&lt;h2 id="purpose-and-architecture"&gt;Purpose and Architecture&lt;/h2&gt;
&lt;p&gt;Nagios Core performs periodic checks of hosts and services, runs plugins to test availability and health, and alerts when thresholds are breached. It&amp;rsquo;s rule-based monitoring with dependency handling, escalations, and a massive plugin ecosystem that covers virtually any service or device.&lt;/p&gt;
&lt;p&gt;The architecture is refreshingly straightforward:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Scheduled checks&lt;/strong&gt;: Predictable, configurable monitoring intervals&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plugin ecosystem&lt;/strong&gt;: Extend monitoring to any service or protocol&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State management&lt;/strong&gt;: Clear host/service states (OK, Warning, Critical, Unknown)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dependency handling&lt;/strong&gt;: Prevent alert storms through intelligent parent/child relationships&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Escalation policies&lt;/strong&gt;: Route alerts appropriately based on severity and duration&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="key-benefits"&gt;Key Benefits&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Proven and stable&lt;/strong&gt;: Decades in production across countless organizations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lightweight architecture&lt;/strong&gt;: Minimal resource consumption, even at scale&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Huge plugin ecosystem&lt;/strong&gt;: Likely a plugin exists for whatever you need to monitor&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Predictable alerting model&lt;/strong&gt;: Host/service states, dependencies, escalations, no surprises&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fully on-premises&lt;/strong&gt;: Great for air-gapped or regulated environments&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Open source&lt;/strong&gt; (Nagios Core): No vendor lock-in for basic monitoring needs&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="free-tiers--editions"&gt;Free Tiers / Editions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nagios Core&lt;/strong&gt;: Free and open source (self-hosted)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nagios XI&lt;/strong&gt;: Commercial with evaluation/demo; paid tiers for enterprise features and polished UI&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Other Nagios products&lt;/strong&gt;: Fusion, Log Server, Network Analyzer are commercial or trial-based&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-choose-nagios"&gt;When to Choose Nagios&lt;/h2&gt;
&lt;p&gt;Strategic fit for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Small to medium static IT environments (servers, VMs, network gear)&lt;/li&gt;
&lt;li&gt;Labs, classrooms, SMBs, and conservative or regulated organizations&lt;/li&gt;
&lt;li&gt;On-premises / air-gapped environments where SaaS is prohibited&lt;/li&gt;
&lt;li&gt;Teams wanting straightforward up/down availability checks and predictable alerts&lt;/li&gt;
&lt;li&gt;Organizations needing comprehensive community checks without building from scratch&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-not-to-choose-nagios"&gt;When Not to Choose Nagios&lt;/h2&gt;
&lt;p&gt;Consider alternatives for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cloud-native, highly dynamic infrastructure (ephemeral containers, autoscaling)&lt;/li&gt;
&lt;li&gt;Rich time-series metrics, long-term trend analysis, anomaly detection, or high-cardinality telemetry&lt;/li&gt;
&lt;li&gt;Large, high-scale environments with heavy metric volumes (Prometheus-style stacks scale better)&lt;/li&gt;
&lt;li&gt;Modern UIs, automated incident correlation, integrated logs/metrics/traces, or extensive SaaS integrations&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="industries-where-nagios-shines"&gt;Industries Where Nagios Shines&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Education &amp;amp; labs&lt;/strong&gt;: Easy management of classroom PCs, lab servers, and fixed infrastructure&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SMBs and small IT shops&lt;/strong&gt;: Low cost, low complexity&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Government or regulated organizations&lt;/strong&gt;: On-premises-only monitoring requirements&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traditional enterprises&lt;/strong&gt;: Stable, non-ephemeral infrastructure (datacenters, network device uptime)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="industries-where-it-struggles"&gt;Industries Where It Struggles&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cloud-native SaaS companies&lt;/strong&gt;: Modern DevOps teams with ephemeral infrastructure&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Large web platforms&lt;/strong&gt;: Requiring high-volume telemetry and advanced analytics&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Organizations demanding modern observability&lt;/strong&gt;: Integrated traces, logs, and metrics with automated anomaly detection&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="quick-pros--cons"&gt;Quick Pros &amp;amp; Cons&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;: Dependable, extensible plugin library, lightweight, fully on-premises&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;: Old-school configuration model, limited metric retention/analysis, dated UI, not ideal for dynamic fleets&lt;/p&gt;
&lt;h2 id="alternatives-and-comparison"&gt;Alternatives and Comparison&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Metrics + alerting for modern infrastructure&lt;/strong&gt;: Prometheus + Grafana&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Modernized Nagios-style&lt;/strong&gt;: Icinga2, Check_MK, Zabbix&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SaaS / deep integrations&lt;/strong&gt;: Datadog, New Relic, LogicMonitor&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Flexible checks + event handling&lt;/strong&gt;: Sensu&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criteria&lt;/th&gt;
&lt;th&gt;Nagios&lt;/th&gt;
&lt;th&gt;Prometheus&lt;/th&gt;
&lt;th&gt;Zabbix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary focus&lt;/td&gt;
&lt;td&gt;Availability checks (hosts/services)&lt;/td&gt;
&lt;td&gt;Time-series metrics &amp;amp; alerting&lt;/td&gt;
&lt;td&gt;Unified monitoring: metrics, traps, availability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Small/SMB/static infra, labs&lt;/td&gt;
&lt;td&gt;Cloud-native, containerized, microservices&lt;/td&gt;
&lt;td&gt;Mid-to-large infra needing both metrics &amp;amp; legacy device support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scale&lt;/td&gt;
&lt;td&gt;Small → medium (with effort)&lt;/td&gt;
&lt;td&gt;High (designed for scale; federation)&lt;/td&gt;
&lt;td&gt;Medium → large (scales with clustering)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data model &amp;amp; retention&lt;/td&gt;
&lt;td&gt;Check states, limited metric history&lt;/td&gt;
&lt;td&gt;TSDB (Prometheus), short-term retention by default; long-term via remote storage&lt;/td&gt;
&lt;td&gt;Built-in history storage with configurable retention&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Metrics visualization&lt;/td&gt;
&lt;td&gt;External tools (Grafana) or basic UI&lt;/td&gt;
&lt;td&gt;Grafana or built-in graphing; strong ecosystem&lt;/td&gt;
&lt;td&gt;Built-in dashboards; Grafana integration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alerting &amp;amp; correlation&lt;/td&gt;
&lt;td&gt;Basic alerts, escalations, dependencies&lt;/td&gt;
&lt;td&gt;Powerful rule-based alerts; Alertmanager for grouping/dedup&lt;/td&gt;
&lt;td&gt;Flexible triggers, escalations, notifications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic/cloud-native support&lt;/td&gt;
&lt;td&gt;Poor for ephemeral infra&lt;/td&gt;
&lt;td&gt;Excellent (service discovery, scraping)&lt;/td&gt;
&lt;td&gt;Good (agent, SNMP, auto-registration)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Setup &amp;amp; maintenance&lt;/td&gt;
&lt;td&gt;Simple for small installs; config heavy&lt;/td&gt;
&lt;td&gt;Pull model needs scrape config + storage planning&lt;/td&gt;
&lt;td&gt;Agent + server setup; GUI config but can be complex&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extensibility/plugins&lt;/td&gt;
&lt;td&gt;Huge plugin ecosystem&lt;/td&gt;
&lt;td&gt;Exporters + client libs; many integrations&lt;/td&gt;
&lt;td&gt;Templates, user parameters, scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On-premises friendliness&lt;/td&gt;
&lt;td&gt;Excellent (air-gapped friendly)&lt;/td&gt;
&lt;td&gt;Good (self-hosted)&lt;/td&gt;
&lt;td&gt;Excellent (on-premises first)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical use cases&lt;/td&gt;
&lt;td&gt;Labs, SMBs, network device uptime, regulated envs&lt;/td&gt;
&lt;td&gt;Metrics for microservices, SRE workflows, high-cardinality monitoring&lt;/td&gt;
&lt;td&gt;Mixed environments: servers, network, apps, SNMP devices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Not suitable when&lt;/td&gt;
&lt;td&gt;Need long-term metrics, dynamic infra, advanced analytics&lt;/td&gt;
&lt;td&gt;Need raw host/service plugin checks or heavy SNMP device mgmt&lt;/td&gt;
&lt;td&gt;Need extreme TSDB scaling or cloud-native ephemeral service auto-discovery&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="quick-pick-guide"&gt;Quick Pick Guide&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Choose Nagios&lt;/strong&gt; if you want simple, reliable up/down checks, on-premises only, and a massive plugin library for legacy devices&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Choose Prometheus&lt;/strong&gt; if you run cloud-native, containerized apps and need high-resolution metrics, service discovery, and modern alert routing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Choose Zabbix&lt;/strong&gt; if you need an all-in-one on-premises system covering metrics, SNMP, traps, and history without stitching many components together&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="architectural-lessons-learned"&gt;Architectural Lessons Learned&lt;/h2&gt;
&lt;p&gt;After a decade of Nagios deployments, key insights emerged:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Configuration as code&lt;/strong&gt;: Treat Nagios configs like application code, version control, peer review, automated testing&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dependency modeling&lt;/strong&gt;: Properly configured dependencies prevent alert fatigue and focus attention where it matters&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Escalation policies&lt;/strong&gt;: Well-designed escalations ensure the right people are notified at the right time without overwhelming anyone&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Plugin standardization&lt;/strong&gt;: Custom plugins should follow consistent interfaces and error handling patterns&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Monitoring the monitor&lt;/strong&gt;: Nagios itself needs monitoring, use external health checks to ensure your monitoring system is operational&lt;/p&gt;
&lt;h2 id="final-thought"&gt;Final Thought&lt;/h2&gt;
&lt;p&gt;Monitoring is boring until it saves your day, then it&amp;rsquo;s priceless. Nagios is old school, but if you want a no-nonsense, on-premises sentinel that simply tells you &amp;ldquo;this server is down,&amp;rdquo; it still earns its keep. Use it for stability and simplicity; choose a newer stack when you need rich metrics, scale, and modern observability features.&lt;/p&gt;
&lt;p&gt;After ten years, the homelab installation that validated an enterprise deployment is still running. That&amp;rsquo;s the kind of stability and reliability that defines Nagios: unglamorous, dependable infrastructure monitoring that just works.&lt;/p&gt;
&lt;h2 id="key-takeaways"&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Validate in a homelab first — prove the concept at small scale before committing to production deployment&lt;/li&gt;
&lt;li&gt;Nagios is still relevant for static infrastructure: on-premises labs, SMBs, regulated environments where SaaS monitoring is off the table&lt;/li&gt;
&lt;li&gt;When infrastructure is ephemeral or highly dynamic, Prometheus or Zabbix are better fits than Nagios&lt;/li&gt;
&lt;li&gt;Good dependency modeling and escalation policies prevent alert fatigue; bad configuration turns monitoring into noise&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="next"&gt;Next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
— homelab-to-production in action with a completely different workload&lt;/li&gt;
&lt;li&gt;
— how the underlying infrastructure was built&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Podman Cheat Sheet</title><link>https://derekarmstrong.dev/blog/podman-cheat-sheet/</link><pubDate>Wed, 21 May 2025 00:00:00 +0000</pubDate><guid>https://derekarmstrong.dev/blog/podman-cheat-sheet/</guid><description>&lt;h3 id="start-and-stop-containers"&gt;Start and Stop Containers&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Start a container&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman start &amp;lt;container_name_or_id&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stop a container&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman stop &amp;lt;container_name_or_id&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="build-an-image"&gt;Build an Image&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Build an image from a Dockerfile&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman build -t &amp;lt;image_name:tag&amp;gt; .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="run-a-container"&gt;Run a Container&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Run a container&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman run --name &amp;lt;container_name&amp;gt; &amp;lt;image_name:tag&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Run a container and remove it after it exits&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman run --rm &amp;lt;image_name:tag&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="remove-containers-and-images"&gt;Remove Containers and Images&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Remove a container&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman rm &amp;lt;container_name_or_id&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Remove all stopped containers&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman container prune
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Remove an image&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman rmi &amp;lt;image_name_or_id&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="podman-compose-if-using-podman-compose"&gt;Podman Compose (if using &lt;code&gt;podman-compose&lt;/code&gt;)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Start containers with Podman Compose&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman-compose up
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stop containers with Podman Compose&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman-compose down
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Build images with Podman Compose&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman-compose build
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="additional-useful-commands"&gt;Additional Useful Commands&lt;/h2&gt;
&lt;h3 id="inspect"&gt;Inspect&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Inspect a container&lt;/strong&gt; (view details about a running or stopped container):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman inspect &amp;lt;container_name_or_id&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="logs"&gt;Logs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;View logs for a container&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman logs &amp;lt;container_name_or_id&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="list-containers-and-images"&gt;List Containers and Images&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;List all containers&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman ps -a
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;List running containers&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman ps
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;List all images&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman images
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="key-takeaways"&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Podman is a drop-in replacement for Docker with a CLI that maps 1:1 for common container operations&lt;/li&gt;
&lt;li&gt;podman-compose handles multi-container setups, but requires the separate podman-compose package&lt;/li&gt;
&lt;li&gt;Rootless podman is the default and preferred mode — no daemon running as root is a security improvement over Docker&lt;/li&gt;
&lt;li&gt;Commands group by lifecycle: start/stop, build/run, remove, inspect/logs, and list&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="next"&gt;Next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
— a real-world Podman deployment with troubleshooting notes&lt;/li&gt;
&lt;li&gt;
— container basics and why they matter for development workflows&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Gitea: Git on Your Own Terms</title><link>https://derekarmstrong.dev/blog/gitea-git-on-your-own-terms/</link><pubDate>Wed, 23 Apr 2025 00:00:00 +0000</pubDate><guid>https://derekarmstrong.dev/blog/gitea-git-on-your-own-terms/</guid><description>&lt;p&gt;Welcome, fellow home lab enthusiasts! If you&amp;rsquo;re anything like me, you&amp;rsquo;ve probably caught yourself thinking, &amp;ldquo;You know what my server rack needs? More services to tinker with!&amp;rdquo; Well, today we&amp;rsquo;re diving into one of my favorite self-hosted applications: a personal Git server with Gitea. It&amp;rsquo;s like having your own mini GitHub, without the corporate overlords or surprise &amp;ldquo;updates&amp;rdquo; to the terms of service.&lt;/p&gt;
&lt;h2 id="why-gitea-the-little-git-server-that-could"&gt;Why Gitea? The Little Git Server That Could&lt;/h2&gt;
&lt;p&gt;In the world of self-hosted Git solutions, Gitea stands out like a sane person at a cryptocurrency convention. Written in Go, Gitea is ridiculously lightweight, blazing fast, and requires minimal resources - perfect for that dusty Raspberry Pi or the VM you&amp;rsquo;ve allocated just 512MB of RAM to.&lt;/p&gt;
&lt;p&gt;While GitLab offers a more comprehensive DevOps platform with all the bells and whistles (and resource requirements to match), Gitea focuses on doing one thing extremely well: being a Git server that doesn&amp;rsquo;t make your hardware weep. As one user aptly put it: &amp;ldquo;Gitea + SQLite is perfect for home lab. Zero maintenance overhead&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;The interface will feel familiar to GitHub users, which makes the transition nearly painless. Plus, the project is actively maintained with regular updates and security patches.&lt;/p&gt;
&lt;h2 id="the-pros-why-youd-want-your-own-git-fortress"&gt;The Pros: Why You&amp;rsquo;d Want Your Own Git Fortress&lt;/h2&gt;
&lt;h3 id="data-sovereignty-your-code-your-rules"&gt;Data Sovereignty: Your Code, Your Rules&lt;/h3&gt;
&lt;p&gt;Having your own Git server means you&amp;rsquo;re not subject to a third party&amp;rsquo;s policies, outages, or sudden pricing changes. No third party has access to your data, ensuring security (which can still be questionable), and you have unlimited repository size.&lt;/p&gt;
&lt;h3 id="mirror-mirror-on-the-wall-who-has-the-most-repos-of-all"&gt;Mirror, Mirror on the Wall, Who Has the Most Repos of All?&lt;/h3&gt;
&lt;p&gt;One of Gitea&amp;rsquo;s killer features is its mirroring capability. You can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Mirror repositories from GitHub, GitLab, or other services to create automatic backups&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Push changes from your private Gitea instance to public repositories&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Keep everything in sync with minimal effort&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Gitea makes it trivial to mirror a repo. You just choose &amp;rsquo;new migration&amp;rsquo; from under the &amp;lsquo;+&amp;rsquo; menu, and then click on the service you&amp;rsquo;re migrating from.&lt;/p&gt;
&lt;h3 id="unrestricted-runner-minutes-cicd-without-the-meter-running"&gt;Unrestricted Runner Minutes: CI/CD without the Meter Running&lt;/h3&gt;
&lt;p&gt;Unlike GitHub, which meters your CI/CD minutes like a stingy taxi driver, your self-hosted Gitea instance lets you run your CI/CD pipelines as long as your hardware can handle it. Want to set up a 3-hour build process that compiles your personal project on seven different architectures? Go wild!&lt;/p&gt;
&lt;h3 id="offline-access-because-internet-outages-are-a-thing"&gt;Offline Access: Because Internet Outages Are a Thing&lt;/h3&gt;
&lt;p&gt;Another great reason to host your own Gitea instance is that it&amp;rsquo;s available offline. When your internet decides to take an unscheduled vacation, you can still commit changes, browse code, and reference documentation.&lt;/p&gt;
&lt;h3 id="unlimited-private-repositories"&gt;Unlimited Private Repositories&lt;/h3&gt;
&lt;p&gt;You don&amp;rsquo;t need to pay for private repositories or worry about limits from third-party services. With your own server, you have full control and can create unlimited private repositories at no extra cost. This lets you organize projects your way, whether they&amp;rsquo;re small or large, and customize your workflow to fit your needs.&lt;/p&gt;
&lt;h2 id="the-cons-the-price-of-freedom"&gt;The Cons: The Price of Freedom&lt;/h2&gt;
&lt;h3 id="maintenance-you-break-it-you-fix-it"&gt;Maintenance: You Break It, You Fix It&lt;/h3&gt;
&lt;p&gt;Self-hosting means being your own system administrator. When things go sideways, there&amp;rsquo;s no support ticket to file (unless you count yelling at your server rack).&lt;/p&gt;
&lt;h3 id="backups-dont-be-that-person"&gt;Backups: Don&amp;rsquo;t Be That Person&lt;/h3&gt;
&lt;p&gt;You absolutely need a backup strategy. &amp;ldquo;Just wondering what everyone is doing to back up a gitea container?” is a question you should answer before, not after, a disk failure.&lt;/p&gt;
&lt;h3 id="security-with-great-power-comes-great-responsibility"&gt;Security: With Great Power Comes Great Responsibility&lt;/h3&gt;
&lt;p&gt;Security - continuous monitoring just in case someone gets curious&amp;hellip;and lucky. If you&amp;rsquo;re exposing your Gitea instance to the internet, you need to be vigilant about security. Do your homework, understanding how to impliment good security is a high value skill!&lt;/p&gt;
&lt;h2 id="protecting-your-code-castle"&gt;Protecting Your Code Castle&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re keeping your Gitea instance local, behind your firewall, security is relatively simple. But if you&amp;rsquo;re exposing it to the internet, consider:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Using Cloudflare Zero Trust tunnels to avoid opening ports&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enforcing two-factor authentication for all accounts&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Keeping your instance updated religiously&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Implementing strong password policies&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember: The first registered user automatically gets admin privileges, so set up your account immediately after installation!&lt;/p&gt;
&lt;h2 id="setting-sail-with-docker-compose"&gt;Setting Sail with Docker Compose&lt;/h2&gt;
&lt;p&gt;Getting started with Gitea is as easy as creating a docker-compose.yml file. Here&amp;rsquo;s a basic example to get you started:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;3&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;gitea/gitea:latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;gitea&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;USER_UID=1000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;USER_GID=1000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;always&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./gitea:/data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/etc/timezone:/etc/timezone:ro&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/etc/localtime:/etc/localtime:ro&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;3000:3000&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;2222:22&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Save this to a file, run &lt;code&gt;docker-compose up -d&lt;/code&gt;, and voilà! Your Gitea instance will be available at
. The first user to register will become the admin.&lt;/p&gt;
&lt;p&gt;For those who prefer a more rootless approach (because who doesn&amp;rsquo;t like added security?), Gitea also offers a rootless Docker image that uses Gitea&amp;rsquo;s internal SSH instead of OpenSSH.&lt;/p&gt;
&lt;h2 id="customization-making-it-your-own"&gt;Customization: Making It Your Own&lt;/h2&gt;
&lt;p&gt;The beauty of self-hosting is customization. Want to change the theme? Go for it. Need to integrate with your existing authentication system? It&amp;rsquo;s possible. Want to add a dancing cat gif to the login page? Weird, but technically doable.&lt;/p&gt;
&lt;p&gt;All configuration is stored in the &lt;code&gt;app.ini&lt;/code&gt; file, which you can find in the &lt;code&gt;custom&lt;/code&gt; directory of your Gitea installation.&lt;/p&gt;
&lt;h2 id="backup-strategies-because-stuff-happens"&gt;Backup Strategies: Because Stuff Happens&lt;/h2&gt;
&lt;p&gt;Gitea provides a built-in &lt;code&gt;dump&lt;/code&gt; command that creates a ZIP file containing everything needed to restore your instance. However, for a more robust solution, consider:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Regular database backups&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Volume snapshots if you&amp;rsquo;re using a filesystem that supports them&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Repository mirroring to another location&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Automated backup scripts that run on a schedule&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember: a backup you haven&amp;rsquo;t tested restoring from is just a file taking up disk space.&lt;/p&gt;
&lt;h2 id="conclusion-to-git-or-not-to-git"&gt;Conclusion: To Git or Not to Git?&lt;/h2&gt;
&lt;p&gt;Self-hosting Gitea is like brewing your own craft beer. Sure, you could just buy it from the store, but where&amp;rsquo;s the fun in that? Plus, you get to brag about it to your friends who don&amp;rsquo;t care but politely nod anyway.&lt;/p&gt;
&lt;p&gt;The control, flexibility, and ownership you gain makes it worth the effort, especially if you&amp;rsquo;re already maintaining a home lab. So fire up that Docker container and start gitting on your own terms. Your code deserves a home where it&amp;rsquo;s treated like the precious resource it is, not just another tenant in a massive cloud datacenter.&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Gitea Documentation. (2023). Repository Mirror.
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Gitea Documentation. (2023). Installation with Docker (rootless).
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stack Overflow. (2017). Which are the pros (and cons) of self-hosting your repositories.
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;XDA Developers. (2024). 5 reasons you should host your own Git server at home using Gitea.
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
. (2022). Mirroring With Gitea.
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;phoenixNAP. (2025). How to Install Gitea with Docker on Ubuntu.
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reddit. (2019). Pros &amp;amp; Cons: Self Hosted Git.
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="key-takeaways"&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Gitea is lightweight enough for a Raspberry Pi or a 512MB VM. Written in Go, it does one thing well without the resource drain of GitLab.&lt;/li&gt;
&lt;li&gt;Repository mirroring is a killer feature. One-click mirroring from GitHub or GitLab gives you automatic backups and offline access.&lt;/li&gt;
&lt;li&gt;Self-hosted CI/CD means unlimited runner minutes. Build pipelines run as long as your hardware can handle them.&lt;/li&gt;
&lt;li&gt;Security is your responsibility. Cloudflare Zero Trust tunnels, 2FA, and strong password policies are the bare minimum when exposing Gitea to the internet.&lt;/li&gt;
&lt;li&gt;A backup you have not tested restoring from is just a file taking up disk space. Test restores regularly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="next"&gt;Next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
— the server infrastructure that makes self-hosting services practical.&lt;/li&gt;
&lt;li&gt;
— VM management tools for the homelab that runs alongside container services.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Dev Magic with Docker</title><link>https://derekarmstrong.dev/blog/dev-magic-with-docker/</link><pubDate>Wed, 19 Feb 2025 00:00:00 +0000</pubDate><guid>https://derekarmstrong.dev/blog/dev-magic-with-docker/</guid><description>&lt;p&gt;Docker removed the &amp;ldquo;it works on my machine&amp;rdquo; problem by packaging applications with all their dependencies into containers. If you&amp;rsquo;ve spent time debugging why a service runs on one machine but not another, Docker is the solution that made that problem disappear.&lt;/p&gt;
&lt;h2 id="so-whats-docker"&gt;&lt;strong&gt;So, What’s Docker?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Docker is this awesome open-source platform that helps you package up your application, along with EVERYTHING it needs to run—like libraries, dependencies, and settings—into little units called &lt;strong&gt;containers&lt;/strong&gt;. Think of a container like a &amp;ldquo;to-go” box for apps. You put all the ingredients inside, close the lid, and boom! It works the same wherever you take it—on your laptop, your data center, or even the cloud. No more “but it worked on my machine!” excuses (we&amp;rsquo;ve all been there). Now, here’s the extra-cool part: Unlike virtual machines (VMs), which are big, bulky, and carry an entire operating system with every app instance, Docker containers share the host OS. They’re lightweight, resource-friendly, and stupid fast. You could say Docker is like upgrading from a clunky wagon to a sleek sports car.&lt;/p&gt;
&lt;h2 id="why-do-developers-love-docker"&gt;&lt;strong&gt;Why Do Developers Love Docker?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Here’s the deal: Docker makes life way simpler. It’s packed with features that hit all the right developer feels. Let’s break it down:&lt;/p&gt;
&lt;h3 id="1-its-lightweight-like-really-lightweight"&gt;&lt;strong&gt;1. It’s Lightweight, Like REALLY Lightweight&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Imagine running multiple apps on one computer without it feeling like it’s gasping for air. Instead of bulky VMs, Docker containers are super slim because they piggyback off the host system’s OS. Think of a VM as an entire mansion for one app, but Docker? It’s like cool tiny homes that share utilities but still have their own kitchens. Efficient, right?&lt;/p&gt;
&lt;h3 id="2-speed-is-its-middle-name"&gt;&lt;strong&gt;2. Speed Is Its Middle Name&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Want faster development cycles? Done! Docker containers start up in literal milliseconds. Forget waiting around for a VM to boot (&amp;ldquo;Go grab coffee&amp;rdquo; fast). Docker’s more like a “Blink and it&amp;rsquo;s ready&amp;rdquo; vibe.&lt;/p&gt;
&lt;h3 id="3-it-works-everywhere-no-drama"&gt;&lt;strong&gt;3. It Works Everywhere (No Drama)&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Ever wasted hours debugging why your app works on dev but not prod? With Docker, what you build works EXACTLY the same wherever you take it. Linux, Windows, cloud, data centers—it’s all the same to Docker. No nasty surprises when moving your app from your laptop to a server.&lt;/p&gt;
&lt;h3 id="4-its-amazingly-efficient"&gt;&lt;strong&gt;4. It’s Amazingly Efficient&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Each container is tiny, using only the resources it needs—nothing more, nothing less. That means you can run a ton of containers on the same system without feeling like you’re playing Jenga with your server.&lt;/p&gt;
&lt;h3 id="5-scaling-is-a-breeze"&gt;&lt;strong&gt;5. Scaling Is a Breeze&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;If your app goes viral overnight (lucky you!), no worries. Scaling with Docker is as easy as spinning up a few more containers. Bonus: They’re already optimized to run super-smooth on minimal resources.&lt;/p&gt;
&lt;h2 id="docker-vs-virtual-machines-who-wins"&gt;&lt;strong&gt;Docker vs Virtual Machines: Who Wins?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Let’s get real: VMs aren’t bad. They’re great if you need the full OS-within-an-OS thing. But for most modern app development, Docker wipes the floor with VMs.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Docker&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Virtual Machines&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Startup Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Milliseconds!&lt;/td&gt;
&lt;td&gt;Minutes (go grab a snack)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Resource Usage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lightweight and shared OS&lt;/td&gt;
&lt;td&gt;Heavy. Every VM carries an OS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Portability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Works consistently EVERYWHERE&lt;/td&gt;
&lt;td&gt;Needs specific setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scalability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Piece of cake&lt;/td&gt;
&lt;td&gt;Lots of moving parts. More $$$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Isolation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strong enough for most cases&lt;/td&gt;
&lt;td&gt;Maximum (but overkill for many apps)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In short? Docker wins for modern apps, microservices, and cloud-native stuff. VMs are fine, but Docker’s just &lt;em&gt;better&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="the-secret-sauce-to-docker-best-practices"&gt;&lt;strong&gt;The Secret Sauce to Docker: Best Practices&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Docker’s fantastic out of the box, but if you want to go pro-level, let’s talk best practices. These handy tricks will help you avoid common mistakes and squeeze every bit of awesome out of Docker.&lt;/p&gt;
&lt;h3 id="image-optimization-keeping-it-tidy"&gt;&lt;strong&gt;Image Optimization: Keeping It Tidy&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Go Minimal&lt;/strong&gt;: Big images are bad. Use lightweight options like &lt;code&gt;alpine&lt;/code&gt; to save storage—trust me, your hard drive will thank you.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Multi-Stage Builds&lt;/strong&gt;: Reduce bloat by separating build and run steps, so the final container is lean and clean.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Clean Up After Yourself&lt;/strong&gt;: Combine steps to avoid extra Dockerfile layers. Basically, don’t hoard unnecessary stuff.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="performance-hacks-make-it-fly"&gt;&lt;strong&gt;Performance Hacks: Make It Fly&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set Resource Limits&lt;/strong&gt;: Stop containers from acting greedy with your CPU and memory. (Yes, you can tame them.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Get Smart with Layer Caching&lt;/strong&gt;: Order your &lt;code&gt;Dockerfile&lt;/code&gt; to maximize the caching magic and speed up builds.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Add Health Checks&lt;/strong&gt;: Docker can automatically check if your app is running properly. No more manual box-checking.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="security-tips-stay-safe-out-there"&gt;&lt;strong&gt;Security Tips: Stay Safe Out There&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Don’t Go All &amp;ldquo;Root&amp;rdquo;&lt;/strong&gt;: Running as root = bad idea. Create a specific user for your app instead.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stick to Trusted Images&lt;/strong&gt;: Use official or verified images from Docker Hub for peace of mind.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lock it Down&lt;/strong&gt;: Use restricted privileges and read-only flags whenever possible. Better safe than sorry!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="but-wait-theres-more-"&gt;**But Wait… There’s More **&lt;/h2&gt;
&lt;p&gt;Docker’s not just a one-trick pony. Once you master the basics, there are all these cool advanced features you can dive into:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use Docker Swarm or Kubernetes&lt;/strong&gt;: Running tons of containers? Tools like Swarm and Kubernetes let you orchestrate your containers so everything stays organized and smooth. It’s like being the conductor of your own app orchestra.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Routing Mesh&lt;/strong&gt;: No matter where your containers live, Docker ensures incoming requests find them. It’s basically traffic control for your app.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Shrink Images (Without Tears)&lt;/strong&gt;: Tools like &lt;code&gt;docker-slim&lt;/code&gt; trim all the unnecessary fat from your images. Think weight loss for software.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="real-life-cool-stuff-you-can-do-with-docker"&gt;&lt;strong&gt;Real-Life Cool Stuff You Can Do with Docker&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Docker’s powering everything from indie apps to enterprise giants. Here’s just a glimpse of how people are using it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Microservices&lt;/strong&gt;: Break big monolithic apps into smaller pieces. Develop, test, and deploy them in neat little chunks.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cloud Stuff&lt;/strong&gt;: Containers and the cloud go together like peanut butter and jelly. Developers love how portable and scalable Docker is.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CI/CD Pipelines&lt;/strong&gt;: Test and ship faster by rolling containers through build pipelines like a factory assembly line. Fun fact: This is why a lot of DevOps teams have Docker tattoos. Probably.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="wrapping-it-up-with-a-bow-"&gt;&lt;strong&gt;Wrapping It Up (With a Bow )&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Docker isn’t just software; it’s a movement—a better way of doing things. Whether you’re looking to clean up your dev workflow, scale your app like a pro, or just stop screaming “Why won’t this work!?” at your computer, Docker’s there for you. Start small, follow best practices, and before you know it, you’ll be deploying apps like a rockstar. Ready? Grab a coffee, install Docker, and dive into the world of containers. Your future self will thank you. More consistency. More speed. More fun. That&amp;rsquo;s Docker.&lt;/p&gt;
&lt;h2 id="key-takeaways"&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Docker containers package your app with all its dependencies, eliminating the &amp;ldquo;it works on my machine&amp;rdquo; problem by design.&lt;/li&gt;
&lt;li&gt;Containers are lightweight because they share the host OS kernel, unlike VMs that each carry a full OS — result is faster startup and more instances per server.&lt;/li&gt;
&lt;li&gt;Use alpine base images, multi-stage builds, and ordered Dockerfiles to keep image size down and build times fast.&lt;/li&gt;
&lt;li&gt;Never run containers as root, pin trusted base images, and use read-only flags where possible. Security starts at build time.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="next"&gt;Next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
— why your Docker installation method matters&lt;/li&gt;
&lt;li&gt;
— a real-world example of running containers with backup策略&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Comparing Docker.io and Snap Docker on Ubuntu</title><link>https://derekarmstrong.dev/blog/comparing-dockerio-and-snap-docker-on-ubuntu/</link><pubDate>Wed, 04 Sep 2024 00:00:00 +0000</pubDate><guid>https://derekarmstrong.dev/blog/comparing-dockerio-and-snap-docker-on-ubuntu/</guid><description>&lt;p&gt;Docker is a game-changer for developers and DevOps folks. It lets you package applications into containers, making them super portable and easy to manage. But when it comes to installing Docker on Ubuntu, you have a couple of options:
and snap docker. Let&amp;rsquo;s take a look at both to see what fits your needs and project!&lt;/p&gt;
&lt;h3 id="overview-of-dockerio-and-snap-docker-in-ubuntu"&gt;Overview of
and snap docker in Ubuntu&lt;/h3&gt;
&lt;p&gt;First up, we have
. This is the classic way of installing Docker using the APT package manager. You just run &lt;code&gt;sudo apt install&lt;/code&gt;
, and boom, Docker is ready to roll. It&amp;rsquo;s like ordering your favorite pizza and having it delivered right to your door.&lt;/p&gt;
&lt;p&gt;Then there&amp;rsquo;s &lt;strong&gt;snap docker&lt;/strong&gt;. Snap is a package management system that makes it easy to install and update software. You can get Docker via Snap by running &lt;code&gt;sudo snap install docker&lt;/code&gt;. It&amp;rsquo;s a more modern approach and has some cool features, but it also comes with a few quirks. Think of it as getting a gourmet pizza with some unique toppings – exciting, but maybe not for everyone.&lt;/p&gt;
&lt;h3 id="comparison-of-dockerio-and-snap-docker-in-terms-of-file-access-permissions"&gt;Comparison of
and snap docker in terms of file access permissions&lt;/h3&gt;
&lt;p&gt;Here&amp;rsquo;s where things get interesting. One of the key differences between
and snap docker is how they handle file access permissions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;
: This version of Docker has more traditional file access permissions. It can access files outside of your home directory if needed. This is handy for certain use cases where you need Docker to interact with system files or directories. Imagine having a master key that lets you into any room in the house.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;snap docker&lt;/strong&gt;: Snap packages are designed with security in mind, so they come with stricter confinement. Snap docker is limited to accessing files within the &lt;code&gt;$HOME&lt;/code&gt; directory. This means it can&amp;rsquo;t poke around in system directories, which can be a good thing for security but might be a limitation for some advanced use cases. Think of it as having a key that only lets you into your bedroom – safe, but a bit restrictive.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="implications-for-devops-and-security-professionals"&gt;Implications for DevOps and security professionals&lt;/h3&gt;
&lt;p&gt;For DevOps and security pros, the choice between
and snap docker can have significant implications.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;: Snap docker&amp;rsquo;s confinement model adds an extra layer of security by restricting file access. This can help prevent malicious containers from messing with your system files. If security is a top priority, snap docker might be the way to go. It&amp;rsquo;s like having a security guard at your door, making sure only the right people get in.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;: On the flip side,
offers more flexibility. If your workflows require Docker to access files outside the home directory,
is the better choice. It&amp;rsquo;s more aligned with traditional Docker setups and might be easier to integrate into existing systems. Think of it as having the freedom to roam around your entire house without restrictions.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="key-takeaways"&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker.io&lt;/code&gt; (APT) gives you unrestricted file access — necessary when containers need to interact with system directories or bind-mount outside your home folder.&lt;/li&gt;
&lt;li&gt;Snap Docker runs in a confined sandbox limited to &lt;code&gt;$HOME&lt;/code&gt;. Better security for isolated work, but a dealbreaker for workflows that need broader access.&lt;/li&gt;
&lt;li&gt;For most DevOps setups and CI/CD pipelines, &lt;code&gt;docker.io&lt;/code&gt; is the practical choice. Snap Docker fits personal or highly restricted environments.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="next"&gt;Next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
— why Docker matters for local development and infrastructure&lt;/li&gt;
&lt;li&gt;
— the production infrastructure using container management&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Redirecting Root Domain with Cloudflare</title><link>https://derekarmstrong.dev/blog/redirecting-root-domain-with-cloudflare/</link><pubDate>Wed, 28 Aug 2024 00:00:00 +0000</pubDate><guid>https://derekarmstrong.dev/blog/redirecting-root-domain-with-cloudflare/</guid><description>&lt;hr&gt;
&lt;p&gt;You know the old saying, &amp;ldquo;It’s always DNS&amp;rdquo;? Well, it&amp;rsquo;s true. And the more you dabble in the wonderful world of web management, the more you realize just how much your digital kingdom rests on those little DNS settings. Whether you’re managing a massive web empire or just tinkering with your personal site, knowing how to tame your network infrastructure is like having the keys to the castle. So let&amp;rsquo;s get into it and setup a redirect at the root level domain together!&lt;/p&gt;
&lt;h3 id="example-scenarios"&gt;Example Scenarios&lt;/h3&gt;
&lt;p&gt;Redirecting a root domain using Cloudflare is a common practice in various scenarios, especially when managing web traffic, branding, or SEO. Here are some scenarios where someone might need to do this:&lt;/p&gt;
&lt;h4 id="1-branding-and-consistency"&gt;1. Branding and Consistency&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Redirecting Non-www to www&lt;/strong&gt;: Because we all want to look sharp and consistent, right? You might want all traffic to go to
instead of
. This helps ensure that users always see the same version of your site, like having all your socks match—because mismatched URLs are just as bad as mismatched socks.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Redirecting www to Non-www&lt;/strong&gt;: Or maybe you’re a minimalist and prefer the sleek, no-frills
as your primary URL. In that case, you’ll be redirecting everything from
to
. Just like ditching that unnecessary &amp;ldquo;www&amp;rdquo; clutter.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-domain-consolidation"&gt;2. Domain Consolidation&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Merging Multiple Domains&lt;/strong&gt;: Got a handful of domains (e.g.,
,
)? It’s like trying to herd cats. Consolidate them by redirecting all traffic to a single domain (
), so everything points in the same direction. It’s domain feng shui.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Rebranding&lt;/strong&gt;: Changing your domain from
to
? Redirect the old root domain to the new one to keep all your loyal visitors (and your SEO rankings) in tow. Think of it like forwarding your mail after moving to a fancy new digital address.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-seo-and-duplicate-content"&gt;3. SEO and Duplicate Content&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Avoiding Duplicate Content&lt;/strong&gt;: Google frowns upon duplicate content like a librarian shushing a noisy visitor. To avoid penalties, you’ll want to redirect all traffic to a single canonical URL (e.g.,
redirects to
). Because let’s be honest, duplicate content is just unnecessary noise.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Maintaining SEO Rankings&lt;/strong&gt;: Migrating to a new domain? Redirect the old root domain to the new one, and watch as your hard-earned SEO rankings follow you to your shiny new home. It’s like changing the address on your business card but with way more techy jargon involved.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-traffic-management"&gt;4. Traffic Management&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Temporary Redirects During Maintenance&lt;/strong&gt;: Sometimes your website needs a little TLC. Set up a temporary redirect to a maintenance page (
) so your visitors know you haven’t vanished into the digital abyss.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Redirecting to a Regional or Language-Specific Site&lt;/strong&gt;: Got a global audience? Redirect users from the root domain to region-specific sites (
to
for U.S. visitors). It’s like rolling out the red carpet, tailored to each visitor.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="5-domain-migration"&gt;5. Domain Migration&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Moving to a New TLD&lt;/strong&gt;: Making the leap from &lt;code&gt;.com&lt;/code&gt; to &lt;code&gt;.dev&lt;/code&gt;? Redirect the old domain (
) to the new one (
), and keep everyone on the right track. Think of it as leaving breadcrumbs for your visitors to follow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Transition from a Development or Staging Environment&lt;/strong&gt;: Your site is graduating from staging (
) to production! Redirect the root domain to ensure all traffic flows to your up-to-date masterpiece.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="6-preventing-domain-squatting"&gt;6. Preventing Domain Squatting&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Protecting a Brand&lt;/strong&gt;: Own multiple variations of your domain to protect your brand? Redirect those variations to the main site to prevent confusion and keep domain squatters at bay. Because nobody likes a digital trespasser.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="7-simple-url-forwarding"&gt;7. Simple URL Forwarding&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Redirecting to a Social Media Profile&lt;/strong&gt;: Not quite ready for a full website? Redirect your root domain to a social media profile (
to
). It’s like handing out your business card, but online.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Redirecting to a Third-Party Service&lt;/strong&gt;: If your domain is just a gateway to another service (e.g., a blog hosted on Medium or a store on Shopify), redirect it there (
to
). Because who said you need to build everything from scratch?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="8-dealing-with-expired-services"&gt;8. Dealing with Expired Services&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Redirecting After Expiring or Discontinuing a Service&lt;/strong&gt;: If a service or site is no more, its root domain can be redirected to another service or a page explaining the change. It’s like leaving a &amp;ldquo;We’ve Moved&amp;rdquo; sign up for your digital neighbors.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="step-by-step-guide-to-redirect-a-root-domain-using-cloudflare"&gt;Step-by-Step Guide to Redirect a Root Domain Using Cloudflare&lt;/h3&gt;
&lt;p&gt;Alright, enough scenarios. Let’s get down to business and set up that redirect!&lt;/p&gt;
&lt;h4 id="1-log-in-to-cloudflare"&gt;1. Log in to Cloudflare&lt;/h4&gt;
&lt;p&gt;First things first, log in to your
.&lt;/p&gt;
&lt;h4 id="2-select-your-domain"&gt;2. Select Your Domain&lt;/h4&gt;
&lt;p&gt;From your list of domains, click on the one you want to redirect.&lt;/p&gt;
&lt;h4 id="3-set-up-dns-records"&gt;3. Set Up DNS Records&lt;/h4&gt;
&lt;p&gt;To make sure traffic to
flows smoothly through Cloudflare, set up these DNS records:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Root Domain A Record (&lt;/strong&gt;
):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: A&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Name&lt;/strong&gt;: &lt;code&gt;@&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;IPv4 Address&lt;/strong&gt;: &lt;code&gt;192.0.2.1&lt;/code&gt; (Just a placeholder, doesn&amp;rsquo;t actually matter)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;TTL&lt;/strong&gt;: Auto&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Proxy status&lt;/strong&gt;: Proxied (Orange Cloud)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;www&lt;/code&gt; Subdomain A Record (
):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: A&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Name&lt;/strong&gt;: &lt;code&gt;www&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;IPv4 Address&lt;/strong&gt;: Same as above (&lt;code&gt;192.0.2.1&lt;/code&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;TTL&lt;/strong&gt;: Auto&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Proxy status&lt;/strong&gt;: Proxied (Orange Cloud)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Pro Tip&lt;/strong&gt;: Prefer a CNAME? No problem. Use this instead:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CNAME Record for Root Domain&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt;: CNAME&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Name&lt;/strong&gt;: &lt;code&gt;@&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Target&lt;/strong&gt;:
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;TTL&lt;/strong&gt;: Auto&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Proxy status&lt;/strong&gt;: Proxied (Orange Cloud)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-create-a-page-rule-for-the-redirect"&gt;4. Create a Page Rule for the Redirect&lt;/h4&gt;
&lt;p&gt;Now for the fun part: setting up the Page Rule to actually do the redirecting.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In your domain’s dashboard, head over to &lt;strong&gt;Page Rules&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Create Page Rule&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;&amp;ldquo;If the URL matches&amp;rdquo;&lt;/strong&gt; field, enter
(This little wildcard &lt;code&gt;*&lt;/code&gt; will capture everything after the root domain).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under &lt;strong&gt;&amp;ldquo;Then the settings are&amp;rdquo;&lt;/strong&gt;, select &lt;strong&gt;Forwarding URL&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Choose your redirect type:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;301 - Permanent Redirect&lt;/strong&gt;: This is your &amp;ldquo;Forever&amp;rdquo; option.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;302 - Temporary Redirect&lt;/strong&gt;: Just temporary? Use this.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;&amp;ldquo;Enter destination URL&amp;rdquo;&lt;/strong&gt; field, type the URL you want to send folks to, like
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;$1&lt;/code&gt; is the bit that keeps all your existing links like &lt;code&gt;example.com/some/path&lt;/code&gt; working. In short it keeps your old paths intact.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Save and Deploy&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="5-test-the-redirect"&gt;5. Test the Redirect&lt;/h4&gt;
&lt;p&gt;Now’s the moment of truth. Go to
in your browser and make sure you land at
or wherever you’ve decided to send your traffic. If it works, give yourself a high-five—you’ve just mastered DNS redirection like a pro.&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;To redirect both
and example.com to newdomain.com, you need to create a separate page rule for each address.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="summary-example-configuration"&gt;Summary Example Configuration&lt;/h3&gt;
&lt;p&gt;Here’s a quick recap of what you’ve just done:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;DNS Settings&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A Record&lt;/strong&gt;: &lt;code&gt;@&lt;/code&gt; → &lt;code&gt;192.0.2.1&lt;/code&gt; (Proxied)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A Record&lt;/strong&gt;: &lt;code&gt;www&lt;/code&gt; → &lt;code&gt;192.0.2.1&lt;/code&gt; (Proxied)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Page Rule&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;URL Pattern&lt;/strong&gt;:
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Setting&lt;/strong&gt;: Forwarding URL →
(301 - Permanent Redirect)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Congrats! By following these steps, you’ve ensured that your root domain is successfully redirected using Cloudflare’s DNS and Page Rules features. Go forth and redirect with confidence—because when it comes to DNS, you’re now in the driver’s seat!&lt;/p&gt;
&lt;h2 id="key-takeaways"&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;You can redirect a root domain with Cloudflare using Page Rules (or DNS with a CNAME at the root, since root-level CNAMEs aren&amp;rsquo;t always supported)&lt;/li&gt;
&lt;li&gt;Set up an A record for &lt;code&gt;@&lt;/code&gt; pointing to a placeholder IP, enable proxy (orange cloud), then create a Page Rule to forward the URL to your target domain&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;$1&lt;/code&gt; placeholder in the forwarding URL preserves the original path—so &lt;code&gt;/about&lt;/code&gt; becomes &lt;code&gt;example.com/about&lt;/code&gt; instead of dropping to the root&lt;/li&gt;
&lt;li&gt;You need separate rules for each domain. If you&amp;rsquo;re redirecting &lt;code&gt;example.com&lt;/code&gt; and &lt;code&gt;www.example.com&lt;/code&gt; to the same place, create two rules with each source domain&lt;/li&gt;
&lt;li&gt;Cloudflare&amp;rsquo;s pricing determines rule counts: Free tier gets 3 Page Rules, Pro gets 20, Business gets unlimited&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="next"&gt;Next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
— another Cloudflare integration, this time for routing traffic through tunnels&lt;/li&gt;
&lt;li&gt;
— infrastructure that benefits from proper DNS and domain management&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>All-in-One Unraid HomeLab Server</title><link>https://derekarmstrong.dev/blog/all-in-one-unraid-homelab-server/</link><pubDate>Fri, 26 Jul 2024 00:00:00 +0000</pubDate><guid>https://derekarmstrong.dev/blog/all-in-one-unraid-homelab-server/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;I have tried a ton of different HomeLab configurations and setups of all types of hardware. But this one is my personally preferred solution for its versatility, reliability, and proven battle-tested track record. Built from gaming PC hardware, it&amp;rsquo;s an extremely powerful HomeLab that can fit many different needs and is highly customizable. Whether you&amp;rsquo;re a tech enthusiast, a developer, or someone looking to consolidate multiple functions into a single machine, this Unraid HomeLab server offers a robust and flexible solution.&lt;/p&gt;
&lt;p&gt;![](
align=&amp;ldquo;center&amp;rdquo;)&lt;/p&gt;
&lt;h2 id="hardware-specs"&gt;Hardware Specs&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Components&lt;/th&gt;
&lt;th&gt;Part Links&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Operating System (OS)&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Case&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fans&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Motherboard&lt;/td&gt;
&lt;td&gt;Gigabyte X470 AORUS ULTRA GAMING-CF&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PSU&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CPU&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CPU Cooler&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAM - 64 GB Total&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage NVMe - Docker and NAS writes&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage NVMe - Gaming VM&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage SSD - Lab VMs&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage HDD - NAS Array - 64 TB Total&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPU 1 - Gaming VM&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPU 2 - AI Models and Video Transcoding&lt;/td&gt;
&lt;td&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-features"&gt;Key Features&lt;/h2&gt;
&lt;h4 id="easy-setup-and-management"&gt;Easy Setup and Management&lt;/h4&gt;
&lt;p&gt;Unraid OS makes setting up and managing your server a breeze with its user-friendly web interface. Even if you&amp;rsquo;re not a tech wizard, you&amp;rsquo;ll find it easy to navigate and configure your server thanks to its intuitive design. From the moment you start the installation to your everyday tasks, the interface guides you step-by-step, taking the hassle out of server management.&lt;/p&gt;
&lt;p&gt;Everything you need, like setting up storage, creating virtual machines, and managing Docker containers, is right there in the web interface. No need to mess with complicated command lines. Plus, the dashboard gives you a real-time snapshot of your system&amp;rsquo;s performance, resource usage, and storage health, so you always know what&amp;rsquo;s going on.&lt;/p&gt;
&lt;h4 id="flexible-storage-options"&gt;Flexible Storage Options&lt;/h4&gt;
&lt;p&gt;Supports a mix of different drive sizes and types, allowing for easy expansion and customization. Not all drives have to be the same size. The parity drives just must be the largest ones. This really allows a huge amount of flexibility and a great place to use random old hard drives laying around if you can fit them. Saving costs and reducing electronic waste at the same time.&lt;/p&gt;
&lt;h4 id="data-protection"&gt;Data Protection&lt;/h4&gt;
&lt;p&gt;Provides robust data protection with parity-based redundancy, ensuring data integrity even if a drive fails. With multiple parity drives, you can have multiple disk failures at once. But even with a single parity drive, I have had multiple disks fail on me. Even when waiting on a warranty disk. The system will emulate the data from the failed drive until you are able to get a replacement drive reinstalled. I cannot stress how important this is and how much peace of mind you get when you know even if a drive fails, it&amp;rsquo;s no big deal and it will be perfectly fine. I have yet to lose any data due to disk failures 5+ years later.&lt;/p&gt;
&lt;h4 id="virtualization"&gt;Virtualization&lt;/h4&gt;
&lt;p&gt;Allows you to run multiple virtual machines (VMs) simultaneously, making it ideal for testing and development environments. The hypervisor capabilities are highly functional and work great for lab experimentations or a few production VMs. I have a gaming VM that performs amazingly with hardware pass-thru on the GPU and NVMe Storage too. For more complex VM clusters of servers, I would recommend Proxmox running on a Xeon CPU enterprise server as a much better solution. See my article on the Enterprise HomeLab Server Cluster and Rack I built.&lt;/p&gt;
&lt;h4 id="docker-support"&gt;Docker Support&lt;/h4&gt;
&lt;p&gt;Seamlessly integrates with Docker, enabling you to run a wide range of containerized applications.&lt;/p&gt;
&lt;h4 id="community-app-store"&gt;Community App Store&lt;/h4&gt;
&lt;p&gt;Although unofficial, this is a searchable template database for all sorts of applications that run using Docker containers. This makes deploying self-hosted services and even your own custom Docker-based applications a breeze. With a highly active and helpful community behind them, the App Store is what makes Unraid stand out with the simple ease of use and updates by the community.&lt;/p&gt;
&lt;h4 id="efficient-resource-utilization"&gt;Efficient Resource Utilization&lt;/h4&gt;
&lt;p&gt;Optimizes the use of hardware resources, ensuring efficient performance. Advanced capabilities such as CPU pinning are available for use with VMs and Docker from directly within the UI and are beyond simple to use. I have not seen a better implementation of this feature on any other hypervisor I have worked with.&lt;/p&gt;
&lt;h4 id="scalability"&gt;Scalability&lt;/h4&gt;
&lt;p&gt;Easily scalable to accommodate growing storage needs without requiring a complete system overhaul. Have a few extra hard drives laying around or need to upgrade an existing one? It is as simple as installing the new drives and doing some simple drop-down menu configuration via the GUI. I&amp;rsquo;ve never had an easier time working with storage arrays ever. It&amp;rsquo;s so easy it actually seems too easy.&lt;/p&gt;
&lt;h4 id="community-support"&gt;Community Support&lt;/h4&gt;
&lt;p&gt;Backed by a strong community of users and developers, providing extensive resources and support. The community is great to be a part of and everyone is always helpful. Never a bad experience.&lt;/p&gt;
&lt;h4 id="plugin-system"&gt;Plugin System&lt;/h4&gt;
&lt;p&gt;Offers a wide range of plugins to extend functionality, from media servers to backup solutions. The plugins are what make Unraid so awesome and sometimes they even get put into the OS itself.&lt;/p&gt;
&lt;h4 id="low-power-consumption"&gt;Low Power Consumption&lt;/h4&gt;
&lt;p&gt;Designed to be energy-efficient, reducing overall power consumption. It only uses the power it needs and will even spin down drives that are not in use after a certain amount of time which is configurable as well.&lt;/p&gt;
&lt;h4 id="hardware-compatibility"&gt;Hardware Compatibility&lt;/h4&gt;
&lt;p&gt;Compatible with a wide range of hardware, including consumer-grade components. I&amp;rsquo;ve never had a component or item not at least generally work right out of the box. Support is very broad for most hardware.&lt;/p&gt;
&lt;h4 id="data-recovery"&gt;Data Recovery&lt;/h4&gt;
&lt;p&gt;Features robust data recovery options, minimizing the risk of data loss. As well as having a highly resilient storage array system using parity disks to maintain data integrity even during a failure by failing over and emulating the data it cannot access at the time. It simply never skips a beat.&lt;/p&gt;
&lt;h4 id="network-attached-storage-nas"&gt;Network Attached Storage (NAS)&lt;/h4&gt;
&lt;p&gt;Functions as a powerful NAS, supporting NFS and SMB file shares.&lt;/p&gt;
&lt;h4 id="media-server-capabilities"&gt;Media Server Capabilities&lt;/h4&gt;
&lt;p&gt;Ideal for setting up media servers like Plex or Jellyfin, with hardware pass-thru for optimal performance. Including tools and software through the community App Store that can be used to automatically re-encode your media to save space as well.&lt;/p&gt;
&lt;h4 id="automated-backups"&gt;Automated Backups&lt;/h4&gt;
&lt;p&gt;Supports automated backups, ensuring your data is always protected. Via 3rd party plugins, it will back up your Docker volumes and container configurations automatically based on a schedule you create. As well as rotate and maintain the number of backups you want to keep.&lt;/p&gt;
&lt;h4 id="cost-effective"&gt;Cost-Effective&lt;/h4&gt;
&lt;p&gt;Allows the use of existing hardware, reducing the need for expensive enterprise solutions. You can build a very capable system out of an old PC or a few older PCs that you then combine together. The part mix and match is unbeatable and you can swap things around anytime you want with very little effort or reconfiguration if at all.&lt;/p&gt;
&lt;h4 id="customizable"&gt;Customizable&lt;/h4&gt;
&lt;p&gt;Highly customizable to fit specific needs and preferences. It&amp;rsquo;s your own playground. The broad part compatibility gives you almost unlimited amounts of different builds and configurations you can have.&lt;/p&gt;
&lt;h4 id="remote-access"&gt;Remote Access&lt;/h4&gt;
&lt;p&gt;Unraid provides options for remote access to the server GUI itself, making it easy to manage your server from anywhere. You can use Cloudflare Zero Trust tunnels to do this too since you will most likely have other services you will want to access remotely.&lt;/p&gt;
&lt;h4 id="security"&gt;Security&lt;/h4&gt;
&lt;p&gt;Includes various security features to protect your data and network. Please be sure to follow best standard security practices for any system you put your personal data onto.&lt;/p&gt;
&lt;h4 id="performance-monitoring"&gt;Performance Monitoring&lt;/h4&gt;
&lt;p&gt;Offers tools for monitoring system performance and resource usage. 3rd party plugins are available to help you monitor your GPU&amp;rsquo;s and hardware thermals as well.&lt;/p&gt;
&lt;h4 id="multi-user-support"&gt;Multi-User Support&lt;/h4&gt;
&lt;p&gt;Allows multiple users to access and use the system simultaneously.&lt;/p&gt;
&lt;h4 id="file-sharing"&gt;File Sharing&lt;/h4&gt;
&lt;p&gt;Simplifies file sharing across different devices and platforms. Managing user access to SMB or NFS shares is extremely easy and simple to set up all through the GUI.&lt;/p&gt;
&lt;h4 id="backup-solutions"&gt;Backup Solutions&lt;/h4&gt;
&lt;p&gt;Integrates with various backup solutions to ensure data safety. There are many ways to sync your OneDrive, Google, or iCloud storage as well as host your own private cloud storage solutions.&lt;/p&gt;
&lt;h4 id="software-updates"&gt;Software Updates&lt;/h4&gt;
&lt;p&gt;Regular updates and patches to keep the system secure and up-to-date.&lt;/p&gt;
&lt;h2 id="usage-and-ideas"&gt;Usage and Ideas&lt;/h2&gt;
&lt;h3 id="gaming-vm"&gt;Gaming VM&lt;/h3&gt;
&lt;p&gt;Unraid&amp;rsquo;s virtualization capabilities allow you to run a high-performance gaming VM. With hardware pass-thru for the GPU and NVMe storage, you can achieve near-native gaming performance. This setup is ideal for those who want to consolidate their gaming and server needs into a single machine.&lt;/p&gt;
&lt;h3 id="labs"&gt;Labs&lt;/h3&gt;
&lt;p&gt;Unraid is perfect for setting up lab environments for testing and development. Its support for multiple VMs and Docker containers makes it easy to create isolated environments for different projects. Whether you&amp;rsquo;re experimenting with new software, testing configurations, or developing applications, Unraid provides a flexible and powerful platform.&lt;/p&gt;
&lt;h3 id="storage-and-backups"&gt;Storage and Backups&lt;/h3&gt;
&lt;p&gt;Unraid excels in providing robust storage solutions. With its flexible storage options, you can mix and match different drive sizes and types. The system&amp;rsquo;s parity-based redundancy ensures data integrity, even if a drive fails. Automated backups and data recovery options further enhance the reliability of your storage setup.&lt;/p&gt;
&lt;h3 id="media-server"&gt;Media Server&lt;/h3&gt;
&lt;p&gt;Unraid is an excellent choice for setting up a media server. With support for applications like Plex and Jellyfin, you can easily stream your media collection to various devices. Hardware pass-thru ensures optimal performance, and the community App Store offers tools to automatically re-encode media to save space.&lt;/p&gt;
&lt;h2 id="personal-experiences"&gt;Personal Experiences&lt;/h2&gt;
&lt;p&gt;This build and setup not only is used by my entire family and extended family 24/7 for its media server, self-hosted AI Chatbots, and data backup capabilities. It really is production and in use by many people at all times. It also runs critical services like my Unifi network controller for all of my networking equipment. And non-critical services and VMs for all of my development and lab environments. Even a Gaming VM for when I want to relax a little between projects. And some would say, including myself before. Are you crazy!? That&amp;rsquo;s a single point of failure! It is but I can say after many years of using and maintaining this system. And trying many more others including more distributed setups. It is by far the most reliable and stable that I have ever built. Even after hardware failures and many different configurations I have gone through. It&amp;rsquo;s rock solid. It&amp;rsquo;s friendly and approachable by tech enthusiasts for general-purpose needs and beyond customizable for the hardcore tinkers and developers. Give it a try and if you want to share your own setup or story please leave a comment!&lt;/p&gt;
&lt;h2 id="key-takeaways"&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Unraid&amp;rsquo;s parity-based storage lets you mix drive sizes and survive drive failures without data loss — a practical advantage over traditional RAID.&lt;/li&gt;
&lt;li&gt;The community app store turns Docker deployment into a template-based process, removing the manual configuration overhead.&lt;/li&gt;
&lt;li&gt;For a single-server homelab that handles VMs, Docker, storage, and media in one box, Unraid hits the sweet spot between ease of use and capability.&lt;/li&gt;
&lt;li&gt;If you need a large VM cluster, Proxmox on enterprise hardware is a better fit. Unraid excels at the all-in-one solo build.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="useful-resources"&gt;Useful Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some links are affiliate links that help support me to create this content.&lt;/p&gt;
&lt;h2 id="next"&gt;Next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
— how AI infrastructure layers on top of this homelab&lt;/li&gt;
&lt;li&gt;
— manage access to your infrastructure without typing full hostnames every time&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Streamlining SSH Connections: A Quick Guide</title><link>https://derekarmstrong.dev/blog/streamlining-ssh-connections-a-quick-guide/</link><pubDate>Sat, 08 Apr 2023 00:00:00 +0000</pubDate><guid>https://derekarmstrong.dev/blog/streamlining-ssh-connections-a-quick-guide/</guid><description>&lt;hr&gt;
&lt;p&gt;Maximizing efficiency in our daily tasks is a shared goal among developers. When it comes to SSH connections, wouldn&amp;rsquo;t it be great to reduce this&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ssh&lt;/code&gt;
&lt;code&gt;-i /path/to/your/keyfile&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;hellip;to simply this?&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ssh Server1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Today, I&amp;rsquo;m sharing a quick guide on how to set default values for host, user, and key file in your SSH connections.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt; You can use these in VSCode or your favorite JetBrains IDE too!&lt;/p&gt;
&lt;h2 id="configuring-the-ssh-config-file"&gt;Configuring the SSH Config File&lt;/h2&gt;
&lt;p&gt;The default path to the SSH config file is &lt;code&gt;~/.ssh/config&lt;/code&gt;. Let&amp;rsquo;s explore how to set it up:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Set Default User for All Hosts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Host *
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; User your_user
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Set Default User, HostName, and Key File&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# You don&amp;#39;t have to use a keyfile aka SSH Key, just comment it out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Host name-to-use &lt;span class="c1"&gt;# Name you want to use - ssh Host&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; HostName 10.10.10.10 &lt;span class="c1"&gt;# The IP address or FQDN of the destination server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# HostName servername.domain.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; IdentityFile /path/to/your/key/KeyFile.pem &lt;span class="c1"&gt;# Key File&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; User your_user &lt;span class="c1"&gt;# Default User&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By implementing these configurations, you can make your SSH connections more efficient and easier to manage. This approach is especially useful when you&amp;rsquo;re frequently connecting to the same servers or clusters.&lt;/p&gt;
&lt;p&gt;Remember, efficiency is key in any development environment. I hope this guide proves useful in your daily tasks. Do you have more tips to streamline SSH connections? Feel free to share in the comments!&lt;/p&gt;
&lt;h2 id="key-takeaways"&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;An SSH config file at &lt;code&gt;~/.ssh/config&lt;/code&gt; lets you define aliases, default users, and key paths so you can connect with &lt;code&gt;ssh Server1&lt;/code&gt; instead of typing full hostnames and key paths every time&lt;/li&gt;
&lt;li&gt;Setting a wildcard &lt;code&gt;Host *&lt;/code&gt; block establishes defaults for all connections, reducing repetition when you frequently use the same user or key&lt;/li&gt;
&lt;li&gt;The config works with VSCode Remote-SSH and JetBrains IDEs — whatever tool you use to connect, it reads the same config file&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="next"&gt;Next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
— SSH config is useful; combined with Docker remote hosts, your workflow compresses even further&lt;/li&gt;
&lt;li&gt;
— the infrastructure you&amp;rsquo;ll need to SSH into&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Setting up Cloud Init Ubuntu Image on Proxmox</title><link>https://derekarmstrong.dev/blog/setting-up-cloud-init-ubuntu-image-on-proxmox/</link><pubDate>Sat, 15 Oct 2022 00:00:00 +0000</pubDate><guid>https://derekarmstrong.dev/blog/setting-up-cloud-init-ubuntu-image-on-proxmox/</guid><description>&lt;p&gt;This post shows a compact, repeatable flow for creating a Cloud-Init based Ubuntu template in Proxmox so you can spin up configured VMs quickly.&lt;/p&gt;
&lt;p&gt;Quick run: download an Ubuntu cloud image, import it into Proxmox, add a Cloud-Init drive, set boot order, convert to a template, then clone.&lt;/p&gt;
&lt;p&gt;You will need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A Proxmox VE host with LVM (or other writable storage like &lt;code&gt;local-lvm&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;SSH or shell access to your Proxmox host&lt;/li&gt;
&lt;li&gt;A public SSH key (for injecting into cloud-init)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="quick-checklist"&gt;Quick checklist&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Download cloud image&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Create a small VM (temporary)&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Import disk, attach to VM&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Add cloud-init drive and configure user/ssh&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Convert VM to template&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Clone when needed&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="step-by-step"&gt;Step-by-step&lt;/h2&gt;
&lt;h3 id="1-download-the-ubuntu-cloud-image"&gt;1) Download the Ubuntu cloud image&lt;/h3&gt;
&lt;p&gt;Choose the release you prefer and download the cloud image. Example (Focal):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-create-a-temporary-vm-to-attach-the-image-to"&gt;2) Create a temporary VM to attach the image to&lt;/h3&gt;
&lt;p&gt;Adjust memory and CPU to taste — this VM will become the template.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qm create &lt;span class="m"&gt;8000&lt;/span&gt; --memory &lt;span class="m"&gt;2048&lt;/span&gt; --core &lt;span class="m"&gt;2&lt;/span&gt; --name ubuntu-cloud --net0 virtio,bridge&lt;span class="o"&gt;=&lt;/span&gt;vmbr0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-import-the-cloud-image-into-storage"&gt;3) Import the cloud image into storage&lt;/h3&gt;
&lt;p&gt;Import the downloaded image into a Proxmox storage pool (example uses &lt;code&gt;local-lvm&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qm importdisk &lt;span class="m"&gt;8000&lt;/span&gt; focal-server-cloudimg-amd64.img local-lvm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="4-attach-the-imported-disk-to-the-vm-scsi-recommended"&gt;4) Attach the imported disk to the VM (SCSI recommended)&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qm &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt; --scsihw virtio-scsi-pci --scsi0 local-lvm:vm-8000-disk-0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="5-add-the-cloud-init-drive"&gt;5) Add the Cloud-Init drive&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qm &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt; --ide2 local-lvm:cloudinit
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="6-make-the-vm-boot-from-the-disk"&gt;6) Make the VM boot from the disk&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qm &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt; --boot c --bootdisk scsi0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="7-add-a-serial-console-optional-helpful-for-headless-debugging"&gt;7) Add a serial console (optional, helpful for headless debugging)&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qm &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt; --serial0 socket --vga serial0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="callout flex px-4 py-3 mb-6 rounded-md border-l-4 bg-orange-100 dark:bg-orange-900 border-orange-500"
data-callout="warning"
data-callout-metadata=""&gt;
&lt;span class="callout-icon pr-3 pt-1 text-orange-600 dark:text-orange-300"&gt;
&lt;svg height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0zM12 15.75h.007v.008H12z"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;div class="callout-content dark:text-neutral-300"&gt;
&lt;div class="callout-title font-semibold mb-1"&gt;Don&amp;rsquo;t Start Yet&lt;br&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;&lt;p&gt;&lt;strong&gt;Warning — do not start the VM yet.&lt;/strong&gt; Configure cloud-init and hardware first. Starting too early can record IDs/state you may not want in your template.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="8-configure-cloud-init-fields-hostname-user-ssh-key"&gt;8) Configure Cloud-Init fields (hostname, user, SSH key)&lt;/h3&gt;
&lt;p&gt;You can set these with the GUI or via &lt;code&gt;qm set&lt;/code&gt;. Example CLI:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qm &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt; --ciuser ubuntu --sshkey &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;cat ~/.ssh/id_rsa.pub&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qm &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt; --citype nocloud
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you want to provide a full &lt;code&gt;user-data&lt;/code&gt;/&lt;code&gt;meta-data&lt;/code&gt; payload for NoCloud, you can supply files or use Proxmox GUI fields.&lt;/p&gt;
&lt;h3 id="9-convert-the-vm-to-a-template"&gt;9) Convert the VM to a template&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qm template &lt;span class="m"&gt;8000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="10-clone-the-template-whenever-you-need-a-new-vm"&gt;10) Clone the template whenever you need a new VM&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qm clone &lt;span class="m"&gt;8000&lt;/span&gt; &lt;span class="m"&gt;135&lt;/span&gt; --name yoshi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="tips"&gt;Tips&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Resize disks after cloning if you need per-VM different sizes; keep the template small.&lt;/li&gt;
&lt;li&gt;Put idempotent provisioning (Ansible, cloud-init modules) in the guest rather than baking many steps into the template.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting&lt;/h2&gt;
&lt;p&gt;If you accidentally booted a template (or need a fresh machine-id inside a guest):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo rm -f /etc/machine-id
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo rm -f /var/lib/dbus/machine-id
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Shutdown the VM and do not boot it; a new id will be generated on next boot. If it&amp;rsquo;s not generated automatically, run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemd-machine-id-setup
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If cloud-init doesn&amp;rsquo;t apply after cloning, verify the cloud-init datasource type and that Proxmox&amp;rsquo;s cloud-init fields are populated correctly for the new host.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="key-takeaways"&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Cloud-init templates save hours per VM when you deploy regularly&lt;/li&gt;
&lt;li&gt;Never start a VM before configuring cloud-init — booting early bakes state into the template&lt;/li&gt;
&lt;li&gt;Keep the template minimal; use idempotent provisioning (Ansible, cloud-init modules) for post-clone customization&lt;/li&gt;
&lt;li&gt;Always use SCSI for the imported disk for performance&lt;/li&gt;
&lt;li&gt;Reset machine-id after cloning if cloud-init doesn&amp;rsquo;t apply correctly&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="next"&gt;Next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
— tools and scripts for VM management, backups, and automation on Proxmox&lt;/li&gt;
&lt;li&gt;
— managing credentials homelab automation without scattered secrets&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Maximizing Efficiency in IT: Simplifying Software and Infrastructure Development</title><link>https://derekarmstrong.dev/blog/maximizing-efficiency-in-it-simplifying-software-and-infrastructure-development/</link><pubDate>Sat, 09 Apr 2022 00:00:00 +0000</pubDate><guid>https://derekarmstrong.dev/blog/maximizing-efficiency-in-it-simplifying-software-and-infrastructure-development/</guid><description>&lt;p&gt;In my years of crafting software, networks, and infrastructure, I&amp;rsquo;ve learned a key lesson: more features don&amp;rsquo;t always mean better functionality. Often, loading a system with too many extras leads to more problems than solutions. A system crammed with features can become a maze, where finding the cause of a problem is like searching for a needle in a haystack. This overcomplexity turns maintenance into a nightmare task, like trying to navigate a thick forest without a compass. If you ever have experienced this, you know the importance of simplicity and area focus in system design.&lt;/p&gt;
&lt;h2 id="-the-farm-a-lesson-in-digital-simplicity"&gt;** The Farm: A Lesson in Digital Simplicity**&lt;/h2&gt;
&lt;p&gt;Envision your IT infrastructure as a lively, diverse farm. Each device is akin to a different animal, each with its unique requirements. As the farmer in this technology landscape, your tasks are multifaceted: nurturing your digital livestock, managing expenses efficiently, ensuring smooth functionality, and protecting against cyber threats. This metaphor highlights the day to day life of upholding a solid and secure IT environment. I often reflect on a saying: &amp;ldquo;It&amp;rsquo;s hard to see the forest when you&amp;rsquo;re amongst the trees.&amp;rdquo; This is a valuable reminder in our context. Rather than fixating on adding tons of features into a single project, it&amp;rsquo;s crucial to step back and embrace simplicity. It&amp;rsquo;s ok to focus in problem branches of a single tree but always remember to look at the forest and don&amp;rsquo;t get lost in the trees.&lt;/p&gt;
&lt;p&gt;![](
align=&amp;ldquo;center&amp;rdquo;)&lt;/p&gt;
&lt;h2 id="case-study-betsy-the-prized-product"&gt;&lt;strong&gt;Case Study: Betsy, the Prized Product&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Meet Betsy, the star and latest addition to our IT farm. She&amp;rsquo;s your crown jewel, be it a sleek software, a robust server, a seamless network, or a well-oiled DevOps pipeline. You&amp;rsquo;ve invested blood, sweat, and maybe a few tears into perfecting Betsy. Now, it&amp;rsquo;s all about keeping her producing and pleasing everyone. Sure, you&amp;rsquo;re tempted to deck her out with the latest features and fix every tiny bug, all while keeping a keen eye on her performance. But beware - every new bell adds a new layer of complexity. Resulting in even more monitors and alerts that turn a small problem into a high-tech hide and seek. Save yourself some stress and time. Stick to essential enhancements and simplicity, where less could actually mean more. Remember Betsy above. Does she really need all of those bells to provide an awesome product?&lt;/p&gt;
&lt;h2 id="managing-your-it-farm-a-balanced-approach"&gt;&lt;strong&gt;Managing Your IT Farm: A Balanced Approach&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Imagine your IT infrastructure as a complex farm, where each component is a unique animal with specific needs. As the caretaker in this digital ecosystem, your role is to ensure every element is well-maintained and secure from potential threats, much like a farmer tending to diverse livestock. In the current landscape of rapidly evolving cloud-based solutions, choosing which tools and services are essential and which are superfluous can be challenging. It&amp;rsquo;s about striking a balance between enriching your infrastructure and being selective with the resources at your disposal, ensuring a stable and efficient operational environment. It&amp;rsquo;s a lot of work! Don&amp;rsquo;t make it harder on yourself with extra work that is not truly needed.&lt;/p&gt;
&lt;h2 id="adopting-the-8020-rule-and-yagni"&gt;Adopting the 80/20 Rule and YAGNI&lt;/h2&gt;
&lt;p&gt;Regardless of your project&amp;rsquo;s stage, be it greenfield (starting from scratch) or brownfield (upgrading existing systems), two guiding principles can streamline your approach: the 80/20 rule and &amp;ldquo;YAGNI&amp;rdquo; (You Ain&amp;rsquo;t Gonna Need It). The 80/20 rule suggests concentrating on the vital 20% of tasks that deliver 80% of the results. Simultaneously, the YAGNI principle advocates for a minimalistic initial design, adding features only when they become necessary. This strategy enables quicker progression to the iteration phase, letting you make adjustments informed by practical feedback. Imagine trying to design and build your whole farm before you even know what problems you will face. What if no one even likes cows at all and they wanted chickens instead! O Geez! Now you have a whole system and area of your farm dedicated to something no one needs or wants. But no matter how much you plan and research, sometimes this does happen.&lt;/p&gt;
&lt;h2 id="adapting-to-the-unpredictable"&gt;Adapting to the Unpredictable&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s crucial to remember that you don&amp;rsquo;t know what you don&amp;rsquo;t know - there&amp;rsquo;s always going to be something unexpected that comes up. Being able to adapt your solution and make tweaks based on these unexpected challenges is key. And if the system simply doesn&amp;rsquo;t work, it&amp;rsquo;s even better that you didn&amp;rsquo;t waste more time on that solution! Don&amp;rsquo;t feel defeated though. Failure can be disguised as clarity to the solution and actually progress instead of a set back. Even a step back can be 2 steps forward if you pay attention to your footing.&lt;/p&gt;
&lt;h2 id="the-virtue-of-simplicity"&gt;&lt;strong&gt;The Virtue of Simplicity&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Remember, you don&amp;rsquo;t need to use every feature or monitoring alarm. Overloading a design with features complicates maintenance and troubleshooting. Simplicity and efficiency often outperform complexity and over-engineering. Finally, managing costs and efficiently utilizing resources is key in building software, networks and infrastructure. Stay open to iteration and adaptation, and you&amp;rsquo;ll be well on your way to building robust, efficient, and manageable systems.&lt;/p&gt;
&lt;h3 id="-top-5-tips-for-streamlining-your-it-projects"&gt;** Top 5 Tips for Streamlining Your IT Projects**&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;** MVP First**: Start with a Minimal Viable Product. Focus on core features that meet basic needs, then expand later.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;** Regular Reviews**: Periodically evaluate your systems. Simplify or remove unnecessary components.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cost Efficiency &amp;amp; Resource Management&lt;/strong&gt;: Prioritize efficient cost control and smart resource utilization.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;80/20 Rule &amp;amp; YAGNI&lt;/strong&gt;: Focus on the essential 20% of features that meet 80% of needs, and embrace &amp;ldquo;YAGNI&amp;rdquo; (You Ain&amp;rsquo;t Gonna Need It) to avoid unnecessary complexities.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;** Feedback and Adaptation**: Regularly seek and act on feedback. Stay agile and ready to make changes for continuous improvement.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="key-takeaways"&gt;Key Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Complexity is a maintenance burden — the simpler the system, the easier it is to fix when things break&lt;/li&gt;
&lt;li&gt;Ship an MVP, get real feedback, then iterate; planning every detail up front wastes time on features nobody needs&lt;/li&gt;
&lt;li&gt;The 80/20 rule and YAGNI are discipline, not buzzwords: focus on the 20% of features that deliver 80% of value, and skip what you don&amp;rsquo;t need yet&lt;/li&gt;
&lt;li&gt;Costs and resources compound with every added component — monitoring, alerting, and operational overhead grow with feature count&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="next"&gt;Next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
— applies the same prioritization thinking to productivity and life decisions&lt;/li&gt;
&lt;li&gt;
— another practical approach to keeping things simple and focused&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>