<?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 slefhost.casa</title><link>https://selfhost.casa/</link><description>Recent content in Home on slefhost.casa</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Thu, 18 Sep 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://selfhost.casa/index.xml" rel="self" type="application/rss+xml"/><item><title>Cloudflare load balancer for home lab services</title><link>https://selfhost.casa/posts/cloudflare-load-balancer-for-home-lab-services/</link><pubDate>Thu, 18 Sep 2025 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/cloudflare-load-balancer-for-home-lab-services/</guid><description>&lt;h1 id="cloudflare-lb-setup">Cloudflare LB Setup&lt;/h1>
&lt;p>Traffic -&amp;gt; Load Balancing -&amp;gt; Create Load Balancer (paid feature)
Each tunnel you created in the first step was assigned an origin address, which you&amp;rsquo;ll use here for the two orgins in your load balancer. I&amp;rsquo;ve set each to 50%, alternating each request evenly between the two tunnels. The hostname of your load balancer will be the endpoint that you can use for other CNAMEs as you add ingress rules for local services you want to host or expose. To ensure your LB groups show as healthy, add in the healthcheck endpoint defined in your ingress rules, which should look like this &lt;a href="https://lb-hostname.domain.net/check">https://lb-hostname.domain.net/check&lt;/a> I find this setup to be my preference vs hosting my own Traefik proxy (or similar) since I do not need to open up any ports on my firewall.

&lt;figure class="image-figure not-prose my-8" 
 data-lightbox-enabled="false"
 data-gallery-type="auto">
 &lt;div class="image-container">
 &lt;img
 src="https://selfhost.casa/posts/cloudflare-load-balancer-for-home-lab-services/lb1.png"
 alt="cloudflare load balancer"
 
 
 
 
 
 width="1501"
 height="848"
 
 
 
 loading="lazy"
 decoding="async"
 data-gallery-src="https://selfhost.casa/posts/cloudflare-load-balancer-for-home-lab-services/lb1.png"
 data-gallery-alt="cloudflare load balancer"
 data-gallery-title="" />&lt;/div>

 &lt;/figure>&lt;/p></description></item><item><title>Configure Split DNS with Tailscale and Local DNS</title><link>https://selfhost.casa/posts/configure-split-dns-with-tailscale-and-local-dns/</link><pubDate>Fri, 08 Aug 2025 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/configure-split-dns-with-tailscale-and-local-dns/</guid><description>&lt;p>asd Tailscale is a fantastic tool for securely accessing all your systems and applications remotely.
However, it does come with some trade-offs — especially when it comes to DNS. By default, Tailscale takes over your system’s DNS settings. While non-Tailscale domains are generally forwarded to your local resolver, that behavior depends on Tailscale functioning correctly.&lt;/p>
&lt;p>Recently, I ran into an issue where one of my nodes had an expired key and couldn’t connect to the tailnet anymore. As a result, all DNS queries on that system failed, even for unrelated domains.&lt;/p></description></item><item><title>Deploying a Hugo Site with Cloudflare Workers</title><link>https://selfhost.casa/posts/deploying-a-hugo-site-with-cloudflare-workers/</link><pubDate>Sun, 20 Jul 2025 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/deploying-a-hugo-site-with-cloudflare-workers/</guid><description>&lt;p>I recently migrated my blog from Jekyll to Hugo — more on that soon. As part of the migration, I needed to set up deployments to Cloudflare. I typically use Cloudflare Pages, but when I went to configure it, I was met with a notice recommending Cloudflare Workers for new projects.&lt;/p>
&lt;p>While Cloudflare hasn’t explicitly stated the future of Pages, it’s clear that the focus and innovation are shifting toward Workers.&lt;/p></description></item><item><title>Managing Portainer Stacks Using GitOps</title><link>https://selfhost.casa/posts/managing-portainer-stacks-using-gitops/</link><pubDate>Mon, 07 Jul 2025 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/managing-portainer-stacks-using-gitops/</guid><description>&lt;p>Container orchestration can quickly become complex as your infrastructure grows. By combining Portainer’s intuitive UI with a GitOps workflow, you can declaratively manage your Docker stacks and enjoy both transparency and reproducibility. In this post, we’ll walk through the process of installing Portainer, configuring GitOps using a Git repository, and automating deployments of your Docker stacks.&lt;/p>
&lt;h2 id="why-gitops-with-portainer">Why GitOps with Portainer?&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Declarative Infrastructure&lt;/strong>: Store your stack definitions (Compose files, environment variables, configs) in Git — your single source of truth.&lt;/li>
&lt;li>&lt;strong>Version Control &amp;amp; Auditability&lt;/strong>: Every change is tracked, making rollbacks and audits straightforward.&lt;/li>
&lt;li>&lt;strong>Self-Service Deployments&lt;/strong>: Propose changes via pull requests, fostering collaboration and code review.&lt;/li>
&lt;li>&lt;strong>Automated Sync&lt;/strong>: Portainer’s GitOps integration will automatically reconcile your live environment with the desired state in Git.&lt;/li>
&lt;/ul>
&lt;h2 id="install-portainer">Install Portainer&lt;/h2>
&lt;p>The first step is to install Portainer on the host where you plan to manage your Docker Compose stacks.&lt;/p></description></item><item><title>Ansible Essentials Managing Secrets with Vault</title><link>https://selfhost.casa/posts/ansible-essentials-managing-secrets-with-vault/</link><pubDate>Thu, 29 May 2025 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/ansible-essentials-managing-secrets-with-vault/</guid><description>&lt;p>Storing API keys, tokens, and passwords in your playbooks isn’t safe—especially if you keep your Ansible project in version control. That’s where &lt;strong>Ansible Vault&lt;/strong> comes in. It lets you encrypt sensitive variables while still using them like any other part of your automation.&lt;/p>
&lt;p>In this third part of the series, I’ll show you how I use Vault to securely manage secrets in my homelab setup. In this example, we’ll use Vault to store a Tailscale auth key, which one of my roles uses to authenticate a server into my private Tailscale network.&lt;/p></description></item><item><title>Remote Packet Capture with Wireshark</title><link>https://selfhost.casa/posts/remote-packet-capture-with-wireshark/</link><pubDate>Mon, 26 May 2025 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/remote-packet-capture-with-wireshark/</guid><description>&lt;p>This guide explains how to configure &lt;strong>Wireshark&lt;/strong> for remote packet capture over &lt;strong>SSH&lt;/strong> using &lt;code>tcpdump&lt;/code>.&lt;/p>
&lt;h2 id="prerequisites">Prerequisites&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Wireshark installed&lt;/strong> on your local machine.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>SSH access&lt;/strong> to the remote host:&lt;/p>
&lt;ul>
&lt;li>Either standard SSH with &lt;code>sudo&lt;/code> privileges, &lt;strong>or&lt;/strong>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;code>tcpdump&lt;/code> installed on the remote host.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="configuring-remote-capture-in-wireshark">Configuring Remote Capture in Wireshark&lt;/h2>
&lt;h3 id="steps-in-wireshark">Steps in Wireshark&lt;/h3>
&lt;ol>
&lt;li>
&lt;p>Navigate to: &lt;code>Capture&lt;/code> ? &lt;code>Options&lt;/code> ? &lt;code>Manage Interfaces&lt;/code>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Click the options icon next to &lt;strong>SSH Remote Capture&lt;/strong>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Enter the interface details:&lt;/p></description></item><item><title>Ansible Essentials Playbooks, Roles &amp; Handlers</title><link>https://selfhost.casa/posts/ansible-essentials-playbooks-roles-handlers/</link><pubDate>Mon, 19 May 2025 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/ansible-essentials-playbooks-roles-handlers/</guid><description>&lt;p>In this part of the Ansible series, you’ll learn how to automate routine system maintenance tasks like updating packages and rebooting, while organizing your project using &lt;strong>roles&lt;/strong> and &lt;strong>handlers&lt;/strong> for better structure and reuse.&lt;/p>
&lt;h2 id="what-are-ansible-roles">What Are Ansible Roles?&lt;/h2>
&lt;p>Roles are a way to organize your Ansible code into reusable, modular components.&lt;/p>
&lt;p>A role has a standard folder structure (tasks/, handlers/ etc.), and can include everything needed to configure a specific part of your system.&lt;/p></description></item><item><title>Ansible Essentials Installation &amp; Configuration</title><link>https://selfhost.casa/posts/ansible-essentials-installation-configuration/</link><pubDate>Thu, 15 May 2025 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/ansible-essentials-installation-configuration/</guid><description>&lt;p>Ansible is a powerful automation tool that lets you manage your infrastructure using simple, repeatable playbooks. In this first part of the series, you&amp;rsquo;ll install Ansible, configure SSH access, and run your first task — laying the foundation for automating your homelab.&lt;/p>
&lt;h2 id="install-ansible">Install Ansible&lt;/h2>
&lt;p>Install Ansible on your local workstation or control node. In my case I use a my macbook as &amp;ldquo;control node&amp;rdquo;.&lt;/p>
&lt;p>Ensure pip is available and up to date:&lt;/p></description></item><item><title>Automating Dependabot for Docker Compose</title><link>https://selfhost.casa/posts/automating-dependabot-for-docker-compose/</link><pubDate>Mon, 12 May 2025 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/automating-dependabot-for-docker-compose/</guid><description>&lt;p>Keeping dependencies up to date is essential for security and maintainability—but manually managing updates across multiple &lt;code>docker-compose.yml&lt;/code> files in a project can be tedious. In this post, I’ll show you a small Bash script I wrote to automate the generation of a &lt;code>dependabot.yml&lt;/code> file. It scans your repo for all Docker Compose files and configures Dependabot to check them for updates monthly. It’s lightweight, efficient, and ensures you never miss a patch. Let’s dive in. We will automate the updating the &lt;code>dependabot.yml&lt;/code> with Github Actions.&lt;/p></description></item><item><title>Setting Up Your Travel Router | Secure and Reliable Internet Anywhere</title><link>https://selfhost.casa/posts/setting-up-your-travel-router-secure-and-reliable-internet-anywhere/</link><pubDate>Sat, 05 Apr 2025 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/setting-up-your-travel-router-secure-and-reliable-internet-anywhere/</guid><description>&lt;p>Whether you&amp;rsquo;re a digital nomad, a frequent traveler, or just someone who values a secure and stable internet connection on the go, a travel router can be a game-changer. In this guide, we&amp;rsquo;ll walk you through everything you need to know about setting up your travel router—from choosing the right model securing your connection, and optimizing performance. Stay connected, stay secure, and make the most of your travel router wherever you go!&lt;/p></description></item><item><title>Setting up VyOS router for your home network</title><link>https://selfhost.casa/posts/setting-up-vyos-router-for-your-home-network/</link><pubDate>Tue, 25 Mar 2025 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/setting-up-vyos-router-for-your-home-network/</guid><description>&lt;p>Setting up a &lt;a href="https://vyos.io">VyOS&lt;/a> router for your homelab gives you enterprise-grade networking with open-source flexibility. In this post, we&amp;rsquo;ll cover the essential steps to install and configure VyOS for a more secure and efficient network.&lt;/p>
&lt;p>VyOS provides a free routing platform that competes directly with other commercially available solutions from well-known network providers. Because VyOS is run on standard amd64 systems, it can be used as a router and firewall platform for cloud deployments.&lt;/p></description></item><item><title>Monitoring Tailscale clients with Prometheus</title><link>https://selfhost.casa/posts/monitoring-tailscale-clients-with-prometheus/</link><pubDate>Mon, 17 Feb 2025 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/monitoring-tailscale-clients-with-prometheus/</guid><description>&lt;p>Tailscale makes secure networking easy, but how do you monitor its performance? In this guide, we’ll set up Prometheus to collect key Tailscale metrics and gain insights into your mesh VPN connections. Learn how to track bandwidth usage and ensure your network is running smoothly—all with open-source monitoring tools! 🚀&lt;/p>
&lt;p>Setting up Prometheus and Grafana is beyond the scope of this post. If you&amp;rsquo;re interested in setting them up, check out this &lt;a href="../host-container-monitoring-with-prometheus">guide&lt;/a>.&lt;/p></description></item><item><title>How I use GitHub Actions to update my blog daily</title><link>https://selfhost.casa/posts/how-i-use-github-actions-to-update-my-blog-daily/</link><pubDate>Fri, 31 Jan 2025 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/how-i-use-github-actions-to-update-my-blog-daily/</guid><description>&lt;p>This blog is hosted on Cloudflare Pages for optimal loading speed. As a static website built with Jekyll and the Chirpy theme, it relies on a trigger to prompt Cloudflare to rebuild and publish the site. In a previous post, I showed how to set up &lt;a href="../jekyll-chirpy-blog-on-cloudflare-pages/">Jekyll with Cloudflare Pages&lt;/a>, where Cloudflare monitors your Git repository and automatically rebuilds the site with every merge or commit.&lt;/p>
&lt;p>Jekyll allows posts to be scheduled based on the date in the frontmatter, so I often write posts in advance while working on something new. This means there won’t always be a commit or merge to trigger a rebuild on the right date to publisch a post. Instead of only relying on Cloudflare to watch the repository, we needed a trigger to rebuild the site. This is where GitHub Actions comes in.&lt;/p></description></item><item><title>Selfhost your website analytics with Umami</title><link>https://selfhost.casa/posts/selfhost-your-website-analytics-with-umami/</link><pubDate>Wed, 29 Jan 2025 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/selfhost-your-website-analytics-with-umami/</guid><description>&lt;p>Umami is an open-source, privacy-focused web analytics tool that serves as an alternative to Google Analytics. It offers essential insights into website traffic, user behavior, and performance while prioritizing data privacy. Unlike many traditional analytics platforms, Umami does not collect or store personal data, ensuring compliance with GDPR and PECR, and eliminating the need for cookies.&lt;/p>
&lt;p>What makes Umami even more appealing is that it can be self-hosted, giving you full control over your data. In this guide, we’ll walk through the process of setting up Umami on your own server and exposing it via Cloudflare Tunnel, allowing it to securely collect the analytics sent by your website, all while maintaining privacy.&lt;/p></description></item><item><title>Connecting selfhosted apps to Tailscale with TSDProxy</title><link>https://selfhost.casa/posts/connecting-selfhosted-apps-to-tailscale-with-tsdproxy/</link><pubDate>Sat, 25 Jan 2025 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/connecting-selfhosted-apps-to-tailscale-with-tsdproxy/</guid><description>&lt;div
 class="alert alert-warning my-6 overflow-hidden rounded-lg transition-all duration-200 ease-out hover:-translate-y-0.5 hover:shadow-md"
 style="background-color: color-mix(in srgb, var(--color-warning) 10%, transparent);
 border-left-color: var(--color-warning);
 --hover-bg: color-mix(in srgb, var(--color-warning) 15%, transparent);"
 onmouseover="this.style.backgroundColor = this.style.getPropertyValue('--hover-bg')"
 onmouseout="this.style.backgroundColor = 'color-mix(in srgb, var(--color-warning) 10%, transparent)'"
 role="alert"
 aria-labelledby="alert-0-title">
 
 &lt;div
 class=" flex items-center justify-between px-6 pt-6 pb-3"
 >
 &lt;div class="flex items-center gap-3">
 
 &lt;h4
 id="alert-0-title"
 class="m-0 font-semibold text-foreground/90">
 Warning
 &lt;/h4>
 &lt;/div>

 
 
 &lt;/div>

 
 &lt;div
 id="alert-0-content"
 class="alert-content px-6 pb-6">
 &lt;div class="prose prose-sm text-foreground/90 max-w-none">
 &lt;p>This project appears to be abandoned. Use at your own risk.&lt;/p>
 &lt;/div>
 &lt;/div>
 &lt;/div>&lt;script>
function toggleAlert(alertId) {
 const content = document.getElementById(alertId + '-content');
 const chevron = document.getElementById(alertId + '-chevron');
 const header = content.previousElementSibling;
 
 if (content.classList.contains('hidden')) {
 content.classList.remove('hidden');
 chevron.style.transform = 'rotate(0deg)';
 header.setAttribute('aria-expanded', 'true');
 } else {
 content.classList.add('hidden');
 chevron.style.transform = 'rotate(-90deg)';
 header.setAttribute('aria-expanded', 'false');
 }
}


document.addEventListener('DOMContentLoaded', function() {
 const collapsedAlerts = document.querySelectorAll('.alert-content.hidden');
 collapsedAlerts.forEach(function(content) {
 const alertId = content.id.replace('-content', '');
 const chevron = document.getElementById(alertId + '-chevron');
 if (chevron) {
 chevron.style.transform = 'rotate(-90deg)';
 }
 });
});
&lt;/script>

&lt;p>Self-hosted applications often involve juggling network configurations, firewall rules, and ensuring secure access from anywhere. Tailscale simplifies this process by creating a secure, private network—called a “tailnet”—that seamlessly connects all your devices.&lt;/p></description></item><item><title>Setting up an Mikrotik Router</title><link>https://selfhost.casa/posts/setting-up-an-mikrotik-router/</link><pubDate>Sun, 05 Jan 2025 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/setting-up-an-mikrotik-router/</guid><description>&lt;p>Setting up a MikroTik router for your homelab can be an exciting way to improve network performance, security, and management. MikroTik routers are known for their flexibility, power, and affordability, making them an ideal choice for homelab enthusiasts looking to build a robust network infrastructure. In this post, we’ll walk you through the essential steps to get your MikroTik router up and running.&lt;/p>
&lt;h2 id="connect-to-the-router">Connect to the router&lt;/h2>
&lt;p>To configure the MikroTik router, you’ll first need to establish a connection. We recommend using either a serial cable or an SSH connection. These methods allow you to easily copy and paste the configuration commands provided below, making the setup process more efficient and error-free.&lt;/p></description></item><item><title>About selfhost.casa</title><link>https://selfhost.casa/about/</link><pubDate>Fri, 03 Jan 2025 08:00:00 -0900</pubDate><guid>https://selfhost.casa/about/</guid><description>&lt;h3 id="why-casa-domain">Why .casa domain?&lt;/h3>
&lt;p>The word casa means &amp;ldquo;home&amp;rdquo; or &amp;ldquo;house&amp;rdquo; in several Romance languages, including Spanish, Italian, Portuguese, and Romanian. While the Latin root casa originally meant &amp;ldquo;hut&amp;rdquo; or &amp;ldquo;cottage,&amp;rdquo; its meaning expanded over time to encompass a broader sense of &amp;ldquo;house&amp;rdquo; or &amp;ldquo;home&amp;rdquo; within these languages.
Now it makes sens to do self hosting or a homelab at, well, &lt;em>home&lt;/em> 
&lt;a href="https://selfhost.casa/" class="inline-flex items-center no-underline">
&lt;img src="home2.svg" alt="Home" class="h-7 align-text-bottom mx-1">
&lt;/a>&lt;/p>
&lt;h3 id="motivation">Motivation:&lt;/h3>
&lt;p>What is a Homelab?
&lt;figure class="image-figure not-prose my-8" 
 data-lightbox-enabled="false"
 data-gallery-type="auto">
 &lt;div class="image-container">
 &lt;img
 src="home.svg"
 alt="home small picture"
 
 
 loading="lazy"
 decoding="async"
 data-gallery-src="home.svg"
 data-gallery-alt="home small picture"
 data-gallery-title="" />&lt;/div>

 &lt;/figure>
In case you have never heard the term, Homelab is the name given to a server (or multiple server setup) that resides locally in your home and where you host several applications and virtualized systems for testing and developing or for home and functional usage.&lt;/p></description></item><item><title>Secure Your Homelab with Tailscale &amp; Cloudflare</title><link>https://selfhost.casa/posts/secure-your-homelab-with-tailscale-cloudflare/</link><pubDate>Mon, 21 Oct 2024 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/secure-your-homelab-with-tailscale-cloudflare/</guid><description>&lt;p>There are instances when you want to ensure that only you have remote access to specific areas of your homelab. In this post, we’ll explore how to leverage Tailscale, Traefik, and Cloudflare to establish a private and secure connection to your homelab services.&lt;/p>
&lt;h2 id="cloudflare">Cloudflare&lt;/h2>
&lt;h3 id="cloudflare-api">Cloudflare API&lt;/h3>
&lt;p>To begin, we need to generate the necessary API keys with Cloudflare.&lt;/p>
&lt;p>Go the &lt;a href="https://dash.cloudflare.com/profile/api-tokens">API page&lt;/a> and login with your Cloudflare Account.&lt;/p>
&lt;p>Create a API Key on the link above.&lt;/p></description></item><item><title>Setup ntfy for selfhosted notifications</title><link>https://selfhost.casa/posts/setup-ntfy-for-selfhosted-notifications/</link><pubDate>Tue, 01 Oct 2024 09:00:00 +0200</pubDate><guid>https://selfhost.casa/posts/setup-ntfy-for-selfhosted-notifications/</guid><description>&lt;p>In today’s world, staying informed about events in our homelabs is essential. ntfy is a straightforward HTTP-based notification service that allows you to send notifications to your phone or desktop from any computer using scripts or a REST API. The best part? You can host it entirely within your own homelab.&lt;/p>
&lt;p>In this guide, we’ll show you how to make ntfy publicly accessible through Cloudflare Tunnels, ensuring you receive notifications wherever you are.&lt;/p></description></item><item><title>Secure your Cloudflare Tunnel with Authentik</title><link>https://selfhost.casa/posts/secure-your-cloudflare-tunnel-with-authentik/</link><pubDate>Wed, 04 Sep 2024 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/secure-your-cloudflare-tunnel-with-authentik/</guid><description>&lt;p>Enhancing the security and accessibility of your self-hosted applications is simplified with the right tools. By leveraging Cloudflare Tunnels and Authentik, you can create a powerful combination that fortifies your setup. Cloudflare Tunnels allow you to securely expose your local server to the internet, concealing your IP address and eliminating the need for port forwarding. In tandem, Authentik provides robust authentication and access control features.&lt;/p>
&lt;p>This blog post will guide you through the process of integrating Cloudflare Tunnels with Authentik, demonstrating how to secure your self-hosted services effortlessly.&lt;/p></description></item><item><title>Self-hosting securely with Cloudflare Tunnels</title><link>https://selfhost.casa/posts/self-hosting-securely-with-cloudflare-tunnels/</link><pubDate>Wed, 21 Aug 2024 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/self-hosting-securely-with-cloudflare-tunnels/</guid><description>&lt;p>In the world of self-hosting, secure and reliable server access is crucial. Cloudflare Zero Trust offers a solution through Cloudflare Tunnels, allowing secure access to self-hosted services without opening ports or changing firewall settings. By creating an outbound-only connection to Cloudflare, traffic remains encrypted and routed through its global network, enhancing security and performance while protecting your server from direct attacks.&lt;/p>
&lt;h2 id="create-cloudflare-tunnel">Create Cloudflare Tunnel&lt;/h2>
&lt;h3 id="docker-compose">Docker compose&lt;/h3>
&lt;p>To get started, we need to set up a directory to store our &lt;code>docker-compose.yml&lt;/code> file.&lt;/p></description></item><item><title>Selfhost a Single Sign-on MFA with Authentik</title><link>https://selfhost.casa/posts/selfhost-a-single-sign-on-mfa-with-authentik/</link><pubDate>Mon, 22 Jul 2024 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/selfhost-a-single-sign-on-mfa-with-authentik/</guid><description>&lt;p>Managing authentication and access control for self-hosted applications can be complex. Authentik, an open-source identity provider, simplifies this with features like single sign-on (SSO), multi-factor authentication (MFA), and seamless integration with various apps, enhancing security and user management.&lt;/p>
&lt;p>In this post, we’ll walk you through setting up Authentik to streamline access control and strengthen security for your self-hosted services.&lt;/p>
&lt;h2 id="setting-up-authentik">Setting Up Authentik&lt;/h2>
&lt;p>First, create a directory to store the &lt;code>docker-compose.yml&lt;/code> file&lt;/p></description></item><item><title>Jekyll &amp; Chirpy blog on Cloudflare Pages</title><link>https://selfhost.casa/posts/jekyll-chirpy-blog-on-cloudflare-pages/</link><pubDate>Mon, 15 Jul 2024 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/jekyll-chirpy-blog-on-cloudflare-pages/</guid><description>&lt;p>Jekyll is a versatile static site generator that turns plain text into beautifully designed static websites and blogs. It’s perfect for documentation sites, blogs, event sites, or any type of website you need. With Jekyll, you get a fast, secure, easy-to-use, and open-source tool for building static sites.&lt;/p>
&lt;p>In this guide, we’ll walk through installing and configuring Jekyll with the Chirpy theme. We’ll set up the site, create some pages using Markdown, and even host it for free using Cloudflare Pages.&lt;/p></description></item><item><title>Material for MkDocs on Cloudflare Pages</title><link>https://selfhost.casa/posts/material-for-mkdocs-on-cloudflare-pages/</link><pubDate>Mon, 08 Jul 2024 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/material-for-mkdocs-on-cloudflare-pages/</guid><description>&lt;p>Material for MkDocs is a responsive, modern, and highly customizable theme that elevates the look and functionality of your MkDocs documentation site. Paired with Cloudflare Pages, it offers a fast, secure, and reliable hosting solution optimized for performance and scalability.&lt;/p>
&lt;p>In this guide, we’ll walk through installing and configuring Material for MkDocs. We’ll set up the site, create pages using Markdown, and deploy it for free on Cloudflare Pages.&lt;/p>
&lt;h2 id="github">Github&lt;/h2>
&lt;p>To kickstart your mkdocs deployment you can use the template I created, by following the steps below.&lt;/p></description></item><item><title>Traefik Essentials Monitoring with Grafana, Prometheus &amp; Loki</title><link>https://selfhost.casa/posts/traefik-essentials-monitoring-with-grafana-prometheus-loki/</link><pubDate>Mon, 01 Jul 2024 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/traefik-essentials-monitoring-with-grafana-prometheus-loki/</guid><description>&lt;p>We all enjoy visually appealing graphs filled with data, especially for the services we host. Thankfully, Traefik exposes useful metrics on EntryPoints, Routers, Services, and more. By using Prometheus to scrape these metrics and integrating Promtail with Loki for log collection, we can create a complete monitoring solution.&lt;/p>
&lt;p>Setting up Grafana, Prometheus, Promtail and Loki is out of scope of this Story. See my other stories on how to setup &lt;a href="../host-container-monitoring-with-prometheus">Grafana &amp;amp; Prometheus&lt;/a> and &lt;a href="../log-monitoring-with-loki-promtail">Promtail &amp;amp; Loki&lt;/a>&lt;/p></description></item><item><title>Log Monitoring with Loki &amp; Promtail</title><link>https://selfhost.casa/posts/log-monitoring-with-loki-promtail/</link><pubDate>Mon, 24 Jun 2024 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/log-monitoring-with-loki-promtail/</guid><description>&lt;p>Monitoring isn’t just about metrics—it’s about ensuring application health. Centralized logging with Loki and Grafana provides deeper insights by visualizing and searching logs, helping you quickly identify and resolve issues.&lt;/p>
&lt;h2 id="setup-loki">Setup Loki&lt;/h2>
&lt;p>To set up Loki, we need to create a folder to hold both the &lt;code>docker-compose.yml&lt;/code> and the configuration file.&lt;/p>
&lt;p>First, create the folder for Loki:&lt;/p>
&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">
 
 &lt;div
 class="code-block-header bg-muted/30 border-border flex items-center justify-between border-b px-4 py-3">
 
 &lt;div class="flex items-center gap-2">
 &lt;div class="text-muted-foreground flex-shrink-0">
 
 &lt;svg class="h-4 w-4"
 fill="none"
 stroke="currentColor"
 viewBox="0 0 24 24">&lt;path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
&lt;/svg>
 &lt;/div>
 &lt;span class="text-muted-foreground text-sm font-medium">
 BASH
 &lt;/span>
 &lt;/div>

 
 &lt;div class="flex items-center gap-2">
 &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">
 &lt;span class="collapse-icon">
 
 &lt;svg class="h-3 w-3"
 fill="none"
 stroke="currentColor"
 viewBox="0 0 24 24">&lt;path fill="currentColor" d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6l-6 6z"/>&lt;/svg>
 &lt;/span>
 &lt;span class="collapse-text hidden sm:inline"
 >Collapse&lt;/span
 >
 &lt;/button>
 &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">
 &lt;span class="copy-icon">
 
 &lt;svg class="h-3 w-3"
 fill="none"
 stroke="currentColor"
 viewBox="0 0 24 24">&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" />
&lt;/svg>
 &lt;/span>
 &lt;span class="copy-text hidden sm:inline"
 >Copy&lt;/span
 >
 &lt;/button>
 &lt;/div>
 &lt;/div>

 
 &lt;div class="code-block-content relative" id="code-0">
 &lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">mkdir loki&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
 
 &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">
 &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">
 Click to expand and view more
 &lt;/div>
 &lt;/div>
 &lt;/div>
&lt;/div>


&lt;script>
(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 > 0) {
 codeText = Array.from(codeLines)
 .map(line => {
 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(() => {
 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(() => {
 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 > autoCollapseLines || height > autoCollapseHeight;
 }

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

 
 const textContent = codeContainer.textContent || codeContainer.innerText || '';
 const estimatedLines = textContent.split('\n').length;
 return estimatedLines > 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(() => {
 codeContainer.style.transition = '';
 }, 300);
 }
 }

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

 
 collapseBtn.addEventListener('click', toggleCollapse);

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

 
 initCollapse();
 }
})();
&lt;/script>
&lt;p>Open a new &lt;code>docker-compose.yml&lt;/code> file for editing:&lt;/p></description></item><item><title>Host &amp; Container Monitoring with Prometheus</title><link>https://selfhost.casa/posts/host-container-monitoring-with-prometheus/</link><pubDate>Wed, 12 Jun 2024 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/host-container-monitoring-with-prometheus/</guid><description>&lt;p>Monitoring your systems and containers is essential for maintaining a reliable homelab or home server. A popular setup involves Prometheus, Node Exporter, and cAdvisor for collecting metrics, combined with Grafana for creating insightful dashboards.&lt;/p>
&lt;p>In this guide, we’ll set up a complete monitoring solution by:&lt;/p>
&lt;ol>
&lt;li>Configuring Prometheus to scrape metrics from Node Exporter and cAdvisor.&lt;/li>
&lt;li>Using Grafana to visualize the data with intuitive dashboards.&lt;/li>
&lt;/ol>
&lt;p>Let’s dive in and build a robust monitoring stack!&lt;/p></description></item><item><title>Traefik Essentials Reverse Proxy with Docker &amp; Let’s Encrypt</title><link>https://selfhost.casa/posts/traefik-essentials-reverse-proxy-with-docker-lets-encrypt/</link><pubDate>Tue, 21 May 2024 00:00:00 +0000</pubDate><guid>https://selfhost.casa/posts/traefik-essentials-reverse-proxy-with-docker-lets-encrypt/</guid><description>&lt;h2 id="what-is-traefik">What is Traefik&lt;/h2>
&lt;p>Traefik is an open-source reverse proxy and load balancer, perfect for managing containerized applications in your homelab or home server. It integrates seamlessly with Docker, automatically detecting services, configuring routing, and securing connections with SSL. Designed for dynamic, self-hosted environments, Traefik adapts to changes in real-time, making it ideal for scaling and simplifying your setup.&lt;/p>
&lt;p>In this guide, we will set up the Traefik Docker container, configure Let’s Encrypt for obtaining SSL certificates.&lt;/p></description></item></channel></rss>