<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: 12ww1160</title>
    <description>The latest articles on Forem by 12ww1160 (@12ww1160).</description>
    <link>https://forem.com/12ww1160</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3668992%2F6029d290-e22d-4744-85cd-6a9d8bbbed92.jpeg</url>
      <title>Forem: 12ww1160</title>
      <link>https://forem.com/12ww1160</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/12ww1160"/>
    <language>en</language>
    <item>
      <title>ConfDroid Puppet Modules - Selinux</title>
      <dc:creator>12ww1160</dc:creator>
      <pubDate>Sat, 11 Apr 2026 10:04:51 +0000</pubDate>
      <link>https://forem.com/12ww1160/confdroid-puppet-modules-selinux-4im3</link>
      <guid>https://forem.com/12ww1160/confdroid-puppet-modules-selinux-4im3</guid>
      <description>&lt;h2&gt;
  
  
  Introducing confdroid_selinux: Declarative SELinux Management for Your Rocky 9 Servers
&lt;/h2&gt;

&lt;p&gt;Security-Enhanced Linux (SELinux) is one of the most powerful built-in defenses on modern Linux systems. Unlike traditional permission-based security (user/group/other), SELinux adds &lt;strong&gt;mandatory access control (MAC)&lt;/strong&gt; at the kernel level. It labels every process, file, directory, and network port with a security context and enforces strict policies that say exactly what each subject is allowed to do with each object — no matter what the file permissions say.&lt;/p&gt;

&lt;p&gt;This means even if an attacker gains root or tricks a service into writing a malicious file, SELinux can still block the attack because the file simply doesn’t have the right context.&lt;br&gt;
Many enterprise Linux distributions enable SELinux &lt;strong&gt;by default&lt;/strong&gt; in enforcing mode on fresh installs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rocky Linux 9&lt;/li&gt;
&lt;li&gt;AlmaLinux 9&lt;/li&gt;
&lt;li&gt;Red Hat Enterprise Linux (RHEL) 9&lt;/li&gt;
&lt;li&gt;Fedora&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On these systems, SELinux is not an afterthought — it’s a core part of the security model.&lt;/p&gt;

&lt;h2&gt;
  
  
  How SELinux Stops Real-World Attacks
&lt;/h2&gt;

&lt;p&gt;Imagine an attacker sends a phishing email with a malicious script disguised as a legitimate configuration file. The user (or a compromised service) downloads and places the file in &lt;code&gt;/tmp&lt;/code&gt; or a web directory.&lt;/p&gt;

&lt;p&gt;Without SELinux:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the file has execute permissions, the attacker might be able to run it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With SELinux (enforcing mode):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The file gets created with the wrong security context (for example, &lt;code&gt;user_tmp_t&lt;/code&gt; instead of &lt;code&gt;httpd_exec_t&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Even if the attacker somehow makes the file executable, SELinux denies execution or access because the policy doesn’t allow it.&lt;/li&gt;
&lt;li&gt;The attack is stopped cold, and an audit log entry is generated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SELinux turns potential disasters into harmless denied operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Manual SELinux Management
&lt;/h2&gt;

&lt;p&gt;While SELinux is powerful, managing it consistently across many servers is painful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Forgetting to run &lt;code&gt;restorecon&lt;/code&gt; after placing files&lt;/li&gt;
&lt;li&gt;Accidentally setting the wrong mode (setenforce)&lt;/li&gt;
&lt;li&gt;Configuration drift between hosts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s exactly why I built &lt;strong&gt;confdroid_selinux&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What confdroid_selinux Does
&lt;/h2&gt;

&lt;p&gt;This new Puppet 8 module (tested on Rocky 9) gives you full declarative control over SELinux:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installs all required SELinux tools and binaries&lt;/li&gt;
&lt;li&gt;Manages the main configuration file &lt;code&gt;/etc/sysconfig/selinux&lt;/code&gt; with correct permissions and SELinux contexts&lt;/li&gt;
&lt;li&gt;Controls the global SELinux mode (enforcing or permissive) — the Puppet equivalent of setenforce&lt;/li&gt;
&lt;li&gt;Ensures every file and directory managed by other Confdroid modules receives the proper SELinux context&lt;/li&gt;
&lt;li&gt;Works cleanly on enforcing-mode systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All other Confdroid modules (see the &lt;a href="https://sourcecode.confdroid.com/confdroid/puppet_collection" rel="noopener noreferrer"&gt;full collection overview&lt;/a&gt;) already include proper SELinux context handling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://sourcecode.confdroid.com/confdroid/confdroid_apache" rel="noopener noreferrer"&gt;confdroid_apache&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://sourcecode.confdroid.com/confdroid/confdroid_gitea" rel="noopener noreferrer"&gt;confdroid_gitea&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://sourcecode.confdroid.com/confdroid/confdroid_php" rel="noopener noreferrer"&gt;confdroid_php&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://sourcecode.confdroid.com/confdroid/confdroid_php" rel="noopener noreferrer"&gt;confdroid_fail2ban&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://sourcecode.confdroid.com/confdroid/confdroid_automatic" rel="noopener noreferrer"&gt;confdroid_automatic&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://sourcecode.confdroid.com/confdroid/confdroid_nrpe" rel="noopener noreferrer"&gt;confdroid_nrpe&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://sourcecode.confdroid.com/confdroid/confdroid_nagios" rel="noopener noreferrer"&gt;confdroid_nagios&lt;/a&gt;,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and many more.&lt;/p&gt;

&lt;p&gt;They work even better when &lt;code&gt;**confdroid_selinux**&lt;/code&gt; is present, because the global policy and mode are managed in one place.&lt;/p&gt;

&lt;h2&gt;
  
  
  SELinux Management Flow with the Module
&lt;/h2&gt;

&lt;p&gt;Here’s how the module turns your Puppet run into reliable SELinux enforcement:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F20z827cy5qyeoyp8iecz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F20z827cy5qyeoyp8iecz.png" alt="Mermaid diagram" width="542" height="1166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Easy Deployment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simple inclusion&lt;/strong&gt;:
in your site.pp or nodes.pp:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight puppet"&gt;&lt;code&gt;&lt;span class="k"&gt;include&lt;/span&gt; &lt;span class="nc"&gt;confdroid_selinux&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;with Foreman (recommended)&lt;/strong&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add the &lt;code&gt;confdroid_selinux::params&lt;/code&gt; class to the host or host group and override parameters (mode, etc.) as smart class parameters.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Important notes:&lt;br&gt;
Test in a non-production environment first.&lt;br&gt;
If you are switching from disabled to enforcing mode, a reboot is required (the module does not reboot automatically to avoid surprises).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can find the full module, source code, and parameter reference here:&lt;br&gt;
&lt;a href="https://sourcecode.confdroid.com/confdroid/confdroid_selinux" rel="noopener noreferrer"&gt;→&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;SELinux is no longer optional on modern enterprise Linux. With &lt;code&gt;confdroid_selinux&lt;/code&gt;, you get consistent, version-controlled, and fully automated SELinux management that works hand-in-hand with the rest of the Confdroid collection.&lt;br&gt;
Your servers stay secure by default — even when things go wrong elsewhere.&lt;br&gt;
Have you been running SELinux in enforcing mode across your fleet, or are you still in permissive because of management headaches? Would you like to see more advanced features (custom Booleans, custom modules, etc.) in a future version? Let me know in the comments!&lt;/p&gt;




&lt;p&gt;Did you find this post helpful?  You can support me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/grizzly_coda" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2znn4km0i2jib7ru1sm9.png" alt="" width="170" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hetzner.cloud/?ref=EY14C8Tema9j" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyab43i0ysz9uwuq267u0.png" alt="Hetzner Referral" width="400" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://confdroid.substack.com/subscribe?params=%5Bobject%20Object%5D" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r49xyl05rwkjb52xbqg.png" alt="Substack" width="250" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://feedback.confdroid.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7d47hck6vziak35nfgf.png" alt="ConfDroid Feedback Portal" width="300" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-pilot/" rel="noopener noreferrer"&gt;Confdroid Puppet Modules - Pilot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-puppet/" rel="noopener noreferrer"&gt;Confdroid Puppet Modules - Puppet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-resources/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - confdroid_resources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-postgresql/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Postgresql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-gitea/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Gitea&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-apache/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Apache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-nagios/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Nagios&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-nrpe/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - NRPE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-fail2ban/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Fail2ban&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-automatic/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Automatic&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>selinux</category>
      <category>security</category>
      <category>puppet</category>
      <category>foreman</category>
    </item>
    <item>
      <title>ConfDroid Puppet Modules - Automatic</title>
      <dc:creator>12ww1160</dc:creator>
      <pubDate>Tue, 07 Apr 2026 10:59:02 +0000</pubDate>
      <link>https://forem.com/12ww1160/confdroid-puppet-modules-automatic-537d</link>
      <guid>https://forem.com/12ww1160/confdroid-puppet-modules-automatic-537d</guid>
      <description>&lt;h2&gt;
  
  
  Introducing confdroid_automatic: Hands-Off OS Updates for Your Rocky 9 Servers
&lt;/h2&gt;

&lt;p&gt;Keeping operating systems patched is one of the most important — yet often neglected — parts of server maintenance. Security updates arrive regularly, and manually applying them across dozens or hundreds of machines quickly becomes a burden and a source of risk.&lt;/p&gt;

&lt;p&gt;That’s why I’m happy to release &lt;a href="https://sourcecode.confdroid.com/confdroid/confdroid_automatic" rel="noopener noreferrer"&gt;&lt;strong&gt;confdroid_automatic&lt;/strong&gt;&lt;/a&gt;, the latest addition to the Confdroid Puppet collection.&lt;/p&gt;

&lt;p&gt;This module brings reliable, automated OS updates to Rocky 9 (and other RHEL 9-based) systems by managing &lt;code&gt;dnf-automatic&lt;/code&gt; declaratively with Puppet 8. It installs the necessary packages, configures update behavior, applies correct SELinux contexts, and ensures the systemd timer runs as expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Automated Updates Matter
&lt;/h2&gt;

&lt;p&gt;Security patches close vulnerabilities before attackers can exploit them. &lt;code&gt;dnf-automatic&lt;/code&gt; already does most of the heavy lifting out of the box — it can download and apply updates on a schedule, send notifications, and even reboot when needed. The challenge is managing it consistently across your entire fleet without configuration drift.&lt;/p&gt;

&lt;p&gt;Additionally, production systems may need a different set of policies for updates than development or staging system, i.e. only security updates, while other stages use fully updated systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;confdroid_automatic&lt;/strong&gt; solves that by turning dnf-automatic into a fully Puppet-controlled service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Installs and configures the &lt;code&gt;dnf-automatic&lt;/code&gt; package&lt;/li&gt;
&lt;li&gt;Manages the main configuration file (&lt;code&gt;/etc/dnf/automatic.conf&lt;/code&gt;) with proper permissions and SELinux contexts&lt;/li&gt;
&lt;li&gt;Controls the &lt;code&gt;dnf-automatic.timer&lt;/code&gt; systemd service&lt;/li&gt;
&lt;li&gt;Supports flexible parameters you can override via Foreman ENC or Hiera&lt;/li&gt;
&lt;li&gt;Includes sensible defaults for production use while allowing fine-tuning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Main tunable parameters include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ac_upgrade_type&lt;/code&gt;-  'default', 'security', 'minimal' or 'all'&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ac_apply_updates&lt;/code&gt; — whether to actually install updates (or just download them)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ac_download_updates&lt;/code&gt; — enable downloading of available packages&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ac_random_sleep&lt;/code&gt; — add a random delay (in seconds) to prevent all servers from updating at the exact same moment&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ac_reboot&lt;/code&gt; - when to reboot after applied updates&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ac_email_to&lt;/code&gt; - which email address to notify&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Automatic Update Flow
&lt;/h2&gt;

&lt;p&gt;Here’s how the module turns Puppet configuration into real-world automated patching:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxbnqljesfg108m7sdqs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxbnqljesfg108m7sdqs.png" alt="Mermaid diagram" width="508" height="1780"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The flow ensures updates are applied safely and predictably. The optional random sleep helps avoid “thundering herd” problems in larger environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Use It
&lt;/h2&gt;

&lt;p&gt;Import the module via r10k (Puppetfile).&lt;/p&gt;

&lt;p&gt;The simplest way to enable automatic updates on a node is in site.pp:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight puppet"&gt;&lt;code&gt;&lt;span class="k"&gt;include&lt;/span&gt; &lt;span class="nc"&gt;confdroid_automatic&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To apply via Foreman:&lt;/p&gt;

&lt;p&gt;Assign &lt;strong&gt;confdroid_automatic::params&lt;/strong&gt; to the host or hostgroup in Question and override parameters as required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Test thoroughly in a non-production environment first. Automatic updates can cause reboots or service restarts.&lt;/li&gt;
&lt;li&gt;If you already have a manual dnf-automatic configuration, the module will overwrite it — start clean or review the generated config carefully.&lt;/li&gt;
&lt;li&gt;The module handles SELinux contexts automatically, so it works smoothly on enforcing-mode Rocky 9 systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the full module, source code, and parameter reference &lt;a href="https://sourcecode.confdroid.com/confdroid/confdroid_automatic" rel="noopener noreferrer"&gt;here: https://sourcecode.confdroid.com/confdroid/confdroid_automatic&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;With &lt;strong&gt;confdroid_automatic&lt;/strong&gt;, keeping your Rocky 9 fleet patched becomes a truly hands-off process. Combined with the rest of the Confdroid collection (including monitoring via &lt;code&gt;confdroid_nagios&lt;/code&gt;), you get a consistent, secure, and maintainable update strategy.&lt;/p&gt;

&lt;p&gt;Automated patching is no longer a nice-to-have — it’s a baseline security requirement. This module makes it simple, repeatable, and fully integrated into your Puppet workflow.&lt;/p&gt;

&lt;p&gt;Have you been managing OS updates manually or with scripts? Would you like automatic reboots enabled or prefer a download-only approach? Drop your thoughts or questions in the comments — I’d love to hear how you handle patching in your environment.&lt;/p&gt;




&lt;p&gt;Did you find this post helpful?  You can support me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/grizzly_coda" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2znn4km0i2jib7ru1sm9.png" alt="" width="170" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hetzner.cloud/?ref=EY14C8Tema9j" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyab43i0ysz9uwuq267u0.png" alt="Hetzner Referral" width="400" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://confdroid.substack.com/subscribe?params=%5Bobject%20Object%5D" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r49xyl05rwkjb52xbqg.png" alt="Substack" width="250" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://feedback.confdroid.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7d47hck6vziak35nfgf.png" alt="ConfDroid Feedback Portal" width="300" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-pilot/" rel="noopener noreferrer"&gt;Confdroid Puppet Modules - Pilot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-puppet/" rel="noopener noreferrer"&gt;Confdroid Puppet Modules - Puppet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-resources/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - confdroid_resources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-postgresql/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Postgresql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-gitea/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Gitea&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-apache/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Apache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-nagios/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Nagios&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-nrpe/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - NRPE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-fail2ban/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Fail2ban&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-selinux/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Selinux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>confdroid</category>
      <category>updates</category>
      <category>puppet</category>
      <category>foreman</category>
    </item>
    <item>
      <title>Kubernetes - Argo-CD - Custom Installation</title>
      <dc:creator>12ww1160</dc:creator>
      <pubDate>Sat, 04 Apr 2026 13:42:24 +0000</pubDate>
      <link>https://forem.com/12ww1160/kubernetes-argo-cd-custom-installation-5906</link>
      <guid>https://forem.com/12ww1160/kubernetes-argo-cd-custom-installation-5906</guid>
      <description>&lt;h2&gt;
  
  
  Installing Argo CD the GitOps Way: A More Stable and Maintainable Approach
&lt;/h2&gt;

&lt;p&gt;I recently deployed Argo CD in my dev cloud and I’m already impressed with how much it improves my Kubernetes workflow. Instead of following the quick official installation method, I adapted the process for better version control, reproducibility, and long-term stability.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Official Quick-Start Method
&lt;/h2&gt;

&lt;p&gt;The fastest way to get Argo CD running is this one-liner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create namespace argocd
kubectl apply &lt;span class="nt"&gt;-n&lt;/span&gt; argocd &lt;span class="nt"&gt;--server-side&lt;/span&gt; &lt;span class="nt"&gt;--force-conflicts&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works great for testing or throwaway environments. For production or long-lived setups, however, I strongly recommend a more deliberate approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a GitOps-First Installation Is Better
&lt;/h2&gt;

&lt;p&gt;Argo CD is almost entirely configured through Kubernetes ConfigMaps and other manifests. While you can tweak some settings in the web UI, most changes live in YAML files. Relying on ad-hoc &lt;code&gt;kubectl&lt;/code&gt; commands makes it easy to lose track of changes, forget why something was modified, or end up with inconsistent configurations across team members.&lt;/p&gt;

&lt;p&gt;Here’s the recommended workflow I followed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a dedicated Git repository for Argo CD configuration.&lt;/li&gt;
&lt;li&gt;Download the official manifests and commit them to your repo.&lt;/li&gt;
&lt;li&gt;Use a CI/CD pipeline to deploy the manifests (use --server-side --force-conflicts on the very first apply).&lt;/li&gt;
&lt;li&gt;After the initial deployment, you can let Argo CD manage its own configuration (self-management) or continue using the CI/CD pipeline. Both approaches work well.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The big advantages are clear version history, proper editing with your favorite tools, and a stable local copy that doesn’t change unexpectedly with every upstream update.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note on --server-side --force-conflicts&lt;br&gt;
This is required because some Argo CD Custom Resource Definitions (like ApplicationSet) exceed the size limit for client-side apply. Server-side apply avoids storing the large last-applied-configuration annotation. The force flag safely takes ownership of fields during fresh installs or upgrades.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Installing the Argo CD CLI (Optional but Handy)
&lt;/h2&gt;

&lt;p&gt;The Argo CD CLI is useful for scripting, automation, and quick checks from your workstation or CI/CD pipelines.&lt;br&gt;
On Linux, install it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
&lt;span class="nb"&gt;sudo install&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 555 argocd-linux-amd64 /usr/local/bin/argocd
&lt;span class="nb"&gt;rm &lt;/span&gt;argocd-linux-amd64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adapting Argo CD for My Environment
&lt;/h2&gt;

&lt;p&gt;Because I expose all services through an external HAProxy that handles TLS termination, I needed to run Argo CD in insecure mode (disabling its built-in TLS). Same is required when you use argocd cli.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ConfigMap&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd-cmd-params-cm&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/part-of&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd-cmd-params-cm&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;server.insecure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Exposing Argo CD via NodePort
&lt;/h2&gt;

&lt;p&gt;The official docs don’t clearly document NodePort as an option, so I customized the Service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/component&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;server&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd-server&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/part-of&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd-server&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
    &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
    &lt;span class="na"&gt;nodePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30080&lt;/span&gt;   &lt;span class="c1"&gt;# adjust to your needs&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd-server&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePort&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since HAProxy forwards everything to HTTP on port 80, the HTTPS port isn’t needed. The &lt;code&gt;--insecure&lt;/code&gt; flag prevents redirect loops.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up OIDC Authentication with Keycloak
&lt;/h2&gt;

&lt;p&gt;For centralized authentication, I configured Argo CD to use my existing Keycloak instance via OIDC, which his why I needed the service to be accessible from outside Kubernetes in first place:&lt;/p&gt;

&lt;p&gt;First, create a client in Keycloak, then add this to the argocd-cm ConfigMap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ConfigMap&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argocd-cm&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://argocd.yourdomain.com&lt;/span&gt;
  &lt;span class="na"&gt;oidc.config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;name: Keycloak&lt;/span&gt;
    &lt;span class="s"&gt;issuer: https://keycloak.yourdomain.com/realms/your_realm&lt;/span&gt;
    &lt;span class="s"&gt;clientID: argocd&lt;/span&gt;
    &lt;span class="s"&gt;clientSecret: $oidc.keycloak.clientSecret&lt;/span&gt;
    &lt;span class="s"&gt;refreshTokenThreshold: 2m&lt;/span&gt;
    &lt;span class="s"&gt;requestedScopes: ["openid", "profile", "email", "groups"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives me single sign-on with Keycloak, which is especially useful in company environments that already use centralized identity management.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visualizing the GitOps Flow with Argo CD
&lt;/h2&gt;

&lt;p&gt;Here’s how the GitOps loop looks when Argo CD manages applications — and even itself:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2cgpzo1k60trwc15n40d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2cgpzo1k60trwc15n40d.png" alt="Mermaid diagram" width="586" height="744"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Keycloak OIDC Authentication Flow
&lt;/h2&gt;

&lt;p&gt;And here’s the authentication flow once OIDC is configured:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftl9trdgk0l724ct0wfgx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftl9trdgk0l724ct0wfgx.png" alt="Mermaid diagram" width="784" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;At this point, Argo CD is up and running with a clean GitOps foundation, external load balancing, and centralized authentication. In the next post, I’ll cover how to add and manage your first applications declaratively.&lt;br&gt;
If you’re setting up Argo CD in your own environment — especially with external TLS termination or OIDC — I hope these tweaks save you some time.&lt;br&gt;
Have you tried managing Argo CD declaratively yet? Do you prefer the CLI or the UI for day-to-day operations? Share your thoughts in the comments!&lt;/p&gt;




&lt;p&gt;Did you find this post helpful?  You can support me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/grizzly_coda" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2znn4km0i2jib7ru1sm9.png" alt="" width="170" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hetzner.cloud/?ref=EY14C8Tema9j" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyab43i0ysz9uwuq267u0.png" alt="Hetzner Referral" width="400" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://confdroid.substack.com/subscribe?params=%5Bobject%20Object%5D" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r49xyl05rwkjb52xbqg.png" alt="Substack" width="250" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://feedback.confdroid.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7d47hck6vziak35nfgf.png" alt="ConfDroid Feedback Portal" width="300" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/kubernetes-adventures-pilot/" rel="noopener noreferrer"&gt;Kubernetes - Adventures - Pilot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/kubernetes-adventures-argocd/" rel="noopener noreferrer"&gt;Kubernetes - Adventures - Argo-CD&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>cicd</category>
      <category>argocd</category>
      <category>gitops</category>
    </item>
    <item>
      <title>Puppet with Foreman - PuppetDB Reporting Errors</title>
      <dc:creator>12ww1160</dc:creator>
      <pubDate>Mon, 30 Mar 2026 13:59:16 +0000</pubDate>
      <link>https://forem.com/12ww1160/puppet-with-foreman-puppetdb-reporting-errors-3ldc</link>
      <guid>https://forem.com/12ww1160/puppet-with-foreman-puppetdb-reporting-errors-3ldc</guid>
      <description>&lt;h2&gt;
  
  
  Fixing Missing OS, Environment, and Fact Data in Foreman When Using PuppetDB
&lt;/h2&gt;

&lt;p&gt;Recently, I re-introduced &lt;strong&gt;PuppetDB&lt;/strong&gt; into my infrastructure to support the new &lt;code&gt;confdroid_nagios&lt;/code&gt; module. Everything worked as expected on the Puppet side — PuppetDB stored facts, catalogs, and reports correctly.&lt;/p&gt;

&lt;p&gt;However, when I checked Foreman, something looked wrong. All hosts showed empty fields for basic information such as &lt;strong&gt;Operating System&lt;/strong&gt;, &lt;strong&gt;Environment&lt;/strong&gt;, and many other facts. The core Puppet functionality was fine, but Foreman’s host overview and reporting appeared broken.&lt;br&gt;
After some investigation, I found a simple but important configuration mismatch.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Root Cause
&lt;/h2&gt;

&lt;p&gt;When Foreman is used as an External Node Classifier (ENC), Puppet needs a specific routing configuration to properly handle facts. This is defined in the file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/etc/puppetlabs/puppet/routes.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;An older default configuration (still present in some Foreman installations) looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;master&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;facts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;terminus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;puppetdb&lt;/span&gt;
    &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup worked in earlier versions of Puppet Server, but modern Puppet Server (starting around version 7) prefers JSON for the fact cache because it is faster and avoids certain quirks of YAML.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Correct Configuration
&lt;/h2&gt;

&lt;p&gt;Update the file to use JSON as the cache format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;master&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;facts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;terminus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;puppetdb&lt;/span&gt;
    &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After making this change, restart the relevant services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl restart puppetserver
systemctl restart foreman
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As soon as the services came back up, all the missing facts — OS details, environments, custom facts, and more — started populating correctly in Foreman.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Pieces Fit Together
&lt;/h2&gt;

&lt;p&gt;To make the interaction clearer, here’s a visual overview of the data flow between the Puppet agent, Puppet Server, PuppetDB, and Foreman:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ckdkrg2onkkjs2877ad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ckdkrg2onkkjs2877ad.png" alt="Mermaid diagram" width="784" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Key flow explained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Puppet agent reports facts to the Puppet Server.&lt;/li&gt;
&lt;li&gt;Puppet Server stores them in PuppetDB (using the puppetdb terminus).&lt;/li&gt;
&lt;li&gt;When Foreman acts as the ENC, the Puppet Server also needs to retrieve facts from PuppetDB to display rich host information in the Foreman UI.
The &lt;code&gt;routes.yaml&lt;/code&gt; file tells Puppet Server exactly how to read and cache those facts. Using &lt;code&gt;cache: json&lt;/code&gt; aligns with current Puppet Server defaults and ensures Foreman receives complete, properly formatted data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Tip
&lt;/h2&gt;

&lt;p&gt;If you are running a modern Puppet Server (7 or 8) with Foreman and PuppetDB, always double-check that &lt;code&gt;routes.yaml&lt;/code&gt; uses &lt;code&gt;cache: json&lt;/code&gt;. The older &lt;code&gt;yaml&lt;/code&gt; setting can silently cause missing or incomplete data in Foreman without breaking Puppet itself.&lt;/p&gt;

&lt;p&gt;This small change took only a few minutes but restored full visibility and reporting in my Foreman dashboard.&lt;br&gt;
Have you run into similar fact synchronization issues between PuppetDB and Foreman? What versions are you running? Feel free to share your experiences or additional tips in the comments.&lt;/p&gt;




&lt;p&gt;Did you find this post helpful?  You can support me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/grizzly_coda" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2znn4km0i2jib7ru1sm9.png" alt="" width="170" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hetzner.cloud/?ref=EY14C8Tema9j" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyab43i0ysz9uwuq267u0.png" alt="Hetzner Referral" width="400" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://confdroid.substack.com/subscribe?params=%5Bobject%20Object%5D" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r49xyl05rwkjb52xbqg.png" alt="Substack" width="250" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://feedback.confdroid.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7d47hck6vziak35nfgf.png" alt="ConfDroid Feedback Portal" width="300" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/puppet-with-foreman-pilot/" rel="noopener noreferrer"&gt;Puppet with Foreman - Pilot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/puppet-with-foreman-installation/" rel="noopener noreferrer"&gt;Puppet with Foreman - Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/puppet-with-foreman-infrastructure/" rel="noopener noreferrer"&gt;Puppet with Foreman - Infrastructure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/puppet-with-foreman-r10k/" rel="noopener noreferrer"&gt;Puppet with Foreman - R10k&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/puppet-with-foreman-host-registration/" rel="noopener noreferrer"&gt;Puppet with Foreman - Host registration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>automation</category>
      <category>devops</category>
      <category>puppet</category>
      <category>foreman</category>
    </item>
    <item>
      <title>ConfDroid Puppet Modules - Fail2ban</title>
      <dc:creator>12ww1160</dc:creator>
      <pubDate>Sat, 28 Mar 2026 18:22:55 +0000</pubDate>
      <link>https://forem.com/12ww1160/confdroid-puppet-modules-fail2ban-m6m</link>
      <guid>https://forem.com/12ww1160/confdroid-puppet-modules-fail2ban-m6m</guid>
      <description>&lt;h2&gt;
  
  
  Introducing confdroid_fail2ban: Automated Brute-Force Protection for Your Puppet-Managed Servers
&lt;/h2&gt;

&lt;p&gt;Brute-force attacks remain one of the most common threats to internet-facing services. Attackers continuously scan for open ports and try thousands of username/password combinations against SSH, web logins, admin panels, and other services. Left unchecked, these attacks can lead to compromised accounts, data breaches, or even full server takeovers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fail2Ban&lt;/strong&gt; has been the go-to open-source solution for years. It monitors log files for suspicious patterns — such as repeated failed login attempts — and automatically bans the offending IP addresses by updating firewall rules (usually via iptables).&lt;/p&gt;

&lt;p&gt;Out of the box, Fail2Ban already does an excellent job protecting common services like SSH (&lt;code&gt;sshd&lt;/code&gt; jail) and Apache with its default settings. It requires almost no manual tuning for basic protection, making it a set-it-and-forget-it tool that quietly strengthens server security.&lt;/p&gt;

&lt;h2&gt;
  
  
  Taking Fail2Ban Further with Puppet
&lt;/h2&gt;

&lt;p&gt;While Fail2Ban works great on its own, managing it consistently across multiple servers — especially with custom jails for non-standard services — quickly becomes tedious. That’s where my new Puppet module comes in.&lt;/p&gt;

&lt;p&gt;I’m happy to announce the release of &lt;strong&gt;confdroid_fail2ban&lt;/strong&gt;, now available in the Confdroid Forge.&lt;br&gt;
This module provides a clean, declarative way to install, configure, and manage Fail2Ban on RHEL/Rocky 9 systems using Puppet 8. It handles everything from package installation and directory setup (with correct SELinux contexts) to managing the core configuration files and systemd service.&lt;/p&gt;
&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Full management of fail2ban.conf, fail2ban.local, jail.conf, and jail.local (using the standard .local override pattern)&lt;/li&gt;
&lt;li&gt;Proper filesystem permissions and SELinux context handling&lt;/li&gt;
&lt;li&gt;Easy parameter overrides via Foreman ENC or Hiera (e.g., ban time, destination email for notifications, Nagios monitoring integration)&lt;/li&gt;
&lt;li&gt;Support for enabling/disabling the service&lt;/li&gt;
&lt;li&gt;Seamless integration with iptables for automatic IP banning&lt;/li&gt;
&lt;li&gt;Designed to work smoothly alongside other Confdroid modules&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Custom Jails for Modern Services
&lt;/h2&gt;

&lt;p&gt;Many self-hosted applications (Gitea, custom Apache setups, Nagios, etc.) are not covered by Fail2Ban’s default jails. The &lt;strong&gt;confdroid_fail2ban&lt;/strong&gt; module makes it simple to add and tune custom jails for these services.&lt;/p&gt;

&lt;p&gt;For example, when you use the &lt;strong&gt;confdroid_apache&lt;/strong&gt; module, you can easily enable a tailored Apache authentication jail that monitors the correct log paths and applies appropriate thresholds.&lt;br&gt;
Going forward, other Confdroid modules that expose authentication or admin interfaces will include their own recommended custom jails where needed. This creates a consistent, zero-touch security layer across your entire infrastructure.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;In today’s threat landscape, relying solely on strong passwords or basic firewall rules is no longer enough. Automated brute-force protection like Fail2Ban adds a critical defensive layer that reacts in real time — banning attackers before they succeed.&lt;br&gt;
By managing Fail2Ban declaratively with Puppet, you gain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistent security posture across all servers&lt;/li&gt;
&lt;li&gt;Version-controlled configuration&lt;/li&gt;
&lt;li&gt;Easy customization without editing files by hand&lt;/li&gt;
&lt;li&gt;Reduced risk of configuration drift&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Deploying the module is straightforward. Simply deploy it via R10k and include the class in your node definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;include confdroid_fail2ban
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Via Foreman by adding *&lt;em&gt;confdroid_fail2ban::params *&lt;/em&gt; to your hosts or hostgroups.&lt;/p&gt;

&lt;p&gt;You can then fine-tune parameters (ban time, email notifications, specific jails, etc.) through your ENC.&lt;br&gt;
Note: If you already have a manually configured Fail2Ban installation, test this module in a non-production environment first, as it manages configuration files comprehensively.&lt;/p&gt;

&lt;p&gt;You can find the full module, documentation, and parameter reference &lt;a href="https://sourcecode.confdroid.com/confdroid/confdroid_fail2ban" rel="noopener noreferrer"&gt;here: https://sourcecode.confdroid.com/confdroid/confdroid_fail2ban&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Security should be automated and consistent. &lt;strong&gt;confdroid_fail2ban&lt;/strong&gt; makes it easy to bring reliable brute-force protection to all your Puppet-managed servers while keeping configuration clean and maintainable.&lt;br&gt;
If you run self-hosted services like Gitea, Apache-based apps, or internal tools, I highly recommend pairing this module with the rest of the Confdroid collection for a cohesive and secure setup.&lt;br&gt;
What services do you protect with Fail2Ban today? Have you run into challenges managing custom jails? Feel free to share your experiences in the comments.&lt;/p&gt;




&lt;p&gt;Did you find this post helpful?  You can support me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/grizzly_coda" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2znn4km0i2jib7ru1sm9.png" alt="" width="170" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hetzner.cloud/?ref=EY14C8Tema9j" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyab43i0ysz9uwuq267u0.png" alt="Hetzner Referral" width="400" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://confdroid.substack.com/subscribe?params=%5Bobject%20Object%5D" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r49xyl05rwkjb52xbqg.png" alt="Substack" width="250" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://feedback.confdroid.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7d47hck6vziak35nfgf.png" alt="ConfDroid Feedback Portal" width="300" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-pilot/" rel="noopener noreferrer"&gt;Confdroid Puppet Modules - Pilot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-puppet/" rel="noopener noreferrer"&gt;Confdroid Puppet Modules - Puppet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-resources/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - confdroid_resources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-postgresql/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Postgresql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-gitea/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Gitea&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-apache/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Apache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-nagios/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Nagios&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-nrpe/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - NRPE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-automatic/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Automatic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-selinux/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Selinux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>confdroid</category>
      <category>apache</category>
      <category>puppet</category>
      <category>fail2ban</category>
    </item>
    <item>
      <title>Wordpress - Caching riddles</title>
      <dc:creator>12ww1160</dc:creator>
      <pubDate>Sat, 28 Mar 2026 15:58:03 +0000</pubDate>
      <link>https://forem.com/12ww1160/wordpress-caching-riddles-2bpb</link>
      <guid>https://forem.com/12ww1160/wordpress-caching-riddles-2bpb</guid>
      <description>&lt;h2&gt;
  
  
  When Caching Breaks Your WordPress REST API: A Debugging Story and Why Caching Still Matters
&lt;/h2&gt;

&lt;p&gt;For the past six months, my custom publishing pipeline has worked flawlessly. I write a blog post once in Markdown with YAML frontmatter, push it to Git, and a Jenkins-based CI/CD pipeline automatically publishes it to multiple platforms. WordPress serves as the canonical source, with the pipeline using the &lt;strong&gt;WordPress REST API&lt;/strong&gt; to create or update posts, upload media, set tags, and handle everything else.&lt;/p&gt;

&lt;p&gt;Then, two days ago, everything stopped. The pipeline started throwing tracebacks on every run. Nothing in my code or setup had changed — only a new post was being published. Even after removing the new post, the errors persisted. A similar pipeline on another site broke at the same time.&lt;/p&gt;

&lt;p&gt;After a full day of troubleshooting, I narrowed it down: the WordPress REST API was returning completely empty responses for posts and tags endpoints. That left only two likely culprits — a recent WordPress core update or a plugin update.&lt;br&gt;
I rolled back the latest WordPress update (not ideal, as database schema changes can cause issues). No improvement. Then I began disabling plugins one by one. The culprit? &lt;strong&gt;W3 Total Cache.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even though it was explicitly configured &lt;strong&gt;not&lt;/strong&gt; to cache the REST API, it was still interfering and returning empty pages. Disabling the plugin instantly fixed the problem. What surprised me most was that this same setup had worked without issues for several years. I tried flushing all caches, re-saving settings, and restarting services multiple times — nothing helped. In the end, I switched to WP Super Cache (developed by Automattic) and so far, everything is running smoothly again.&lt;br&gt;
I still want to keep caching on my WordPress sites — it’s simply too important for performance to give up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Caching Is Essential for WordPress Sites
&lt;/h2&gt;

&lt;p&gt;Caching dramatically improves website speed and user experience by storing ready-to-serve versions of your content instead of regenerating it from scratch on every request. Without it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every page load hits the database and PHP processor heavily.&lt;/li&gt;
&lt;li&gt;Server load increases, especially under traffic spikes.&lt;/li&gt;
&lt;li&gt;Visitors experience slower load times, which hurts both user satisfaction and SEO.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modern caching plugins typically combine several layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Page caching&lt;/strong&gt; — Stores full HTML output as static files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Object caching&lt;/strong&gt; — Caches database queries and expensive operations (often using Memcached or Redis).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser caching&lt;/strong&gt; — Tells visitors’ browsers how long to keep assets like images, CSS, and JavaScript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minification and CDN integration&lt;/strong&gt; — Reduces file sizes and delivers content from edge locations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The challenge arises when caching touches dynamic endpoints like the WordPress REST API, which my publishing pipeline relies on. API calls need fresh, up-to-date data — not stale cached responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Object Caching Works with Memcached (Visualized)
&lt;/h2&gt;

&lt;p&gt;Here’s a simplified flow of how object caching (using Memcached) typically works in a WordPress environment:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgp1tyjjkl5qh5ox69ejp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgp1tyjjkl5qh5ox69ejp.png" alt="Mermaid diagram" width="583" height="908"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On a &lt;strong&gt;cache hit&lt;/strong&gt;, the response is served almost instantly from memory.&lt;/li&gt;
&lt;li&gt;On a &lt;strong&gt;cache miss&lt;/strong&gt;, WordPress does the heavy work once, then stores the result in Memcached so future requests are lightning-fast.&lt;/li&gt;
&lt;li&gt;Keys usually include a version or hash so updates can invalidate old entries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trick is configuring the cache plugin to exclude dynamic paths like /wp-json/ while still benefiting from full-page and object caching everywhere else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Even well-configured caching plugins can suddenly interfere with the REST API after years of smooth operation.&lt;/li&gt;
&lt;li&gt;When debugging API issues, always consider caching plugins early in the process.&lt;/li&gt;
&lt;li&gt;Simpler solutions like WP Super Cache can sometimes be more reliable for certain setups than feature-heavy ones like W3 Total Cache.&lt;/li&gt;
&lt;li&gt;Caching remains one of the highest-ROI performance improvements you can make on a WordPress site — just make sure it plays nicely with your automation and API-driven workflows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My publishing pipeline is back online, and I’ll continue monitoring how WP Super Cache behaves over the coming weeks. If you run a similar automated publishing setup or rely heavily on the WordPress REST API, double-check your caching exclusions.&lt;/p&gt;

&lt;p&gt;Have you ever had a caching plugin silently break your API calls? Which caching solution are you using now — W3 Total Cache, WP Super Cache, or something else? Share your experiences in the comments.&lt;/p&gt;




&lt;p&gt;Did you find this post helpful?  You can support me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/grizzly_coda" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2znn4km0i2jib7ru1sm9.png" alt="" width="170" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hetzner.cloud/?ref=EY14C8Tema9j" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyab43i0ysz9uwuq267u0.png" alt="Hetzner Referral" width="400" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://confdroid.substack.com/subscribe?params=%5Bobject%20Object%5D" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r49xyl05rwkjb52xbqg.png" alt="Substack" width="250" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://feedback.confdroid.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7d47hck6vziak35nfgf.png" alt="ConfDroid Feedback Portal" width="300" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>cache</category>
      <category>devops</category>
      <category>gitops</category>
    </item>
    <item>
      <title>Git - Verified Commits with SSH keys</title>
      <dc:creator>12ww1160</dc:creator>
      <pubDate>Thu, 26 Mar 2026 18:09:41 +0000</pubDate>
      <link>https://forem.com/12ww1160/git-verified-commits-with-ssh-keys-4oe6</link>
      <guid>https://forem.com/12ww1160/git-verified-commits-with-ssh-keys-4oe6</guid>
      <description>&lt;h2&gt;
  
  
  Why Verified Commits Matter in Git — And How I Fixed Mine with SSH Signing
&lt;/h2&gt;

&lt;p&gt;When I first started using Git, I had no idea that anyone could easily impersonate me — or anyone else — in the commit history. It turns out it’s shockingly simple.&lt;br&gt;
All you need to do is run a couple of commands like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config user.name &lt;span class="s2"&gt;"Someone Important"&lt;/span&gt;
git config user.email &lt;span class="s2"&gt;"ceo@bigproject.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suddenly, your commits appear as if they came from that person. The commit message, author field, and history all reflect the fake identity. No hacking required.&lt;br&gt;
This isn’t just a theoretical issue. Many supply chain attacks rely on exactly this technique: an attacker creates a convincing pull request under a trusted name, gets it merged, and malicious code slips into the project. Without verified commits, there’s no cryptographic proof that the person who pushed the code is really who they claim to be.&lt;/p&gt;

&lt;p&gt;That’s why &lt;strong&gt;verified commits&lt;/strong&gt; are a critical security practice. Whether you’re running your own GitLab instance, using GitHub, or managing any shared repository, you should strongly consider requiring verified commits — either through automatic enforcement (if your platform supports it) or rigorous peer review.&lt;/p&gt;
&lt;h2&gt;
  
  
  My First Step: Switching to GPG Signing
&lt;/h2&gt;

&lt;p&gt;Once I understood the risk, I created a GPG key, uploaded the public key to my GitLab account (with a verified email address), and enabled commit signing. From that point on, my commits showed up with a nice “Verified” badge. It felt secure and professional.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Keycloak Integration That Broke Everything
&lt;/h2&gt;

&lt;p&gt;Earlier this year, I connected my self-hosted GitLab instance to Keycloak to centralize authentication across all my applications. The move was mostly smooth and improved my overall security posture.&lt;br&gt;
But then something strange happened: all my new commits suddenly appeared as “Unverified.”&lt;br&gt;
I spent nearly two full days troubleshooting — checking keys, emails, configurations, and even re-uploading keys — with no success. The problem felt impossible to pinpoint.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Simpler Solution: SSH Commit Signing
&lt;/h2&gt;

&lt;p&gt;Yesterday I finally dug deeper and discovered that modern Git supports two main ways to sign commits: &lt;strong&gt;GPG&lt;/strong&gt; keys &lt;em&gt;and&lt;/em&gt; &lt;strong&gt;SSH&lt;/strong&gt; keys.&lt;/p&gt;

&lt;p&gt;Since I already use SSH keys to authenticate and push to GitLab, switching to SSH signing was straightforward. Here’s exactly what I did:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tell Git to use SSH for signing:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; gpg.format ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Point Git to my existing SSH public key:Bash
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.signingkey ~/.ssh/id_ed25519.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;(Replace with the path to your own public key file.)&lt;/p&gt;

&lt;p&gt;I already had these settings enabled for automatic signing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; commit.gpgsign &lt;span class="nb"&gt;true
&lt;/span&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; tag.gpgsign &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it.&lt;/p&gt;

&lt;p&gt;Because my SSH public key was already uploaded to my GitLab account (required for SSH access anyway), and the key supports both authentication and signing (the default for most modern keys), all my commits immediately started showing as &lt;strong&gt;Verified&lt;/strong&gt; again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why SSH Signing Feels Easier Than GPG
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No need to upload the public key to external GPG keyservers.&lt;/li&gt;
&lt;li&gt;You’re probably already using an SSH key for Git operations. It is much more convenient than using credentials via https.&lt;/li&gt;
&lt;li&gt;The configuration is lightweight and integrates cleanly with your existing setup.&lt;/li&gt;
&lt;li&gt;GitLab and GitHub both support SSH commit verification out of the box.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Bigger Picture: Make Verified Commits Non-Negotiable
&lt;/h2&gt;

&lt;p&gt;Verified commits close a dangerous gap in the supply chain. They provide cryptographic proof that the code came from the claimed author and hasn’t been tampered with after signing.&lt;/p&gt;

&lt;p&gt;If you administer repositories or run a Git instance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable “Reject unsigned commits” push rules where available (i.e. Gitlab Premium and Ultimate tiers).&lt;/li&gt;
&lt;li&gt;On GitHub, use branch protection rules to require signed commits.&lt;/li&gt;
&lt;li&gt;Encourage (or require) your team to sign every commit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It only takes a few minutes to set up, but it adds a meaningful layer of protection against impersonation and supply chain attacks.&lt;br&gt;
In my case, switching to SSH signing restored my verified status in minutes and reminded me how important this practice really is. My Git workflow now feels secure again — and the world (or at least my private cloud) is a little safer.&lt;/p&gt;

&lt;p&gt;Have you started signing your commits yet? Are you using GPG, SSH, or both? I’d love to hear what worked best for you in the comments.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Verified Commits Matter – Visualized
&lt;/h2&gt;

&lt;p&gt;To make the process easier to understand, here’s a clear flowchart of the Git Commit Verification Flow. It shows how easy it is to impersonate someone without signing, and how cryptographic signing (especially with SSH keys) creates a trustworthy, verifiable chain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsarfwbgcp6tcq73hfoqb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsarfwbgcp6tcq73hfoqb.png" alt="Mermaid diagram" width="784" height="906"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How to Read the Diagram
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Right side (Insecure path)&lt;/strong&gt;: Anyone can fake an author identity with just two git config commands. The commit looks legitimate to the naked eye, but carries no proof of who really created it. This is the vector many supply chain attacks exploit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Left side (Secure path)&lt;/strong&gt;: When you enable commit signing:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Git uses your private key (GPG or SSH) to create a cryptographic signature.&lt;/li&gt;
&lt;li&gt;You upload the public key once to your Git hosting platform (GitHub, GitLab, etc.).&lt;/li&gt;
&lt;li&gt;The platform automatically verifies the signature on every push.&lt;/li&gt;
&lt;li&gt;Successful verification results in the trusted “Verified” badge.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;SSH signing&lt;/strong&gt; (as described in the post) makes this especially convenient because most developers already have an SSH key set up for pushing code. After setting &lt;code&gt;gpg.format=ssh&lt;/code&gt; and &lt;code&gt;user.signingkey&lt;/code&gt;, everything happens automatically with &lt;code&gt;commit.gpgsign=true&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Quick Setup Reminder for SSH Signing
&lt;/h2&gt;

&lt;p&gt;Add these lines to your global Git config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; gpg.format ssh
git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.signingkey ~/.ssh/id_ed25519.pub   &lt;span class="c"&gt;# or your key path&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; commit.gpgsign &lt;span class="nb"&gt;true
&lt;/span&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; tag.gpgsign &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Did you find this post helpful?  You can support me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/grizzly_coda" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2znn4km0i2jib7ru1sm9.png" alt="" width="170" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hetzner.cloud/?ref=EY14C8Tema9j" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyab43i0ysz9uwuq267u0.png" alt="Hetzner Referral" width="400" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://confdroid.substack.com/subscribe?params=%5Bobject%20Object%5D" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r49xyl05rwkjb52xbqg.png" alt="Substack" width="250" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://feedback.confdroid.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7d47hck6vziak35nfgf.png" alt="ConfDroid Feedback Portal" width="300" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>cicd</category>
      <category>devops</category>
      <category>gitops</category>
    </item>
    <item>
      <title>Kubernetes - Adventures - Argo-CD</title>
      <dc:creator>12ww1160</dc:creator>
      <pubDate>Wed, 25 Mar 2026 15:36:21 +0000</pubDate>
      <link>https://forem.com/12ww1160/kubernetes-adventures-argo-cd-4o31</link>
      <guid>https://forem.com/12ww1160/kubernetes-adventures-argo-cd-4o31</guid>
      <description>&lt;h2&gt;
  
  
  From Push to Pull: How I Fully Embraced GitOps with Argo CD in My Confdroid developer cloud
&lt;/h2&gt;

&lt;p&gt;After several days of experimentation, I have now fully implemented Argo CD — and the difference in day-to-day operations is night and day.&lt;/p&gt;

&lt;p&gt;Here’s a clear before-and-after look at how my Kubernetes workflow has changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Old Way (Push-Based Deployments)
&lt;/h2&gt;

&lt;p&gt;Before Argo CD, my setup looked like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A single Git repository containing all raw Kubernetes manifests (YAML files) for both applications and core cluster components.&lt;/li&gt;
&lt;li&gt;A CI/CD pipeline that used &lt;code&gt;kubectl&lt;/code&gt; to connect to the cluster and (re)deploy everything — from the CNI and storage classes to Longhorn and other infrastructure pieces.&lt;/li&gt;
&lt;li&gt;This pipeline acted as a safety net: if the cluster ever got into a bad state, a single pipeline run could restore it to a known-good configuration.&lt;/li&gt;
&lt;li&gt;New applications could be added or updated simply by pushing changes to the repo. The pipeline would pick them up and apply them to the cluster.&lt;/li&gt;
&lt;li&gt;Troubleshooting and manual adjustments were done directly with &lt;code&gt;kubectl&lt;/code&gt; or a UI like the Kubernetes Dashboard, or in my case  Headlamp. While convenient, this also opened the door to accidental changes — scaling a deployment and forgetting to update the manifests, for example.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every git push triggered a push-based deployment. It worked well, but it relied heavily on discipline and perfect execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  The New Way (Pure GitOps with Argo CD)
&lt;/h2&gt;

&lt;p&gt;The old repository and pipeline still exist and continue to handle all low-level cluster reconfiguration (CNI, storage, base infrastructure, Argo CD configuration itself, including Keycloak integration). That safety net remains untouched.&lt;br&gt;
What changed is the introduction of a dedicated second repository dedicated to Argo CD-managed applications.&lt;br&gt;
Here’s how it works now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application manifests have been moved into the new Git repository.&lt;/li&gt;
&lt;li&gt;Argo CD is installed and configured via the original pipeline.&lt;/li&gt;
&lt;li&gt;Once running, Argo CD connects to the new repository and continuously synchronizes the cluster state with the desired state defined in Git. This requires one-off registration of the application via UI or CLI.&lt;/li&gt;
&lt;li&gt;Synchronization can be triggered from the beautiful Argo CD web UI or via the CLI — the result is identical. Best though is setting auto-sync, which is what this is all about. This can be on done application level as required / desired.&lt;/li&gt;
&lt;li&gt;Any drift is automatically corrected. If someone manually scales a deployment with &lt;code&gt;kubectl&lt;/code&gt; or changes a ConfigMap in the dashboard, Argo CD will immediately revert it back to match the Git definition.&lt;/li&gt;
&lt;li&gt;No more “I scaled it temporarily and forgot to update the YAML” accidents.&lt;/li&gt;
&lt;li&gt;All changes — even small tweaks — must now go through Git. This enforces a true pull-based GitOps model. &lt;strong&gt;Stability over convenience!&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why This Feels So Much Better
&lt;/h2&gt;

&lt;p&gt;Argo CD brings several powerful advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It operates in a pure pull model, which is inherently more reliable than the previous push approach.&lt;/li&gt;
&lt;li&gt;It can manage itself (though I chose not to enable that yet), multiple clusters, projects, and even different environments or stages — all without needing an external database.&lt;/li&gt;
&lt;li&gt;The web UI is excellent. For every application, you can see pods, ReplicaSets, Services, ConfigMaps, and more at a glance.&lt;/li&gt;
&lt;li&gt;As a massive bonus, it integrates beautifully with the Trivy Operator running in my cluster, displaying up-to-date vulnerability scan results directly in the Argo CD dashboard for each application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx6frt4kph7hkxu8kc12y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx6frt4kph7hkxu8kc12y.png" alt="argo_cd_applications" width="800" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Implementing Argo CD took me roughly four hours from start to finish, some fine-tuning pending — time extremely well spent.&lt;/p&gt;

&lt;p&gt;The cluster now feels significantly more robust and predictable. By moving to a strict GitOps workflow, I’ve eliminated an entire class of human errors while gaining much better visibility and control.&lt;/p&gt;

&lt;p&gt;This setup brings me noticeably closer to my goal of running cloud-native applications the way they were meant to be operated: declaratively, version-controlled, and automatically reconciled.&lt;/p&gt;

&lt;p&gt;GitOps isn’t just a nice-to-have anymore — it has become the foundation of how I want to run Kubernetes going forward.&lt;/p&gt;

&lt;p&gt;If you’re still managing Kubernetes with direct kubectl applies or traditional CI/CD push pipelines, I highly recommend giving Argo CD a try. The improvement in stability and peace of mind is immediate and very real.&lt;/p&gt;

&lt;p&gt;In the next post of this series, I’ll share the exact steps I took to install and configure Argo CD with Keycloak integration, along with my recommended folder structure and best practices.&lt;br&gt;
Until then — happy deploying!&lt;/p&gt;




&lt;p&gt;Did you find this post helpful?  You can support me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/grizzly_coda" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2znn4km0i2jib7ru1sm9.png" alt="" width="170" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hetzner.cloud/?ref=EY14C8Tema9j" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyab43i0ysz9uwuq267u0.png" alt="Hetzner Referral" width="400" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://confdroid.substack.com/subscribe?params=%5Bobject%20Object%5D" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r49xyl05rwkjb52xbqg.png" alt="Substack" width="250" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://feedback.confdroid.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7d47hck6vziak35nfgf.png" alt="ConfDroid Feedback Portal" width="300" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/kubernetes-adventures-pilot/" rel="noopener noreferrer"&gt;Kubernetes - Adventures - Pilot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/kubernetes-argocd-custom-installation/" rel="noopener noreferrer"&gt;Kubernetes - Argo-CD - Custom Installation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>cicd</category>
      <category>argocd</category>
      <category>gitops</category>
    </item>
    <item>
      <title>Kubernetes - Adventures - Pilot</title>
      <dc:creator>12ww1160</dc:creator>
      <pubDate>Thu, 19 Mar 2026 13:50:44 +0000</pubDate>
      <link>https://forem.com/12ww1160/kubernetes-adventures-pilot-4ioj</link>
      <guid>https://forem.com/12ww1160/kubernetes-adventures-pilot-4ioj</guid>
      <description>&lt;h2&gt;
  
  
  My Kubernetes Journey: From a Fragile Single-Node Setup to a Stable GitOps-Powered Homelab Cluster
&lt;/h2&gt;

&lt;p&gt;A few years back, I dipped my toes into Kubernetes by spinning up a simple lab cluster: one control-plane node, one worker, and a handful of basic services. To my surprise, that minimal setup ran reliably with almost zero maintenance for about two and a half years. Then it suddenly broke.&lt;/p&gt;

&lt;p&gt;That failure became the catalyst for a complete rebuild. I set out to create a proper development cluster—one control-plane node and three workers—using a vanilla kubeadm installation. Over the next three months, I methodically reproduced every common pitfall I could find, reinstalling repeatedly until the process felt rock-solid and repeatable.&lt;/p&gt;

&lt;p&gt;Early on, I shifted toward GitOps practices. I built CI/CD pipelines that handled every cluster change and installation step, relying heavily on kubectl to apply manifests directly. This approach gave me confidence and speed, turning deployments into automated, version-controlled events.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CNI Rollercoaster
&lt;/h2&gt;

&lt;p&gt;Networking proved to be the biggest source of headaches. I started with Weave Net, which worked nicely at first—but the project is no longer actively maintained, so it eventually became unsustainable.&lt;br&gt;
I tried several other CNIs, and each came with its own quirks. Flannel was straightforward but fell short in certain scenarios. Kube-router performed decently overall, yet I could never get Ingress resources to behave reliably. Worse, one day it began overwriting my firewall rules, bringing the entire cluster down hard.&lt;/p&gt;

&lt;p&gt;After multiple experiments, I landed on Calico. With some BGP tweaks to fit my environment, it delivered the stability I needed. Today, Calico remains my go-to CNI in the lab.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Ingress and External Traffic
&lt;/h2&gt;

&lt;p&gt;Ingress troubles pushed me toward an alternative: HAProxy running as an external load balancer on a separate VM. HAProxy handles TLS termination and forwards traffic to NodePort services. Because all my VMs (including the HAProxy host) are managed with Puppet, I can easily maintain proxy rules, renew certificates via Certbot, and keep everything consistent.&lt;br&gt;
This hybrid setup let me migrate many workloads off older standalone VMs and onto Kubernetes, which saved noticeable hosting costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Fits Kubernetes—and What Doesn't (Yet)
&lt;/h2&gt;

&lt;p&gt;Not every service thrives in containers with my current constraints, especially on Hetzner Cloud where storage options are limited and latency-sensitive.&lt;br&gt;
Stateful databases like PostgreSQL and MariaDB, along with Prometheus (which demands low-latency writes), struggled enough that I moved them back to dedicated VMs. The same went for Jenkins: the main controller performs better outside Kubernetes, though its agents run happily as pods.&lt;/p&gt;

&lt;h2&gt;
  
  
  Storage Solutions That Actually Work
&lt;/h2&gt;

&lt;p&gt;For persistent storage, I first looked at Rook/Ceph—but it proved far too resource-heavy for my low-budget setup at Hetzner. Longhorn turned out to be the sweet spot: lightweight, feature-rich, and equipped with solid backup capabilities.&lt;/p&gt;

&lt;p&gt;For ultra-low-cost volumes I sometimes fall back to SSHFS mounts. While SSHFS has clear performance and reliability limits, pairing it with Longhorn covers most use cases reasonably well.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cluster Today
&lt;/h2&gt;

&lt;p&gt;Right now the cluster runs 18 internal services. Infrastructure components include Keycloak for identity, OpenBao for secrets, Trivy for vulnerability scanning, Longhorn itself, and PgBouncer for connection pooling. Application workloads cover SonarQube, Gitea, OpenProject, Wiki.js, and several others.&lt;/p&gt;

&lt;p&gt;The combination delivers excellent stability. Deployments feel effortless thanks to CI/CD pipelines, while Puppet keeps the surrounding VM layer tidy. Puppet doesn't play nicely with container orchestration, though, so Ansible is steadily taking on more responsibility in the environment.&lt;/p&gt;

&lt;p&gt;Tools like Argo CD (which I deployed just yesterday and already love), Kustomize, and plain YAML manifests round out the picture. I still lean toward raw manifests for simplicity and direct control, but GitOps patterns are clearly the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking Ahead: GitOps, Argo CD, and Beyond
&lt;/h2&gt;

&lt;p&gt;With agentic development gaining momentum, I'm now looking into building applications designed to run as future SaaS offerings inside production-grade clusters. Kubernetes has proven to be the right foundation—even if there's still plenty left to master.&lt;/p&gt;

&lt;p&gt;The lessons from this homelab will fuel an ongoing series. The next post dives straight into migrating to Argo CD and embracing proper GitOps workflows, which are becoming essential in modern software delivery.&lt;/p&gt;

&lt;p&gt;If you're running Kubernetes at home, experimenting in the cloud, or just curious about real-world trade-offs, stay tuned. There's a lot more to share.&lt;br&gt;
What challenges have you hit with Kubernetes in your own setups? Drop a comment—I'd love to hear your stories.&lt;/p&gt;




&lt;p&gt;Did you find this post helpful?  You can support me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/grizzly_coda" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2znn4km0i2jib7ru1sm9.png" alt="" width="170" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hetzner.cloud/?ref=EY14C8Tema9j" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyab43i0ysz9uwuq267u0.png" alt="Hetzner Referral" width="400" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://confdroid.substack.com/subscribe?params=%5Bobject%20Object%5D" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r49xyl05rwkjb52xbqg.png" alt="Substack" width="250" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://feedback.confdroid.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7d47hck6vziak35nfgf.png" alt="ConfDroid Feedback Portal" width="300" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/kubernetes-adventures-argocd/" rel="noopener noreferrer"&gt;Kubernetes - Adventures - Argo-CD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/kubernetes-argocd-custom-installation/" rel="noopener noreferrer"&gt;Kubernetes - Argo-CD - Custom Installation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>cicd</category>
      <category>devops</category>
      <category>gitops</category>
    </item>
    <item>
      <title>ConfDroid Puppet Modules - NRPE</title>
      <dc:creator>12ww1160</dc:creator>
      <pubDate>Sun, 15 Mar 2026 16:45:07 +0000</pubDate>
      <link>https://forem.com/12ww1160/confdroid-puppet-modules-nrpe-218c</link>
      <guid>https://forem.com/12ww1160/confdroid-puppet-modules-nrpe-218c</guid>
      <description>&lt;h2&gt;
  
  
  Secure Remote Monitoring Made Simple: confdroid_nrpe Completes Your Puppet-Powered Nagios Setup
&lt;/h2&gt;

&lt;p&gt;If you’re already using &lt;a href="https://sourcecode.confdroid.com/confdroid/confdroid_nagios" rel="noopener noreferrer"&gt;&lt;strong&gt;confdroid_nagios&lt;/strong&gt;&lt;/a&gt; for automated, exported-resource monitoring, the missing piece was always the client side. That piece is now here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;confdroid_nrpe&lt;/strong&gt; is the clean, client-only Puppet module that installs and configures NRPE (Nagios Remote Plugin Executor) on every host you want to monitor. It works hand-in-hand with the Nagios server so checks run securely and automatically across your entire infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://sourcecode.confdroid.com/confdroid/confdroid_nrpe" rel="noopener noreferrer"&gt;source code: https://sourcecode.confdroid.com/confdroid/confdroid_nrpe&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://deepwiki.com/grizzlycoda/puppet_collection/4.7-confdroid_nrpe" rel="noopener noreferrer"&gt;Detailed overview: https://deepwiki.com/grizzlycoda/puppet_collection/4.7-confdroid_nrpe&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why NRPE Matters
&lt;/h2&gt;

&lt;p&gt;A central Nagios server can’t peek inside every machine without help. NRPE lets the server ask remote Linux hosts to run local check plugins (disk space, CPU load, processes, custom scripts, etc.) and return the result instantly. This keeps monitoring lightweight, secure, and fast — exactly what traditional VM and bare-metal environments need.&lt;/p&gt;

&lt;h2&gt;
  
  
  What confdroid_nrpe Delivers
&lt;/h2&gt;

&lt;p&gt;The module is built for Rocky Linux 9 and similar RedHat-based EL systems (Puppet 8 ready) and follows the same clean philosophy as the rest of the confdroid collection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installs the NRPE daemon and creates the dedicated &lt;code&gt;nrpe&lt;/code&gt; system user&lt;/li&gt;
&lt;li&gt;Sets up proper directory structure with correct permissions and SELinux contexts&lt;/li&gt;
&lt;li&gt;Manages &lt;code&gt;nrpe.conf&lt;/code&gt; (including allowed_hosts from your Nagios server)&lt;/li&gt;
&lt;li&gt;Handles &lt;code&gt;nrpe.cfg&lt;/code&gt; for dynamic check commands&lt;/li&gt;
&lt;li&gt;Grants sudo rights to the Nagios user when checks need elevated privileges&lt;/li&gt;
&lt;li&gt;Dynamically defines custom NRPE commands (no manual config files)&lt;/li&gt;
&lt;li&gt;Optionally opens the firewall port (TCP 5666) and applies SELinux exceptions&lt;/li&gt;
&lt;li&gt;Ensures the NRPE service is running and enabled&lt;/li&gt;
&lt;li&gt;Optionally enables SSL / TLS encryption&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Seamless Integration with confdroid_nagios
&lt;/h2&gt;

&lt;p&gt;Other confdroid modules (Apache, PostgreSQL, etc.) already export their Nagios checks via PuppetDB. When you apply &lt;code&gt;confdroid_nrpe&lt;/code&gt; on a client:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The client registers itself (or gets collected by the server)&lt;/li&gt;
&lt;li&gt;Check commands are written automatically into &lt;code&gt;nrpe.cfg&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The Nagios server starts actively querying the host over NRPE&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No manual host definitions. No SSH keys. No guesswork.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Nagios Connects to Clients and Runs Checks
&lt;/h2&gt;

&lt;p&gt;Here’s exactly what happens behind the scenes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foy98j9embj0b0bqk9jto.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foy98j9embj0b0bqk9jto.png" alt="Mermaid diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Nagios server simply connects to port 5666 on each client, tells NRPE which command to run, and receives the result in seconds.&lt;/p&gt;

&lt;p&gt;## Quick Start&lt;/p&gt;

&lt;p&gt;Add the module to your Puppetfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="n"&gt;mod&lt;/span&gt; &lt;span class="s1"&gt;'confdroid_nrpe'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;git: &lt;/span&gt;&lt;span class="s1"&gt;'https://sourcecode.confdroid.com/confdroid/confdroid_nrpe.git'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
puppet&lt;/p&gt;

&lt;p&gt;Then declare it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;via site.pp or nodes.pp
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="s1"&gt;'example.example.net'&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="n"&gt;confdroid_nrpe&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;through Foreman:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to apply parameters through Foreman, &lt;strong&gt;confdroid_nrpe::params&lt;/strong&gt;- must be added to the host or host group in question, unless the defaults are fully acceptable across the estate.&lt;/p&gt;

&lt;p&gt;That’s it. Your clients are now ready for fully automated monitoring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;With &lt;strong&gt;confdroid_nagios&lt;/strong&gt; on the server side and &lt;strong&gt;confdroid_nrpe&lt;/strong&gt; on every client, you get a complete, zero-touch Nagios setup driven entirely by Puppet and PuppetDB. No more manual config files, no more forgotten hosts, and rock-solid security on every endpoint.&lt;br&gt;
If you’re running traditional infrastructure (VMs, bare metal, or a hybrid mix), this combination is hard to beat.&lt;br&gt;
Ready to add remote checks to your stack? Grab the module today and let Puppet do the heavy lifting.&lt;br&gt;
Questions or feedback? The source is open — comments welcome!&lt;/p&gt;




&lt;p&gt;Did you find this post helpful?  You can support me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/grizzly_coda" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2znn4km0i2jib7ru1sm9.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hetzner.cloud/?ref=EY14C8Tema9j" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyab43i0ysz9uwuq267u0.png" alt="Hetzner Referral"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://confdroid.substack.com/subscribe?params=%5Bobject%20Object%5D" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r49xyl05rwkjb52xbqg.png" alt="Substack"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://feedback.confdroid.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7d47hck6vziak35nfgf.png" alt="ConfDroid Feedback Portal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-pilot/" rel="noopener noreferrer"&gt;Confdroid Puppet Modules - Pilot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-puppet/" rel="noopener noreferrer"&gt;Confdroid Puppet Modules - Puppet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-resources/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - confdroid_resources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-postgresql/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Postgresql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-gitea/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Gitea&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-apache/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Apache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-nagios/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Nagios&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-fail2ban/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Fail2ban&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-automatic/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Automatic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-selinux/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Selinux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>confdroid</category>
      <category>nrpe</category>
      <category>puppet</category>
      <category>nagios</category>
    </item>
    <item>
      <title>ConfDroid Puppet Modules - Nagios</title>
      <dc:creator>12ww1160</dc:creator>
      <pubDate>Sat, 14 Mar 2026 19:19:22 +0000</pubDate>
      <link>https://forem.com/12ww1160/confdroid-puppet-modules-nagios-2997</link>
      <guid>https://forem.com/12ww1160/confdroid-puppet-modules-nagios-2997</guid>
      <description>&lt;h2&gt;
  
  
  Automating Nagios Monitoring with Puppet: Introducing confdroid_nagios
&lt;/h2&gt;

&lt;p&gt;Keeping an eye on servers, services, and applications remains essential in any infrastructure. While newer tools gain attention, classic threshold-based monitoring with Nagios still delivers reliable, straightforward alerting for many environments.&lt;/p&gt;

&lt;p&gt;The newly published &lt;strong&gt;confdroid_nagios&lt;/strong&gt; Puppet module brings full automation to Nagios server setups — especially in traditional VM, bare-metal, or hybrid infrastructures.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://sourcecode.confdroid.com/confdroid/confdroid_nagios" rel="noopener noreferrer"&gt;Source: https://sourcecode.confdroid.com/confdroid/confdroid_nagios&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What confdroid_nagios Delivers
&lt;/h2&gt;

&lt;p&gt;This module handles the complete installation and configuration of a Nagios server (or client nodes) on Rocky Linux 9 (with Puppet 8 compatibility in progress).&lt;/p&gt;

&lt;p&gt;Key highlights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Role-based deployment&lt;/strong&gt; — If a node's FQDN matches the configured &lt;code&gt;ng_nagios_server&lt;/code&gt;, it installs the full Nagios server stack. Otherwise, it deploys only client packages and NRPE (when enabled).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic configuration via PuppetDB&lt;/strong&gt; — Hosts, services, contacts, contact groups, host groups, service groups, commands, and templates are all managed through exported resources. Other confdroid modules (like &lt;a href="https://sourcecode.confdroid.com/confdroid/confdroid_apache" rel="noopener noreferrer"&gt;confdroid_apache&lt;/a&gt;) automatically export their monitored services — no manual host or check definitions needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure and clean setup&lt;/strong&gt; — Sets proper permissions, SELinux contexts, firewall rules, and creates a safe /etc/nagios/conf.d directory for any manual overrides without Puppet overwriting them.&lt;/li&gt;
&lt;li&gt;Integration features — Optional NRPE client setup (&lt;code&gt;ng_include_nrpe&lt;/code&gt;) and Fail2Ban jail for Nagios (&lt;code&gt;ng_enable_fail2ban&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Admin UI access&lt;/strong&gt; — Configures HTPasswd-based authentication with bcrypt-hashed passwords.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once deployed with a simple &lt;code&gt;include confdroid_nagios&lt;/code&gt; (and Hiera/ENC overrides for the server FQDN and credentials), Nagios stays current as your infrastructure changes — all driven by Puppet runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Threshold-Based vs. Metrics-Based Monitoring: A Quick Comparison
&lt;/h2&gt;

&lt;p&gt;Nagios (and similar tools like Icinga) and Prometheus + Grafana represent two different philosophies. Both have valid places in modern setups.&lt;/p&gt;

&lt;h3&gt;
  
  
  Threshold-Based Monitoring (Nagios, Icinga)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Approach&lt;/strong&gt; — Actively runs checks (plugins, NRPE, SNMP) against hosts/services at set intervals. Returns OK/WARNING/CRITICAL/UNKNOWN states based on predefined thresholds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strengths&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Excellent for uptime and availability alerting ("Is the web server responding? Is disk full?").&lt;/li&gt;
&lt;li&gt;Strong dependency handling, scheduled downtimes, and notification routing.&lt;/li&gt;
&lt;li&gt;Simple to understand and configure for traditional infrastructure.&lt;/li&gt;
&lt;li&gt;Very effective for mixed VM/metal environments where you want clear "something is broken" alerts.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Limitations&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Less suited for deep performance trending or high-cardinality data.&lt;/li&gt;
&lt;li&gt;No built-in long-term historical metrics storage or advanced querying.&lt;/li&gt;
&lt;li&gt;not very suitable for dynamic pods in Kubernetes&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Metrics-Based Monitoring (Prometheus + Grafana)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Approach&lt;/strong&gt; — Pulls time-series metrics from instrumented targets (exporters, app endpoints). Stores everything in a powerful time-series database. Uses PromQL for querying and Alertmanager for notifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strengths&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Ideal for cloud-native, Kubernetes, and microservices — automatic service discovery, rich labels, and rate-based alerting (errors/sec, latency p99).&lt;/li&gt;
&lt;li&gt;Deep historical analysis, anomaly detection, and beautiful dashboards via Grafana.&lt;/li&gt;
&lt;li&gt;Handles high-volume, high-cardinality data well (with proper federation/scaling).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Limitations&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Steeper learning curve (PromQL, recording rules, alerting rules).&lt;/li&gt;
&lt;li&gt;Less "out-of-the-box" for simple host/service availability without extra exporters.&lt;/li&gt;
&lt;li&gt;Operational overhead increases at very large scale without Thanos/Mimir.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  When to Choose Which (or Both)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;Nagios / confdroid_nagios-powered setups&lt;/strong&gt; for VM-heavy, bare-metal, or hybrid environments where clear, threshold-driven alerts and easy integration with existing Puppet workflows matter most.&lt;/li&gt;
&lt;li&gt;Choose Prometheus + Grafana for containerized, Kubernetes-native, or microservices-heavy stacks that demand detailed performance insights and trend analysis.&lt;/li&gt;
&lt;li&gt;Many teams run both — Nagios for critical "is it up?" paging alerts, Prometheus for capacity planning, SLO tracking, and debugging.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short: Nagios excels at "something failed — notify the right person now." Prometheus shines at "how is the system behaving over time — and why?"&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fktnbprnch4nfdgnl42u5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fktnbprnch4nfdgnl42u5.png" alt="Mermaid diagram" width="784" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started Today
&lt;/h2&gt;

&lt;p&gt;Deploying automated, zero-touch Nagios has never been easier in Puppet-managed environments.&lt;/p&gt;

&lt;p&gt;Add &lt;strong&gt;confdroid_nagios&lt;/strong&gt; via your Puppetfile or r10k:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;mod&lt;/span&gt; &lt;span class="s1"&gt;'confdroid_nagios'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;git: &lt;/span&gt;&lt;span class="s1"&gt;'https://sourcecode.confdroid.com/confdroid/confdroid_nagios.git'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then configure your Nagios server node and let exported resources do the rest.&lt;br&gt;
If you're tired of manual Nagios config files and love declarative infrastructure, give it a try. It pairs beautifully with the rest of the confdroid collection for a clean, automated monitoring foundation.&lt;br&gt;
Questions or feedback? The source is open — comments welcome!&lt;/p&gt;




&lt;p&gt;Did you find this post helpful?  You can support me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/grizzly_coda" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2znn4km0i2jib7ru1sm9.png" alt="" width="170" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hetzner.cloud/?ref=EY14C8Tema9j" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyab43i0ysz9uwuq267u0.png" alt="Hetzner Referral" width="400" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://confdroid.substack.com/subscribe?params=%5Bobject%20Object%5D" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r49xyl05rwkjb52xbqg.png" alt="Substack" width="250" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://feedback.confdroid.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7d47hck6vziak35nfgf.png" alt="ConfDroid Feedback Portal" width="300" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-pilot/" rel="noopener noreferrer"&gt;Confdroid Puppet Modules - Pilot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-puppet/" rel="noopener noreferrer"&gt;Confdroid Puppet Modules - Puppet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-resources/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - confdroid_resources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-postgresql/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Postgresql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-gitea/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Gitea&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-apache/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Apache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-nrpe/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - NRPE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-fail2ban/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Fail2ban&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-automatic/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Automatic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/confdroid-puppet-module-selinux/" rel="noopener noreferrer"&gt;ConfDroid Puppet Modules - Selinux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>confdroid</category>
      <category>apache</category>
      <category>puppet</category>
      <category>nagios</category>
    </item>
    <item>
      <title>Databases - Postgresql - PGbouncer</title>
      <dc:creator>12ww1160</dc:creator>
      <pubDate>Sat, 14 Mar 2026 16:30:45 +0000</pubDate>
      <link>https://forem.com/12ww1160/databases-postgresql-pgbouncer-2hg</link>
      <guid>https://forem.com/12ww1160/databases-postgresql-pgbouncer-2hg</guid>
      <description>&lt;h2&gt;
  
  
  Why PostgreSQL Needs a Connection Pooler – And How confdroid_pgbouncer Makes It Simple in Kubernetes
&lt;/h2&gt;

&lt;p&gt;In today’s cloud-native applications, PostgreSQL stands out as a reliable, powerful database. Yet one challenge almost every growing team runs into is managing database connections at scale.&lt;br&gt;
That’s exactly where PgBouncer shines — and why the &lt;strong&gt;confdroid_pgbouncer&lt;/strong&gt; container makes it effortless to deploy in Kubernetes.&lt;/p&gt;
&lt;h2&gt;
  
  
  The PostgreSQL Connection Problem
&lt;/h2&gt;

&lt;p&gt;PostgreSQL treats every client connection as a separate backend process. Each one needs memory, CPU, and authentication overhead. The database enforces a hard limit through the &lt;code&gt;max_connections&lt;/code&gt; setting (often 100 by default, though you can raise it).&lt;/p&gt;

&lt;p&gt;Raising that number too high quickly eats into server resources and hurts performance. When you raise the limit, you need adequate RAM memory. Consider the following calculation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Base memory per connection: Each connection uses ~10–15 MB of RAM for session overhead, even when idle.  This includes shared memory structures, connection state, and internal buffers.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;work_mem&lt;/code&gt; impact: The work_mem setting is allocated per operation (e.g., sort, hash), not per connection.  If a query performs multiple operations, memory usage scales accordingly. For example:&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;work_mem = 16MB&lt;/code&gt;, a single complex query might use up to 16MB × (number of sort/hash operations). In high-concurrency scenarios, total memory usage per 100 connections can be approximated as:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(100 connections × 15MB base) + (100 × work_mem × avg operations per query)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For moderate workloads (e.g., 1–2 operations per query), this may add 1.6–3.2 GB beyond the base overhead.&lt;/p&gt;
&lt;h2&gt;
  
  
  What Happens When Connections Run Out or Stay Idle Too Long
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;When connections run out&lt;/strong&gt;: New clients get the dreaded error “FATAL: sorry, too many clients already.” Applications fail, queues build up, and users see downtime — even when the database still has plenty of CPU and memory available.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When connections stay idle&lt;/strong&gt;: They continue to consume memory (typically 5–10 MB each) and hold open slots. During traffic spikes, those idle connections suddenly compete with active ones, turning a manageable situation into a crisis.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result? Unpredictable performance and constant firefighting.&lt;/p&gt;
&lt;h2&gt;
  
  
  Common Scaling Issues
&lt;/h2&gt;

&lt;p&gt;These problems show up in three typical scenarios:&lt;/p&gt;

&lt;p&gt;a) &lt;strong&gt;Many clients for one application&lt;/strong&gt;&lt;br&gt;
A popular web app or API with thousands of concurrent users (or many pods) can easily exhaust the database. Even built-in application pools multiply quickly across instances.&lt;br&gt;
b) &lt;strong&gt;Many applications with limited or many clients&lt;/strong&gt;&lt;br&gt;
Microservices architectures are a classic example. When 15–30 different services each maintain their own connection pool to the same PostgreSQL instance, the total connection count explodes — often with lots of idle waste.&lt;br&gt;
c) &lt;strong&gt;Read- and write demand&lt;/strong&gt;&lt;br&gt;
Writes must hit the primary database, while reads can go to replicas. Without smart routing and pooling, teams end up with complicated application logic, separate connection strings, and uneven load across the cluster.&lt;/p&gt;

&lt;p&gt;These are true already for smaller environments. When it comes to big solutions scaling, the total amount of layers for performance tuning are growing rapidly.&lt;/p&gt;
&lt;h2&gt;
  
  
  PgBouncer: The Lightweight Solution
&lt;/h2&gt;

&lt;p&gt;PgBouncer sits between your applications and PostgreSQL as a fast, efficient proxy. Instead of letting every client open its own direct connection, it reuses a small, controlled pool of real database connections.&lt;/p&gt;

&lt;p&gt;Key wins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Far fewer actual connections to PostgreSQL&lt;/li&gt;
&lt;li&gt;Instant connection reuse (no repeated authentication)&lt;/li&gt;
&lt;li&gt;Built-in queuing for spikes&lt;/li&gt;
&lt;li&gt;Support for transaction pooling (perfect for most web workloads), session pooling (see my &lt;a href="https://confdroid.com/2026/03/db-postgres-gitea-pgbouncer/" rel="noopener noreferrer"&gt;recent post about gitea and pgbouncer&lt;/a&gt;) or statement pooling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The database stays happy, performance improves, and scaling becomes predictable. Fine-grained tuning becomes snappy.&lt;/p&gt;
&lt;h2&gt;
  
  
  confdroid_pgbouncer: Ready-to-Run in Kubernetes
&lt;/h2&gt;

&lt;p&gt;To make PgBouncer truly Kubernetes-native, a clean container solution was built: &lt;strong&gt;confdroid_pgbouncer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Highlights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Small Debian-based image (around 47 MB)&lt;/li&gt;
&lt;li&gt;Runs PgBouncer 1.24.1 as a non-root user (the official binaries)&lt;/li&gt;
&lt;li&gt;Designed as a standalone service&lt;/li&gt;
&lt;li&gt;Supports multiple instances running in parallel — each fully managing connections independently but using the exact same configuration manifest&lt;/li&gt;
&lt;li&gt;Standard port 6432 with built-in health checks&lt;/li&gt;
&lt;li&gt;Easy horizontal scaling and high availability&lt;/li&gt;
&lt;li&gt;allows protecting connections via TLS at different levels between client &amp;lt;=&amp;gt; bouncer and serer &amp;lt;=&amp;gt; bouncer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Get it here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Source code:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sourcecode.confdroid.com/confdroid/confdroid_pgbouncer" rel="noopener noreferrer"&gt;https://sourcecode.confdroid.com/confdroid/confdroid_pgbouncer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Container image:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sourcecode.confdroid.com/confdroid/-/packages/container/confdroid_pgbouncer/latest" rel="noopener noreferrer"&gt;https://sourcecode.confdroid.com/confdroid/-/packages/container/confdroid_pgbouncer/latest&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pull it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull sourcecode.confdroid.com/confdroid/confdroid_pgbouncer:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why This Approach Fits Modern Stacks
&lt;/h2&gt;

&lt;p&gt;Because every instance uses the same manifest-driven configuration, you get perfect consistency across replicas — ideal for GitOps workflows. It integrates smoothly with load balancers, monitoring, and the rest of the confdroid collection.&lt;/p&gt;

&lt;p&gt;Often, the bouncer is running on the same node as the postgres instance. But for one it adds load to the server, for two that does not allow loadbalancing between several server instances.&lt;/p&gt;

&lt;p&gt;Using PGbouncer as standalone service in Kubernetes or similar cluster solutions allows centralized loadbalancing without even ever having to touch Postgres for reconfiguring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Adding a proper connection pooler like PgBouncer is one of the highest-return improvements you can make for any PostgreSQL deployment. It protects your database, boosts performance, and removes a major scaling headache.&lt;/p&gt;

&lt;p&gt;If you’re running PostgreSQL standalone or in Kubernetes (or planning to), try &lt;strong&gt;confdroid_pgbouncer&lt;/strong&gt; today. It takes minutes to set up and delivers immediate relief.&lt;/p&gt;

&lt;p&gt;Have you hit connection limits before? Drop a comment or leave it at the &lt;a href="https://feedback.confdroid.com/" rel="noopener noreferrer"&gt;Confdroid Feedback Portal&lt;/a&gt; — I’d love to hear what worked for you!&lt;/p&gt;




&lt;p&gt;Did you find this post helpful?  You can support me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/grizzly_coda" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2znn4km0i2jib7ru1sm9.png" alt="" width="170" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hetzner.cloud/?ref=EY14C8Tema9j" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyab43i0ysz9uwuq267u0.png" alt="Hetzner Referral" width="400" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://confdroid.substack.com/subscribe?params=%5Bobject%20Object%5D" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r49xyl05rwkjb52xbqg.png" alt="Substack" width="250" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://feedback.confdroid.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7d47hck6vziak35nfgf.png" alt="ConfDroid Feedback Portal" width="300" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/db-postgres-pilot/" rel="noopener noreferrer"&gt;Databases - Postgresql - Pilot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confdroid.com/db-postgres-gitea-pgbouncer/" rel="noopener noreferrer"&gt;Databases - Postgresql - Gitea and PGBouncer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>postgres</category>
      <category>database</category>
      <category>devops</category>
      <category>pgbouncer</category>
    </item>
  </channel>
</rss>
