<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Home on Matheus Thurler</title><link>https://matheusthurler.com.br/</link><description>Recent content in Home on Matheus Thurler</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Mon, 16 Mar 2026 10:00:00 -0300</lastBuildDate><atom:link href="https://matheusthurler.com.br/index.xml" rel="self" type="application/rss+xml"/><item><title>The End of 'It Works on My Machine': How Distrobox Saves Your PC!</title><link>https://matheusthurler.com.br/posts/distrobox-end-of-works-on-my-machine/</link><pubDate>Mon, 16 Mar 2026 10:00:00 -0300</pubDate><guid>https://matheusthurler.com.br/posts/distrobox-end-of-works-on-my-machine/</guid><description>&lt;p&gt;Have you ever experienced the frustration of having to install an older version of Python to maintain a legacy project, and then immediately needing the latest version of Node.js for another project, only to see your system packages conflict?&lt;/p&gt;
&lt;p&gt;Your local machine, once clean and sacred, begins to turn into the famous &lt;strong&gt;&amp;ldquo;it works on my machine&amp;rdquo;&lt;/strong&gt; scenario. Full of broken PPAs, version managers fighting each other, and accumulated junk.&lt;/p&gt;</description></item><item><title>How to Install Apache CloudStack with Ansible - Video Tutorial</title><link>https://matheusthurler.com.br/posts/cloudstack-ansible-video-tutorial/</link><pubDate>Wed, 28 Jan 2026 00:00:00 -0300</pubDate><guid>https://matheusthurler.com.br/posts/cloudstack-ansible-video-tutorial/</guid><description>&lt;p&gt;If you want to learn how to install &lt;strong&gt;Apache CloudStack&lt;/strong&gt; in an automated way using &lt;strong&gt;Ansible&lt;/strong&gt;, I&amp;rsquo;ve prepared a complete video tutorial showing the entire process step by step.&lt;/p&gt;
&lt;h2 id="what-you-will-learn"&gt;What you will learn&lt;/h2&gt;
&lt;p&gt;In this video tutorial, I demonstrate in practice how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;🚀 Set up the environment for CloudStack installation&lt;/li&gt;
&lt;li&gt;⚙️ Use Ansible to automate the entire installation&lt;/li&gt;
&lt;li&gt;🗄️ Configure MySQL Server for CloudStack&lt;/li&gt;
&lt;li&gt;📦 Configure NFS for Primary and Secondary Storage&lt;/li&gt;
&lt;li&gt;🖥️ Install and configure the Management Server&lt;/li&gt;
&lt;li&gt;🔧 Download and configure System VM Templates&lt;/li&gt;
&lt;li&gt;✅ Validate the installation and access the web interface&lt;/li&gt;
&lt;li&gt;☸️ &lt;strong&gt;Live Demo:&lt;/strong&gt; Install a Kubernetes cluster using CloudStack CKS&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-automate-with-ansible"&gt;Why automate with Ansible?&lt;/h2&gt;
&lt;p&gt;Manual CloudStack installation is a complex process that can take hours and is prone to errors. With Ansible, you can:&lt;/p&gt;</description></item><item><title>Is NGINX Ingress Controller Dead? Meet NGINX Gateway Fabric</title><link>https://matheusthurler.com.br/posts/nginx-gateway-api-kubernetes/</link><pubDate>Sat, 06 Dec 2025 00:00:00 -0300</pubDate><guid>https://matheusthurler.com.br/posts/nginx-gateway-api-kubernetes/</guid><description>&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/GbNccjPmavI?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;

&lt;p&gt;If you work with Kubernetes, you&amp;rsquo;ve probably used or at least heard of the &lt;strong&gt;NGINX Ingress Controller&lt;/strong&gt;. For a long time, it was the default choice for exposing applications to the outside world. But recently, F5 (owner of NGINX) announced the &lt;strong&gt;deprecation&lt;/strong&gt; of the project.&lt;/p&gt;</description></item><item><title>Nginx vs Traefik vs Caddy: Which Reverse Proxy to Choose?</title><link>https://matheusthurler.com.br/posts/nginx-vs-traefik-vs-caddy/</link><pubDate>Wed, 26 Nov 2025 00:00:00 -0300</pubDate><guid>https://matheusthurler.com.br/posts/nginx-vs-traefik-vs-caddy/</guid><description>&lt;p&gt;Choosing the right &lt;strong&gt;Reverse Proxy&lt;/strong&gt; is one of the first and most important decisions when building a Homelab or setting up a production infrastructure. It is the gateway to your services, responsible for routing, SSL termination, and security.&lt;/p&gt;
&lt;p&gt;For years, &lt;strong&gt;Nginx&lt;/strong&gt; has been the undisputed king. But recently, &amp;ldquo;Cloud Native&amp;rdquo; options like &lt;strong&gt;Traefik&lt;/strong&gt; and modern simplifiers like &lt;strong&gt;Caddy&lt;/strong&gt; have gained massive popularity.&lt;/p&gt;
&lt;p&gt;In this post, we will compare these three giants to help you decide which one is best for your use case.&lt;/p&gt;</description></item><item><title>Goodbye Proxmox? Why I Migrated My Homelab to Apache CloudStack</title><link>https://matheusthurler.com.br/posts/about-my-homelab/</link><pubDate>Mon, 24 Nov 2025 00:00:00 -0300</pubDate><guid>https://matheusthurler.com.br/posts/about-my-homelab/</guid><description>&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/BB7wloVn3WE?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;

&lt;p&gt;Are you still managing your VMs on Proxmox? If you&amp;rsquo;re looking to advance your cloud computing studies and get closer to real enterprise environments, it might be time to rethink your virtualization stack. In this post, I&amp;rsquo;ll share the reasons that led me to migrate my homelab from Proxmox and OpenStack to &lt;strong&gt;Apache CloudStack&lt;/strong&gt;, and how this decision transformed my learning experience.&lt;/p&gt;</description></item><item><title>Simplify Your Projects: How to Use GitHub Template Repositories</title><link>https://matheusthurler.com.br/posts/github-template-repositories/</link><pubDate>Tue, 18 Nov 2025 00:00:00 -0300</pubDate><guid>https://matheusthurler.com.br/posts/github-template-repositories/</guid><description>&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/Q4nsWELn4mg?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;

&lt;p&gt;🚀 Tired of setting up projects from scratch and copying and pasting the same CI/CD workflow files over and over? No more rework! In this post, we&amp;rsquo;ll solve this problem once and for all using &lt;strong&gt;GitHub Template Repositories&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="the-problem-constant-rework"&gt;The Problem: Constant Rework&lt;/h2&gt;
&lt;p&gt;Every time you start a new project, you need to:&lt;/p&gt;</description></item><item><title>GitHub Actions Matrix Strategy: Testing Multiple Versions Simultaneously</title><link>https://matheusthurler.com.br/posts/github-actions-matrix-strategy/</link><pubDate>Sun, 24 Aug 2025 00:00:00 -0300</pubDate><guid>https://matheusthurler.com.br/posts/github-actions-matrix-strategy/</guid><description>&lt;p&gt;Testing your code on just one version of Node.js, Python, or Ruby is risky. What if your code breaks on Python 3.9 but works on 3.12? What if there are Windows-specific bugs you don&amp;rsquo;t catch on Linux? &lt;strong&gt;GitHub Actions Matrix Strategy&lt;/strong&gt; solves this elegantly.&lt;/p&gt;
&lt;h2 id="the-problem-multi-version-compatibility"&gt;The Problem: Multi-Version Compatibility&lt;/h2&gt;
&lt;p&gt;Imagine this common scenario:&lt;/p&gt;
&lt;div
 class="code-block-container border-border bg-card my-6 overflow-hidden rounded-xl border shadow-sm transition-all duration-200 ease-out hover:-translate-y-0.5 hover:shadow-md"&gt;
 
 &lt;div
 class="code-block-header bg-muted/30 border-border flex items-center justify-between border-b px-4 py-3"&gt;
 
 &lt;div class="flex items-center gap-2"&gt;
 &lt;div class="text-muted-foreground flex-shrink-0"&gt;
 
 &lt;svg class="h-4 w-4"
 fill="none"
 stroke="currentColor"
 viewBox="0 0 24 24"&gt;&lt;path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" /&gt;
&lt;/svg&gt;
 &lt;/div&gt;
 &lt;span class="text-muted-foreground text-sm font-medium"&gt;
 YAML
 &lt;/span&gt;
 &lt;/div&gt;

 
 &lt;div class="flex items-center gap-2"&gt;
 &lt;button
 class="collapse-code-btn text-muted-foreground hover:text-primary hover:bg-primary/10 focus:ring-primary/20 flex items-center gap-1.5 rounded-md px-2 py-1 text-xs font-medium transition-all duration-200 ease-out focus:ring-2 focus:outline-none"
 data-code-id="code-0"
 data-default-state="expanded"
 data-collapsed="false"
 data-auto-collapse-lines="30"
 data-auto-collapse-height="400"
 data-collapsed-height="120"
 title="Collapse"
 aria-label="Collapse"&gt;
 &lt;span class="collapse-icon"&gt;
 
 &lt;svg class="h-3 w-3"
 fill="none"
 stroke="currentColor"
 viewBox="0 0 24 24"&gt;&lt;path fill="currentColor" d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6l-6 6z"/&gt;&lt;/svg&gt;
 &lt;/span&gt;
 &lt;span class="collapse-text hidden sm:inline"
 &gt;Collapse&lt;/span
 &gt;
 &lt;/button&gt;
 &lt;button
 class="copy-code-btn text-muted-foreground hover:text-primary hover:bg-primary/10 focus:ring-primary/20 flex items-center gap-1.5 rounded-md px-2 py-1 text-xs font-medium transition-all duration-200 ease-out focus:ring-2 focus:outline-none"
 data-code-id="code-0"
 title="Copy"
 aria-label="Copy"&gt;
 &lt;span class="copy-icon"&gt;
 
 &lt;svg class="h-3 w-3"
 fill="none"
 stroke="currentColor"
 viewBox="0 0 24 24"&gt;&lt;path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" /&gt;
&lt;/svg&gt;
 &lt;/span&gt;
 &lt;span class="copy-text hidden sm:inline"
 &gt;Copy&lt;/span
 &gt;
 &lt;/button&gt;
 &lt;/div&gt;
 &lt;/div&gt;

 
 &lt;div class="code-block-content relative" id="code-0"&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Simple workflow&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;runs-on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/checkout@v4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/setup-node@v4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;node-version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;20&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;npm test&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 
 &lt;div
 class="collapse-overlay to-card/90 pointer-events-none absolute inset-0 bg-gradient-to-b from-transparent via-transparent opacity-0 transition-opacity duration-300"&gt;
 &lt;div
 class="text-muted-foreground bg-card/80 border-border/50 hover:bg-primary/10 hover:text-primary hover:border-primary/30 absolute bottom-4 left-1/2 -translate-x-1/2 cursor-pointer rounded-full border px-3 py-1.5 text-xs backdrop-blur-sm transition-all duration-200"&gt;
 Click to expand and view more
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;/div&gt;
&lt;/div&gt;


&lt;script&gt;
(function() {
 const codeId = 'code-0';
 const copyBtn = document.querySelector('.copy-code-btn[data-code-id="' + codeId + '"]');
 const collapseBtn = document.querySelector('.collapse-code-btn[data-code-id="' + codeId + '"]');
 const codeContainer = document.getElementById(codeId);

 if (!codeContainer) return;

 
 if (copyBtn) {
 const copyIcon = copyBtn.querySelector('.copy-icon');
 const copyText = copyBtn.querySelector('.copy-text');

 copyBtn.addEventListener('click', async function() {
 try {
 
 let codeText = '';

 
 const codeTableCell = codeContainer.querySelector('.lntd:last-child code');
 if (codeTableCell) {
 codeText = codeTableCell.textContent || codeTableCell.innerText;
 } else {
 
 const codeElement = codeContainer.querySelector('code');
 if (codeElement) {
 
 const hasInlineLineNumbers = codeElement.querySelector('.ln');
 if (hasInlineLineNumbers) {
 
 const codeLines = codeElement.querySelectorAll('.cl');
 if (codeLines.length &gt; 0) {
 codeText = Array.from(codeLines)
 .map(line =&gt; {
 const text = line.textContent || line.innerText;
 
 return text.replace(/\n+$/, '');
 })
 .join('\n')
 .replace(/\n+$/, ''); 
 } else {
 
 const allText = codeElement.textContent || codeElement.innerText;
 codeText = allText.replace(/^\d+/gm, '').replace(/^\s+/gm, '');
 }
 } else {
 
 codeText = codeElement.textContent || codeElement.innerText;
 }
 } else {
 
 codeText = codeContainer.textContent || codeContainer.innerText;
 }
 }

 
 codeText = codeText.trim();

 
 await navigator.clipboard.writeText(codeText);

 
 copyIcon.innerHTML = `\n \u003csvg class=\u0022h-3 w-3\u0022\n fill=\u0022none\u0022\n stroke=\u0022currentColor\u0022\n viewBox=\u00220 0 24 24\u0022\u003e\u003cpath stroke-linecap=\u0022round\u0022 stroke-linejoin=\u0022round\u0022 stroke-width=\u00222\u0022 d=\u0022M5 13l4 4L19 7\u0022 \/\u003e\n\u003c\/svg\u003e`;
 if (copyText) {
 copyText.textContent = 'Copied';
 }
 copyBtn.classList.add('text-green-600');

 
 setTimeout(() =&gt; {
 copyIcon.innerHTML = `\n \u003csvg class=\u0022h-3 w-3\u0022\n fill=\u0022none\u0022\n stroke=\u0022currentColor\u0022\n viewBox=\u00220 0 24 24\u0022\u003e\u003cpath stroke-linecap=\u0022round\u0022 stroke-linejoin=\u0022round\u0022 stroke-width=\u00222\u0022 d=\u0022M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\u0022 \/\u003e\n\u003c\/svg\u003e`;
 if (copyText) {
 copyText.textContent = 'Copy';
 }
 copyBtn.classList.remove('text-green-600');
 }, 2000);

 } catch (err) {
 console.error('复制失败:', err);

 
 const range = document.createRange();
 const codeElement = codeContainer.querySelector('code') || codeContainer;
 range.selectNodeContents(codeElement);
 const selection = window.getSelection();
 selection.removeAllRanges();
 selection.addRange(range);

 
 if (copyText) {
 copyText.textContent = 'Selected';
 }

 setTimeout(() =&gt; {
 if (copyText) {
 copyText.textContent = 'Copy';
 }
 selection.removeAllRanges();
 }, 2000);
 }
 });
 }

 
 if (collapseBtn) {
 const collapseIcon = collapseBtn.querySelector('.collapse-icon');
 const collapseText = collapseBtn.querySelector('.collapse-text');
 const collapseOverlay = codeContainer.querySelector('.collapse-overlay');

 
 let codeElement = codeContainer.querySelector('pre.chroma');
 if (!codeElement) {
 codeElement = codeContainer.querySelector('pre');
 }

 const defaultState = collapseBtn.dataset.defaultState || 'expanded';
 const isCollapsedAttr = collapseBtn.dataset.collapsed === 'true';
 const autoCollapseLines = parseInt(collapseBtn.dataset.autoCollapseLines) || 30;
 const autoCollapseHeight = parseInt(collapseBtn.dataset.autoCollapseHeight) || 400;
 const collapsedHeight = parseInt(collapseBtn.dataset.collapsedHeight) || 120;

 let isCollapsed = false;

 
 function initCollapse() {
 
 const shouldCollapse = isCollapsedAttr ||
 defaultState === 'collapsed' ||
 shouldAutoCollapse();

 if (shouldCollapse) {
 setCollapsed(true, false); 
 }
 }

 function shouldAutoCollapse() {
 
 if (codeElement) {
 const lines = codeElement.querySelectorAll('.line, .cl');
 const height = codeElement.offsetHeight;
 return lines.length &gt; autoCollapseLines || height &gt; autoCollapseHeight;
 }

 
 const containerHeight = codeContainer.offsetHeight;
 if (containerHeight &gt; autoCollapseHeight) {
 return true;
 }

 
 const textContent = codeContainer.textContent || codeContainer.innerText || '';
 const estimatedLines = textContent.split('\n').length;
 return estimatedLines &gt; autoCollapseLines;
 }

 function setCollapsed(collapsed, animate = true) {
 if (!collapseOverlay) return;

 isCollapsed = collapsed;

 if (collapsed) {
 
 codeContainer.style.maxHeight = collapsedHeight + 'px';
 codeContainer.style.overflow = 'hidden';
 collapseOverlay.style.opacity = '1';
 collapseOverlay.style.pointerEvents = 'auto';

 
 collapseIcon.innerHTML = `\n \u003csvg class=\u0022h-3 w-3\u0022\n fill=\u0022none\u0022\n stroke=\u0022currentColor\u0022\n viewBox=\u00220 0 24 24\u0022\u003e\u003cpath stroke-linecap=\u0022round\u0022 stroke-linejoin=\u0022round\u0022 stroke-width=\u00222\u0022 d=\u0022M19 9l-7 7-7-7\u0022 \/\u003e\n\u003c\/svg\u003e`;
 if (collapseText) {
 collapseText.textContent = 'Expand';
 }
 collapseBtn.title = 'Expand';

 } else {
 
 codeContainer.style.maxHeight = '';
 codeContainer.style.overflow = '';
 collapseOverlay.style.opacity = '0';
 collapseOverlay.style.pointerEvents = 'none';

 
 collapseIcon.innerHTML = `\n \u003csvg class=\u0022h-3 w-3\u0022\n fill=\u0022none\u0022\n stroke=\u0022currentColor\u0022\n viewBox=\u00220 0 24 24\u0022\u003e\u003cpath fill=\u0022currentColor\u0022 d=\u0022M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6l-6 6z\u0022\/\u003e\u003c\/svg\u003e`;
 if (collapseText) {
 collapseText.textContent = 'Collapse';
 }
 collapseBtn.title = 'Collapse';
 }

 
 if (animate) {
 codeContainer.style.transition = 'max-height 0.3s ease-out';
 setTimeout(() =&gt; {
 codeContainer.style.transition = '';
 }, 300);
 }
 }

 function toggleCollapse() {
 setCollapsed(!isCollapsed, true);
 }

 
 collapseBtn.addEventListener('click', toggleCollapse);

 
 if (collapseOverlay) {
 collapseOverlay.addEventListener('click', () =&gt; {
 if (isCollapsed) {
 setCollapsed(false, true);
 }
 });
 }

 
 initCollapse();
 }
})();
&lt;/script&gt;
&lt;p&gt;&lt;strong&gt;Problems:&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>MASTER Reusable Workflows and Say GOODBYE to Copy-Paste in Your CI/CD!</title><link>https://matheusthurler.com.br/posts/reusable-workflows-github-actions/</link><pubDate>Tue, 24 Jun 2025 00:00:00 -0300</pubDate><guid>https://matheusthurler.com.br/posts/reusable-workflows-github-actions/</guid><description>&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/E-EvR4fykIc?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;

&lt;p&gt;If you work with CI/CD on GitHub Actions, you&amp;rsquo;ve probably found yourself copying and pasting the same YAML code between different workflows. What if I told you there&amp;rsquo;s a much more elegant and professional way to do this? In this post, I&amp;rsquo;ll show you how &lt;strong&gt;Reusable Workflows&lt;/strong&gt; can revolutionize your CI/CD pipeline.&lt;/p&gt;</description></item><item><title>Privacy Policy</title><link>https://matheusthurler.com.br/privacy/</link><pubDate>Mon, 01 Jan 2024 00:00:00 -0300</pubDate><guid>https://matheusthurler.com.br/privacy/</guid><description>&lt;p&gt;&lt;strong&gt;Last updated: November 19, 2025&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At &lt;strong&gt;Matheus Thurler&lt;/strong&gt; (accessible from &lt;a href="https://matheusthurler.com.br/%29"target="_blank"
 class="inline-flex items-center gap-1"
&gt;https://matheusthurler.com.br/)
 &lt;svg id="external-link" class="h-3 w-3 flex-shrink-0"
 fill="none"
 stroke="currentColor"
 viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 3h6v6m-11 5L21 3m-3 10v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/&gt;&lt;/svg&gt;
&lt;/a&gt;, one of our main priorities is the privacy of our visitors. This Privacy Policy document contains types of information that is collected and recorded by Matheus Thurler and how we use it.&lt;/p&gt;</description></item><item><title>Terms of Service</title><link>https://matheusthurler.com.br/terms/</link><pubDate>Mon, 01 Jan 2024 00:00:00 -0300</pubDate><guid>https://matheusthurler.com.br/terms/</guid><description>&lt;p&gt;&lt;strong&gt;Last updated: November 19, 2025&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="1-terms"&gt;1. Terms&lt;/h2&gt;
&lt;p&gt;By accessing this Website, accessible from &lt;a href="https://matheusthurler.com.br/"target="_blank"
 class="inline-flex items-center gap-1"
&gt;https://matheusthurler.com.br/
 &lt;svg id="external-link" class="h-3 w-3 flex-shrink-0"
 fill="none"
 stroke="currentColor"
 viewBox="0 0 24 24"&gt;&lt;path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 3h6v6m-11 5L21 3m-3 10v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/&gt;&lt;/svg&gt;
&lt;/a&gt;, you are agreeing to be bound by these Website Terms and Conditions of Use and agree that you are responsible for the agreement with any applicable local laws. If you disagree with any of these terms, you are prohibited from accessing this site. The materials contained in this Website are protected by copyright and trade mark law.&lt;/p&gt;</description></item><item><title>About</title><link>https://matheusthurler.com.br/about/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://matheusthurler.com.br/about/</guid><description>&lt;h2 id="about-me"&gt;About Me&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m Matheus Thurler, a passionate and experienced professional in the field of technology, with a strong focus on DevOps, cloud computing, and software development. My journey in IT began in 2012, and since then, I&amp;rsquo;ve been dedicated to continuous learning and applying best practices to deliver robust and scalable solutions.&lt;/p&gt;
&lt;h2 id="my-expertise"&gt;My Expertise&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DevOps &amp;amp; Cloud:&lt;/strong&gt; Extensive experience with AWS, Azure, and Google Cloud Platform, implementing CI/CD pipelines, infrastructure as code (Terraform, CloudFormation), and containerization (Docker, Kubernetes).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Programming Languages:&lt;/strong&gt; Proficient in Python, Go, Java, and JavaScript, with a solid understanding of object-oriented programming and functional paradigms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Databases:&lt;/strong&gt; Experience with relational databases (PostgreSQL, MySQL) and NoSQL databases (MongoDB, DynamoDB).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitoring &amp;amp; Logging:&lt;/strong&gt; Implementation of monitoring solutions (Prometheus, Grafana) and centralized logging (ELK Stack, Splunk).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agile Methodologies:&lt;/strong&gt; Strong advocate for Agile principles, working with Scrum and Kanban to foster collaboration and iterative development.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="my-mission"&gt;My Mission&lt;/h2&gt;
&lt;p&gt;My goal is to leverage my technical skills and experience to help organizations build efficient, reliable, and secure systems. I believe in sharing knowledge and contributing to the community, which is why I maintain this blog to discuss technology, programming, and DevOps topics.&lt;/p&gt;</description></item><item><title>Links</title><link>https://matheusthurler.com.br/links/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://matheusthurler.com.br/links/</guid><description/></item></channel></rss>