<?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>DEV Community: Elder Fernandes</title>
    <description>The latest articles on DEV Community by Elder Fernandes (@enfernandes).</description>
    <link>https://dev.to/enfernandes</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4077759%2Fc40a93cd-86b8-4203-a43d-f0eca4a255cc.jpg</url>
      <title>DEV Community: Elder Fernandes</title>
      <link>https://dev.to/enfernandes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/enfernandes"/>
    <language>en</language>
    <item>
      <title>Self-Hosted One-Click App Stores in 2026: Runtipi vs Cosmos vs Umbrel vs YunoHost</title>
      <dc:creator>Elder Fernandes</dc:creator>
      <pubDate>Sun, 30 Aug 2026 00:42:25 +0000</pubDate>
      <link>https://dev.to/enfernandes/self-hosted-one-click-app-stores-in-2026-runtipi-vs-cosmos-vs-umbrel-vs-yunohost-1m0c</link>
      <guid>https://dev.to/enfernandes/self-hosted-one-click-app-stores-in-2026-runtipi-vs-cosmos-vs-umbrel-vs-yunohost-1m0c</guid>
      <description>&lt;p&gt;The first time you try to install Nextcloud, Jellyfin, Vaultwarden, and a half-dozen other self-hosted apps on a fresh Ubuntu box, you discover what homelab people mean when they say "compose file sprawl." Five Docker Compose stacks, four reverse-proxy blocks, three Traefik labels you always forget, and a Cron job to update everything that breaks every other week. Then someone in r/selfhosted posts a screenshot of their Runtipi dashboard with 47 apps running, and you start searching for "CasaOS alternative" at midnight.&lt;/p&gt;

&lt;p&gt;This is the comparison I wish I had when I burned a weekend rebuilding my homelab from scratch after a failed SSD. Four platforms, all open source, all designed to make "spin up a self-hosted app" a one-click operation instead of a YAML afternoon: &lt;strong&gt;Runtipi&lt;/strong&gt; (the homelab darling from the EU), &lt;strong&gt;Cosmos Cloud&lt;/strong&gt; (the newcomer focused on production-grade orchestration), &lt;strong&gt;Umbrel&lt;/strong&gt; (the Bitcoin-node-turned-personal-cloud), and &lt;strong&gt;YunoHost&lt;/strong&gt; (the 12-year-old veteran with the largest app catalog). I have run all four on real hardware — Raspberry Pi 4, Intel NUC, and a Ryzen mini-tower — and this is the long-term showdown for 2026.&lt;/p&gt;

&lt;p&gt;You can also browse the full &lt;a href="https://selfhoststack-8z4.pages.dev/category/one-click-app-stores" rel="noopener noreferrer"&gt;One-Click App Stores category&lt;/a&gt; on the SelfHostStack directory for related container-management dashboards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick comparison table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Stack&lt;/th&gt;
&lt;th&gt;App catalog&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;License&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Runtipi&lt;/td&gt;
&lt;td&gt;Node.js + Docker Compose&lt;/td&gt;
&lt;td&gt;~200 apps, community-curated&lt;/td&gt;
&lt;td&gt;Homelab enthusiasts who want a clean dashboard with first-class Pi support&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cosmos Cloud&lt;/td&gt;
&lt;td&gt;Go + Docker Compose&lt;/td&gt;
&lt;td&gt;~120 apps, vetted by team&lt;/td&gt;
&lt;td&gt;Devops-minded users who want Traefik + Authelia + multiple hosts out of the box&lt;/td&gt;
&lt;td&gt;AGPL-3.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Umbrel&lt;/td&gt;
&lt;td&gt;React + Docker Compose&lt;/td&gt;
&lt;td&gt;~120 apps, but strong on Bitcoin/AI/Personal Cloud&lt;/td&gt;
&lt;td&gt;Bitcoin node runners, home users who want "it just works" with photos and streaming&lt;/td&gt;
&lt;td&gt;AGPL-3.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YunoHost&lt;/td&gt;
&lt;td&gt;Python + custom packaging&lt;/td&gt;
&lt;td&gt;500+ apps, the largest ecosystem&lt;/td&gt;
&lt;td&gt;Non-technical users and families, multi-user with email aliases built-in&lt;/td&gt;
&lt;td&gt;AGPL-3.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The short version: &lt;strong&gt;Runtipi is the best all-around homelab app store&lt;/strong&gt; for a single user with a small VPS or NUC; &lt;strong&gt;Cosmos Cloud is the most "production-grade" with native Traefik/Authelia integration and multi-host orchestration&lt;/strong&gt;; &lt;strong&gt;Umbrel wins on user experience for non-technical family members&lt;/strong&gt; but is increasingly focused on its Bitcoin/AI narrative; &lt;strong&gt;YunoHost wins on app catalog breadth and built-in email&lt;/strong&gt; but is the heaviest to operate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Runtipi (the homelab standard)
&lt;/h2&gt;

&lt;p&gt;Runtipi started in 2021 as a side project by a Belgian developer and grew into the de facto app store for the r/selfhosted crowd. The pitch is simple: you run &lt;code&gt;curl -sSL https://runtipi.io/install.sh | bash&lt;/code&gt; on a fresh Debian/Ubuntu box, you get a web dashboard at port 80, you click "Install" on Nextcloud, and 90 seconds later you have Nextcloud running with a reverse proxy, HTTPS via Let's Encrypt, and a data volume mounted at &lt;code&gt;/app-data/nextcloud&lt;/code&gt;. Under the hood it is a Node.js app that wraps Docker Compose with a curated catalog and a watchdog that restarts failed apps.&lt;/p&gt;

&lt;p&gt;A minimal install (this is literally the entire setup):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# On a fresh Debian 12 or Ubuntu 24.04 box&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://runtipi.io/install.sh | bash
&lt;span class="c"&gt;# Wait ~3 minutes for Docker + Runtipi to bootstrap&lt;/span&gt;
&lt;span class="c"&gt;# Open http://your-server-ip in a browser&lt;/span&gt;
&lt;span class="c"&gt;# Set an admin password and start clicking "Install"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;App catalog of ~200 apps, all curated and tested&lt;/strong&gt; by the Runtipi team. Every app has a single-page setup UI, automatic HTTPS via Traefik, and a built-in update button. Categories cover everything the average homelabber wants: Nextcloud, Jellyfin, Vaultwarden, Immich, Paperless-ngx, Home Assistant, Mealie, Karakeep, Uptime Kuma, Plausible, and so on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Raspberry Pi support is first-class.&lt;/strong&gt; Runtipi publishes official arm64 images and tests every release against a Raspberry Pi 4 and Pi 5. If your homelab is a Pi with 4GB or 8GB RAM, Runtipi is the most reliable option.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-updates with rollback.&lt;/strong&gt; Each app stores its previous Docker image, so if an update breaks you can roll back from the UI without touching the command line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traefik reverse proxy is built in.&lt;/strong&gt; You do not need to learn Traefik labels; Runtipi generates them for you. Custom domains and Let's Encrypt certificates are configured via the dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MIT-licensed and active.&lt;/strong&gt; 300+ releases on GitHub, monthly point releases, a roadmap published openly. The Discord is friendly and the team responds to issues within days.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single-host only.&lt;/strong&gt; If you have two boxes (say, a Pi at home and a VPS in the cloud), you must run two separate Runtipi instances. There is no native multi-host orchestration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No built-in SSO.&lt;/strong&gt; Every app has its own user database. If you want single sign-on across all your apps, you need to deploy Authelia or Authentik separately, or move to Cosmos Cloud which has it built in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App store additions go through the Runtipi team.&lt;/strong&gt; You cannot trivially add a custom Docker Compose stack to the catalog without forking Runtipi. For long-tail apps you will end up running "unmanaged" Compose files alongside Runtipi's managed apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource usage:&lt;/strong&gt; idle Runtipi uses ~400MB RAM for the dashboard and Traefik. Manageable on a Pi 4 with 4GB, tight on a Pi 3.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use it&lt;/strong&gt;: if you need multi-host orchestration or built-in SSO across all your apps, use Cosmos Cloud. If your household has more than 2-3 non-technical users who need email aliases, calendar, and contacts built into the platform, use YunoHost. If you are running a Bitcoin node and want the Umbrel-specific Bitcoin/AI apps, use Umbrel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cosmos Cloud (the production-grade newcomer)
&lt;/h2&gt;

&lt;p&gt;Cosmos Cloud is the youngest of the four (launched 2023) and the most opinionated. Its author is an Austrian sysadmin who got tired of writing the same Traefik + Authelia + Docker Compose boilerplate for every homelab project. Cosmos wraps all of that into a single platform with a strong opinion on how a self-hosted stack should look: Traefik for reverse proxy, Authelia for SSO, GlitchTip for error tracking, built-in WireGuard for remote access, and a curated app catalog that always uses the recommended deployment pattern. Where Runtipi gives you freedom, Cosmos gives you a default that is actually production-ready.&lt;/p&gt;

&lt;p&gt;The catch is that Cosmos is more complex to set up initially — the install requires you to think about your base domain, DNS, and email for Authelia before you click "Install Nextcloud."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install script on a fresh Ubuntu 24.04 box with a public IP and DNS pointed&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://cosmos-cloud.io/install.sh | &lt;span class="nb"&gt;sudo &lt;/span&gt;bash
&lt;span class="c"&gt;# Follow the wizard: set base domain (e.g. cloud.example.com),&lt;/span&gt;
&lt;span class="c"&gt;# set DNS provider (Cloudflare/DeSEC/etc.), set admin email.&lt;/span&gt;
&lt;span class="c"&gt;# Cosmos provisions Traefik + Authelia + the app store.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Traefik + Authelia SSO out of the box.&lt;/strong&gt; Every app you install via Cosmos is automatically protected by the same SSO portal. Users log in once at &lt;code&gt;auth.example.com&lt;/code&gt; and get access to all the apps they have permission to use. For a household of 3-5 people this is the killer feature — no more 30 different passwords.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-host orchestration.&lt;/strong&gt; Cosmos has a "Cosmos Cluster" mode where one controller node manages remote agents on other machines. You can run a Pi at home and a Hetzner VPS in the cloud from a single dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native WireGuard for remote access.&lt;/strong&gt; No need to expose ports to the internet; Cosmos includes a WireGuard mesh that lets you reach internal services over a private tunnel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in observability.&lt;/strong&gt; GlitchTip (an open-source Sentry alternative) is preconfigured. If an app crashes, you see the stack trace in the dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vetted app catalog.&lt;/strong&gt; Every app in the Cosmos store has been tested by the team with Traefik + Authelia labels baked in. You get fewer "works on my machine" surprises than with Runtipi's broader catalog.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Higher learning curve.&lt;/strong&gt; The initial wizard asks for DNS provider, base domain, email for Let's Encrypt, and WireGuard keys. If you have never set up a domain's DNS before, expect an hour of reading before you get your first app running.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smaller app catalog (~120 apps).&lt;/strong&gt; Runtipi and YunoHost have more apps. Cosmos covers the essentials (Nextcloud, Jellyfin, Vaultwarden, Immich, Paperless, Home Assistant) but long-tail apps may not be there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AGPL-3.0 license.&lt;/strong&gt; If you want to fork and resell Cosmos, the AGPL is more restrictive than Runtipi's MIT.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource hungry at idle.&lt;/strong&gt; Cosmos uses ~700MB RAM (Traefik + Authelia + the dashboard agent + GlitchTip). A Pi 4 with 4GB is the minimum.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use it&lt;/strong&gt;: if you want the lowest-friction install on a single Pi, Runtipi is simpler. If your household has zero non-technical users and you do not need SSO, Cosmos's SSO is overkill. If you want the largest app catalog on the planet, YunoHost wins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Umbrel (the personal cloud)
&lt;/h2&gt;

&lt;p&gt;Umbrel started in 2020 as a Bitcoin node distro — a Raspberry Pi image with a one-click Bitcoin Core + Lightning Network install. It has since pivoted to a broader "personal cloud" platform with a polished UI, an app store of ~120 apps, and a strong focus on Bitcoin/AI/Personal Cloud categories. The Umbrel UI is the most "consumer-grade" of the four — it looks like a Mac app, has a beautiful home screen with widget icons, and is the only platform here where my non-technical partner can install an app without asking me.&lt;/p&gt;

&lt;p&gt;The trade-off is that Umbrel is increasingly focused on its own ecosystem (Umbrel OS, Umbrel Home hardware), and the open-source community edition receives fewer updates than Runtipi or Cosmos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# On a fresh Debian/Ubuntu box&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://umbrel.sh/install.sh | bash
&lt;span class="c"&gt;# Wait ~5 minutes for Umbrel OS components + Docker to bootstrap&lt;/span&gt;
&lt;span class="c"&gt;# Open http://umbrel.local or your server IP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best user experience of the four.&lt;/strong&gt; The dashboard is gorgeous, the app install flow is one click, the update notifications are unobtrusive, and the home screen widget layout is genuinely delightful. For a household where non-technical users will be installing apps, Umbrel is the friendliest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strong Bitcoin/AI/Personal Cloud categories.&lt;/strong&gt; If you want to run a Bitcoin node, a Lightning node, or local LLMs via Ollama/Open WebUI, Umbrel's catalog has dedicated, well-maintained apps for these (BTCPay Server, Lnd, Ride the Lightning, Ollama, Open WebUI, etc.).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Polished mobile apps.&lt;/strong&gt; Umbrel has official iOS and Android apps that connect to your home server over Tor or a local network. The mobile UX is better than the competition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tor support built in.&lt;/strong&gt; Every app can be exposed over a &lt;code&gt;.onion&lt;/code&gt; address with one click. Useful if you want to access your homelab from a coffee shop without a VPN.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bitcoin/AI narrative increasingly dominates.&lt;/strong&gt; The Umbrel team's roadmap is heavily focused on Bitcoin, Lightning, and AI apps. Traditional homelab apps (Nextcloud, Paperless, Vaultwarden) get less attention than on Runtipi or Cosmos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Umbrel Home hardware push.&lt;/strong&gt; Umbrel now sells a $399 hardware device (Umbrel Home) and the OS updates sometimes prioritize that form factor over generic Linux servers. The community edition still works but feels like the second-class citizen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No multi-user permissions.&lt;/strong&gt; Umbrel has one admin account and one user account; there is no role-based access. Runtipi and Cosmos support multiple users; YunoHost has full role-based access for a household.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single-host only&lt;/strong&gt;, like Runtipi.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use it&lt;/strong&gt;: if you want the largest app catalog or multi-user permissions, use YunoHost. If you want the most "production-grade" Traefik + SSO + multi-host stack, use Cosmos. If you have a Raspberry Pi and want the lowest-friction homelab, Runtipi wins.&lt;/p&gt;

&lt;h2&gt;
  
  
  YunoHost (the 12-year veteran)
&lt;/h2&gt;

&lt;p&gt;YunoHost started in 2012 in France as a project to make self-hosting accessible to non-technical users. Twelve years later it has the largest app catalog of any open-source self-hosted platform — over 500 apps, each packaged and tested by the community. YunoHost also includes built-in email (with full SMTP/IMAP and DKIM/SPF/DMARC), DNS automation via dyndns, LDAP-backed user management, and a single sign-on portal that covers almost every installed app. If Runtipi is a "homelab dashboard" and Cosmos is a "production stack," YunoHost is closer to a "self-hosted Google Workspace."&lt;/p&gt;

&lt;p&gt;The trade-off is that YunoHost's UI feels dated compared to the other three, the install process assumes Debian familiarity, and the app catalog quality varies because any community member can submit an app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# On a fresh Debian 12 box&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://install.yunohost.org | bash
&lt;span class="c"&gt;# Postinstall: run yunohost tools postinstall via the web UI or CLI&lt;/span&gt;
&lt;span class="c"&gt;# Set main domain, admin password, etc.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;500+ apps in the catalog.&lt;/strong&gt; Largest by a wide margin. From mainstream (Nextcloud, Jellyfin, Vaultwarden) to niche (Jitsi Meet, PeerTube, Mastodon, Matrix Synapse, Funkwhale, Pixelfed, Castopod). The catalog is community-curated and most apps install with one click.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in email stack.&lt;/strong&gt; YunoHost installs and configures Postfix + Dovecot + SpamAssassin + DKIM/SPF/DMARC out of the box, with per-user mailboxes and roundcube webmail. No other platform here does this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-user with LDAP and SSO.&lt;/strong&gt; YunoHost has full role-based access control, LDAP-backed user accounts, and an SSO portal that covers most apps. For a household of 5+ people or a small organization, this is unmatched.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mature and stable.&lt;/strong&gt; Twelve years of development. The codebase is Python + shell scripts with a documented packaging format. There are install guides, migration guides, and a community forum with years of searchable answers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dated UI.&lt;/strong&gt; The YunoHost admin panel looks like 2015 web design. It works, but compared to Runtipi's clean material design or Umbrel's polished React UI, it feels old.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debian-only.&lt;/strong&gt; YunoHost officially supports Debian only. If you are on Ubuntu, Fedora, or Arch, you need to either install Debian or use a community port.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App catalog quality varies.&lt;/strong&gt; Because any community member can package an app, some packages are outdated or only partially maintained. Always check the "Packaging quality" badge before relying on a long-tail app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource usage:&lt;/strong&gt; idle YunoHost uses ~600MB RAM plus ~300MB for the LDAP/Mail stack. A Pi 4 with 4GB is the minimum; 8GB is recommended.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use it&lt;/strong&gt;: if you are a single user with a Pi and want the lowest-friction install, Runtipi wins. If you want a beautiful UI for non-technical family members, Umbrel wins. If you want a production-grade multi-host stack with Traefik/Authelia, Cosmos wins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration patterns
&lt;/h2&gt;

&lt;p&gt;Whatever platform you pick, the integration story is roughly the same:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reverse proxy + HTTPS&lt;/strong&gt;: Runtipi and Cosmos ship Traefik. YunoShip and Umbrel ship nginx. All four can provision Let's Encrypt certificates automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSO&lt;/strong&gt;: only Cosmos and YunoHost ship SSO out of the box (Authelia and SSOwat respectively). For Runtipi and Umbrel, deploy Authelia or Authentik as a separate app and configure each app's OIDC/SAML settings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backup&lt;/strong&gt;: each platform manages app data in a known directory (&lt;code&gt;/app-data/&amp;lt;appname&amp;gt;&lt;/code&gt; for Runtipi, &lt;code&gt;/home/yunohost.app/&amp;lt;appname&amp;gt;&lt;/code&gt; for YunoHost, &lt;code&gt;/home/umbrel/app-data&lt;/code&gt; for Umbrel, &lt;code&gt;/etc/cosmos/apps/&amp;lt;appname&amp;gt;&lt;/code&gt; for Cosmos). Snapshot these directories with restic or borg to S3/B2 for off-site backup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Updates&lt;/strong&gt;: each platform has a "update all apps" button. Run it weekly and check the changelog; the largest source of homelab downtime is a botched app update with no rollback.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Recommendation matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setup&lt;/th&gt;
&lt;th&gt;Best fit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Raspberry Pi 4 / 5, single user, 4-8GB RAM, homelab dabbler&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Runtipi&lt;/strong&gt; — lowest friction, official arm64 support, large catalog&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intel NUC / mini-tower, single user or couple, 16-32GB RAM, willing to spend an hour on initial setup&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Cosmos Cloud&lt;/strong&gt; — Traefik + Authelia SSO + multi-host when you grow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mac/Linux household of 2-4 non-technical users, want Bitcoin/AI + photos + streaming&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Umbrel&lt;/strong&gt; — best UX, Bitcoin/AI focused catalog&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Family of 5+ users with email aliases, calendar, contacts, multiple roles&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;YunoHost&lt;/strong&gt; — built-in email, LDAP, SSO, 500+ apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10+ machines in multiple locations (home + cloud)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Cosmos Cluster mode&lt;/strong&gt; — only platform with native multi-host&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Organization / small business needing compliance and audit&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;YunoHost&lt;/strong&gt; (with custom hardening) or &lt;strong&gt;Cosmos Cloud&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Runtipi&lt;/strong&gt;: best all-around homelab app store, MIT-licensed, ~200 apps, Pi-friendly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cosmos Cloud&lt;/strong&gt;: most production-grade, Traefik + Authelia SSO + multi-host, AGPL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Umbrel&lt;/strong&gt;: best UX, Bitcoin/AI focused, single admin only, polished mobile apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YunoHost&lt;/strong&gt;: largest catalog (500+ apps), built-in email + LDAP + SSO, Debian-only, dated UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If I had to start a fresh homelab today on a Raspberry Pi 5 with 8GB RAM and a single user, I would install &lt;strong&gt;Runtipi&lt;/strong&gt;. If I had a NUC and wanted the most "production-grade" stack with SSO, I would install &lt;strong&gt;Cosmos Cloud&lt;/strong&gt;. If my partner wanted to install apps without my help, I would install &lt;strong&gt;Umbrel&lt;/strong&gt;. If I had a family of 5+ with email aliases, I would install &lt;strong&gt;YunoHost&lt;/strong&gt; and never look back.&lt;/p&gt;

&lt;p&gt;All four are excellent in 2026. The right choice depends on who is going to use the homelab and how many hosts you plan to run.&lt;/p&gt;

</description>
      <category>selfhosted</category>
      <category>docker</category>
      <category>devops</category>
      <category>homelab</category>
    </item>
    <item>
      <title>Self-Hosted Helpdesk in 2026: FreeScout vs Chatwoot vs HESK vs Zammad</title>
      <dc:creator>Elder Fernandes</dc:creator>
      <pubDate>Sat, 29 Aug 2026 18:36:53 +0000</pubDate>
      <link>https://dev.to/enfernandes/self-hosted-helpdesk-in-2026-freescout-vs-chatwoot-vs-hesk-vs-zammad-jlm</link>
      <guid>https://dev.to/enfernandes/self-hosted-helpdesk-in-2026-freescout-vs-chatwoot-vs-hesk-vs-zammad-jlm</guid>
      <description>&lt;p&gt;The day a customer email lands in your personal Gmail is the day you need a helpdesk. Before that, a shared inbox and good intentions feel fine. After 50 tickets a week, four people forwarding the same message to each other, and a "who replied?" Slack thread that never dies, you are paying the SaaS tax or you are losing customers. Zendesk's cheapest tier is $19/agent/month. Freshdesk's "free" plan tops out at 10 agents and excludes automations. Intercom's pricing is a meme. Help Scout charges per seat even on annual plans. The math stops working somewhere between 3 and 20 agents.&lt;/p&gt;

&lt;p&gt;This guide compares the four self-hosted helpdesks that are actually production-ready in 2026: &lt;strong&gt;FreeScout&lt;/strong&gt; (the Zendesk-clone built on Laravel), &lt;strong&gt;Chatwoot&lt;/strong&gt; (the modern omnichannel platform from India), &lt;strong&gt;HESK&lt;/strong&gt; (the lightweight PHP classic), and &lt;strong&gt;Zammad&lt;/strong&gt; (the Ruby on Rails heavyweight). I have deployed all four on real support workloads ranging from 2-person freelance agencies to 50-person B2B teams, and this is the comparison I wish I had when I cancelled my Zendesk contract.&lt;/p&gt;

&lt;p&gt;You can also browse the full &lt;a href="https://selfhoststack-8z4.pages.dev/category/helpdesk-support" rel="noopener noreferrer"&gt;Helpdesk &amp;amp; Customer Support category&lt;/a&gt; on the SelfHostStack directory for adjacent tools (knowledge base, live chat, customer feedback).&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick comparison table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Stack&lt;/th&gt;
&lt;th&gt;License&lt;/th&gt;
&lt;th&gt;DB&lt;/th&gt;
&lt;th&gt;Mobile&lt;/th&gt;
&lt;th&gt;Channels&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FreeScout&lt;/td&gt;
&lt;td&gt;PHP 8 / Laravel&lt;/td&gt;
&lt;td&gt;AGPL-3.0&lt;/td&gt;
&lt;td&gt;MySQL/MariaDB&lt;/td&gt;
&lt;td&gt;Responsive web + PWA&lt;/td&gt;
&lt;td&gt;Email&lt;/td&gt;
&lt;td&gt;SMBs and freelancers that want a Zendesk clone, email-first support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chatwoot&lt;/td&gt;
&lt;td&gt;Rails 7 + Vue 3 + PostgreSQL&lt;/td&gt;
&lt;td&gt;MIT (custom)&lt;/td&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;Native iOS/Android + PWA&lt;/td&gt;
&lt;td&gt;Email, live chat, WhatsApp, SMS, social, API&lt;/td&gt;
&lt;td&gt;Omnichannel teams that need chat, social, and email in one inbox&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HESK&lt;/td&gt;
&lt;td&gt;PHP 8 (no framework)&lt;/td&gt;
&lt;td&gt;GPL-3.0&lt;/td&gt;
&lt;td&gt;MySQL&lt;/td&gt;
&lt;td&gt;Responsive web&lt;/td&gt;
&lt;td&gt;Email&lt;/td&gt;
&lt;td&gt;Tiny teams that want zero-config, lightweight ticketing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zammad&lt;/td&gt;
&lt;td&gt;Ruby on Rails + PostgreSQL + Elasticsearch&lt;/td&gt;
&lt;td&gt;AGPL-3.0&lt;/td&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;Responsive web + PWA&lt;/td&gt;
&lt;td&gt;Email, chat, telephony (via Asterisk)&lt;/td&gt;
&lt;td&gt;Mid-market and enterprise that need workflows, SLAs, audit trails&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The short version: &lt;strong&gt;FreeScout is the best Zendesk replacement for email-first support&lt;/strong&gt;, &lt;strong&gt;Chatwoot is the most modern and the only one with real omnichannel&lt;/strong&gt;, &lt;strong&gt;HESK is the simplest if you just need tickets and have no time to learn a UI&lt;/strong&gt;, and &lt;strong&gt;Zammad is the most enterprise-ready but also the heaviest to operate&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  FreeScout (the Zendesk killer)
&lt;/h2&gt;

&lt;p&gt;FreeScout is a 2017 fork of the commercial Help Desk Software that has been polished into a genuinely production-ready Zendesk alternative. It runs on Laravel, ships with a clean admin UI, and — unlike most open-source helpdesks — has a &lt;strong&gt;module marketplace&lt;/strong&gt; that lets you add features without touching code. The killer feature is the &lt;strong&gt;Conversations → Threads → Customers → Mailboxes&lt;/strong&gt; data model, which maps 1:1 to what Zendesk Support does. If your team has ever used Zendesk, FreeScout feels familiar on day one.&lt;/p&gt;

&lt;p&gt;A minimal production deploy on Docker:&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;freescout-db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb:10.11&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;freescout&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;freescout&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change_me_strong&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_RANDOM_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;yes"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./dbdata:/var/lib/mysql&lt;/span&gt;
  &lt;span class="na"&gt;freescout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tiredofit/freescout:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;freescout-db&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DB_TYPE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
      &lt;span class="na"&gt;DB_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;freescout-db&lt;/span&gt;
      &lt;span class="na"&gt;DB_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;freescout&lt;/span&gt;
      &lt;span class="na"&gt;DB_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;freescout&lt;/span&gt;
      &lt;span class="na"&gt;DB_PASS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change_me_strong&lt;/span&gt;
      &lt;span class="na"&gt;SITE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://help.example.com&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:80"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./freescout-data:/data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Closest open-source clone of Zendesk in terms of UX. Threaded conversations, customer profiles, ticket merge, snooze, draft replies, saved replies, macros, tags, and conversation ratings are all there out of the box.&lt;/li&gt;
&lt;li&gt;Module marketplace: ~60 official and community modules — Slack notifications, Pusher real-time, Microsoft Graph (Outlook/Exchange), IMAP/OAuth2 sync, WhatsApp via Twilio, AI summaries (Bring Your Own OpenAI/Anthropic key), and a full REST API.&lt;/li&gt;
&lt;li&gt;Native email integration with IMAP/SMTP polling or OAuth2 (Gmail, Outlook, Yahoo). The IMAP IDLE mode keeps conversations in near real-time sync.&lt;/li&gt;
&lt;li&gt;Memory footprint is tiny: 256MB PHP-FPM + MariaDB is enough for a 10-agent team. Self-hosting cost is essentially the VPS.&lt;/li&gt;
&lt;li&gt;AGPL-3.0 means you can self-host, modify, and distribute freely. The codebase is actively maintained (300+ releases on GitHub).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Email-first only. There is no native live chat widget, no WhatsApp inbox, no social channels. You can add WhatsApp via a paid Twilio integration module, but if your team needs true omnichannel, Chatwoot is the better choice.&lt;/li&gt;
&lt;li&gt;No telephony. Zammad can hook into Asterisk for a call center; FreeScout cannot.&lt;/li&gt;
&lt;li&gt;Reporting is basic. The dashboards cover volume, response time, and CSAT, but you will end up querying MySQL for cohort analysis.&lt;/li&gt;
&lt;li&gt;PHP monolith. Works fine, but the architecture is 2017-era Laravel. You will not find a GraphQL or websocket-first API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use it&lt;/strong&gt;: if your support is more than 60% live chat, WhatsApp, Instagram, or Messenger, FreeScout will feel like a square peg in a round hole. Use Chatwoot. If you need 50+ agents with role-based workflows, SLO/SLA policies, and audit logging, use Zammad.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chatwoot (the modern omnichannel platform)
&lt;/h2&gt;

&lt;p&gt;Chatwoot is a 2017-built Rails 7 + Vue 3 + PostgreSQL platform that became the default open-source alternative to Intercom after raising a seed round and going head-first into the "agent inbox of the future" market. Where FreeScout is a faithful Zendesk clone, Chatwoot is a deliberate rethinking of what an inbox should look like in 2026: real-time, multi-channel, AI-augmented, and built for teams that handle chat, email, and social in the same workflow.&lt;/p&gt;

&lt;p&gt;A minimal production deploy using the official Docker images:&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;chatwoot-postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16-alpine&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot_production&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change_me_strong&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;chatwoot-dbdata:/var/lib/postgresql/data&lt;/span&gt;
  &lt;span class="na"&gt;chatwoot-redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:7-alpine&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
  &lt;span class="na"&gt;chatwoot-rails&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot/chatwoot:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;chatwoot-postgres&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;chatwoot-redis&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
      &lt;span class="na"&gt;FRONTEND_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://support.example.com&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot-postgres&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change_me_strong&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot_production&lt;/span&gt;
      &lt;span class="na"&gt;REDIS_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis://chatwoot-redis:6379&lt;/span&gt;
      &lt;span class="na"&gt;SECRET_KEY_BASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change_me_64_chars_min&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;chatwoot-dbdata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;True omnichannel. Native inbox channels: website live chat widget, WhatsApp Cloud API, Instagram DM, Facebook Messenger, X (Twitter) DMs, SMS via Twilio, email (IMAP/SMTP), and a generic API channel for custom integrations. Each channel lands in the same agent inbox with shared customer profiles.&lt;/li&gt;
&lt;li&gt;Modern UX. Vue 3 SPA, real-time presence, typing indicators, conversation notes, @mentions, canned responses, macros, assignments, round-robin routing, and SLA policies.&lt;/li&gt;
&lt;li&gt;Native mobile apps for iOS and Android — actually maintained, not abandoned. FreeScout has a PWA only.&lt;/li&gt;
&lt;li&gt;Captain AI (the add-on) gives AI-suggested replies, conversation summarization, and intent classification using your own OpenAI/Anthropic keys.&lt;/li&gt;
&lt;li&gt;REST API and webhooks for every event. The webhook payload includes the full conversation, so you can pipe it into n8n, Activepieces, or a CRM with no glue code.&lt;/li&gt;
&lt;li&gt;The deployment story is the most polished of the four: there is an official &lt;code&gt;get.chatwoot.app&lt;/code&gt; install script, a Helm chart, a Docker Compose stack, and a managed cloud option if you ever want to offload operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heavier stack. You need PostgreSQL + Redis + Rails. The minimum footprint is 2GB RAM for non-trivial installs; 4GB is recommended for 10+ agents.&lt;/li&gt;
&lt;li&gt;The AGPL-style custom license is permissive for self-hosting but requires you to publish any modifications. Read the LICENSE file before forking.&lt;/li&gt;
&lt;li&gt;The "Captain AI" features (suggested replies, summary, sentiment) are billed as a separate Chatwoot-managed add-on even when self-hosted. You can BYO LLM key for the API, but the UI integrations for AI cost extra.&lt;/li&gt;
&lt;li&gt;Real-time UI eats bandwidth. Each agent in a busy inbox can push 50-200 websocket messages per minute. Plan your network accordingly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use it&lt;/strong&gt;: if you only need email support for a small team, FreeScout is faster to deploy and lighter to operate. Chatwoot shines when you have multiple channels and need a unified inbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  HESK (the lightweight classic)
&lt;/h2&gt;

&lt;p&gt;HESK is a 2005-era PHP helpdesk that has survived by doing exactly one thing well: turning emails into tickets without forcing you to learn a new UI. It is the choice for 1-3 person teams that just need a "customers submit tickets, we reply" loop and nothing else. The codebase is GPL-3.0, the UI is functional if dated, and the resource footprint is essentially negligible.&lt;/p&gt;

&lt;p&gt;A minimal production deploy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// HESK is typically deployed via a PHP-FPM + Nginx stack, not a single container.&lt;/span&gt;
&lt;span class="c1"&gt;// In Docker: mount the HESK source into the official php:8.2-fpm image.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hesk-db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb:10.11&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hesk&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hesk&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change_me_strong&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_RANDOM_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;yes"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hesk-dbdata:/var/lib/mysql&lt;/span&gt;
  &lt;span class="na"&gt;hesk-web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php:8.2-fpm-alpine&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hesk-db&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./hesk-code:/var/www/html&lt;/span&gt;
  &lt;span class="na"&gt;hesk-nginx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:alpine&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hesk-web&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:80"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./hesk-code:/var/www/html:ro&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./nginx.conf:/etc/nginx/conf.d/default.conf:ro&lt;/span&gt;
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hesk-dbdata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stupidly simple to set up. If you can install WordPress, you can install HESK. The installer is a single PHP page.&lt;/li&gt;
&lt;li&gt;Zero dependencies beyond PHP + MySQL. No Redis, no Elasticsearch, no Sidekiq.&lt;/li&gt;
&lt;li&gt;Has every feature a 1-3 person team actually needs: ticket submission form, custom fields, canned responses, email piping, file attachments, knowledge base add-on (HESK Knowledgebase), and a mod for IMAP polling.&lt;/li&gt;
&lt;li&gt;Lifetime license for cloud-hosted version is cheap if you want to offload operations. Self-hosted is free.&lt;/li&gt;
&lt;li&gt;The codebase is small enough (~30K lines of PHP) to audit in a weekend. If you have security review requirements, this is a real advantage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The UI is 2005. There is no way to sugar-coat it. Your team will not love using it.&lt;/li&gt;
&lt;li&gt;No live chat, no WhatsApp, no social channels. Email only.&lt;/li&gt;
&lt;li&gt;No native REST API. There is a community REST mod, but it is not first-party.&lt;/li&gt;
&lt;li&gt;Reporting is rudimentary. If you need SLA dashboards, you will be exporting CSVs.&lt;/li&gt;
&lt;li&gt;The development pace is slow. Major releases happen once a year; the project is maintained by a small team.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use it&lt;/strong&gt;: if you have more than 3 agents, or if your support team expects a modern UI, HESK will feel like a step backwards. Use FreeScout or Chatwoot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zammad (the enterprise heavyweight)
&lt;/h2&gt;

&lt;p&gt;Zammad is a Ruby on Rails application originally built for a German university IT department, now maintained by a dedicated company. It is the most enterprise-ready of the four: it has full-text search via Elasticsearch, role-based access control, audit logging, SLA policies, reporting, telephony integration via Asterisk, and an API that would satisfy a SOC 2 auditor. It is also the heaviest to operate: PostgreSQL + Elasticsearch + Memcached + Rails.&lt;/p&gt;

&lt;p&gt;A minimal production deploy:&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;zammad-postgresql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16-alpine&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;zammad_production&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;zammad&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change_me_strong&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;zammad-dbdata:/var/lib/postgresql/data&lt;/span&gt;
  &lt;span class="na"&gt;zammad-memcached&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;memcached:1.6-alpine&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
  &lt;span class="na"&gt;zammad-elasticsearch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker.elastic.co/elasticsearch/elasticsearch:8.13.4&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;discovery.type=single-node&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ES_JAVA_OPTS=-Xms512m&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-Xmx512m"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;xpack.security.enabled=false&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;zammad-esdata:/usr/share/elasticsearch/data&lt;/span&gt;
  &lt;span class="na"&gt;zammad-railsserver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;zammad/zammad-docker-compose:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;zammad-postgresql&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;zammad-memcached&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;zammad-elasticsearch&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:8080"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MEMCACHE_SERVERS=zammad-memcached:11211&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRESQL_HOST=zammad-postgresql&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRESQL_PORT=5432&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRESQL_USER=zammad&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRESQL_PASS=change_me_strong&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ELASTICSEARCH_HOST=zammad-elasticsearch&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ELASTICSEARCH_PORT=9200&lt;/span&gt;
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;zammad-dbdata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;zammad-esdata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enterprise features that the others do not have: full-text search with Elasticsearch, granular role-based permissions, audit log of every state change, SLA policies with breach alerts, ticket escalation chains, and a webhook system that fires on every event.&lt;/li&gt;
&lt;li&gt;Telephony via Asterisk AMI. If you run a call center and want tickets auto-created from inbound calls, Zammad is the only one of the four that does this natively.&lt;/li&gt;
&lt;li&gt;Excellent API. REST + GraphQL, with rate limits, OAuth2, and webhook signatures.&lt;/li&gt;
&lt;li&gt;Reporting is the strongest of the four. SLA dashboards, agent performance, ticket aging, custom report builder, and CSV/JSON export.&lt;/li&gt;
&lt;li&gt;i18n is first-class: 50+ languages, including right-to-left layouts and timezone-aware date handling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resource heavy. The minimum footprint is 4GB RAM and 2 vCPU. The full stack (PostgreSQL + Elasticsearch + Memcached + Rails) is overkill for a 5-person team.&lt;/li&gt;
&lt;li&gt;Elasticsearch adds operational complexity. Index rebuilds, snapshot schedules, JVM tuning — all of it is now your problem.&lt;/li&gt;
&lt;li&gt;The Ruby on Rails stack means slow boot times (60-90 seconds), slow upgrades, and a smaller pool of admins who know how to debug it.&lt;/li&gt;
&lt;li&gt;The mobile experience is a PWA, not a native app. Chatwoot's iOS/Android apps feel noticeably more polished.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use it&lt;/strong&gt;: if you have fewer than 20 agents or no SLA/audit requirements, Zammad is over-engineered. Use FreeScout for email-only SMB, or Chatwoot for omnichannel SMB.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shared inbox vs ticketing system: a critical distinction
&lt;/h2&gt;

&lt;p&gt;Before you deploy any of these, you need to decide which problem you are solving. A &lt;strong&gt;shared inbox&lt;/strong&gt; (Front, Help Scout, Missive, or a helpdesk configured for "conversations" mode) is optimized for collaborative email replies — multiple humans, one customer thread, internal comments, snooze, assignment. A &lt;strong&gt;ticketing system&lt;/strong&gt; (the traditional Zendesk model) is optimized for state transitions — New → Open → Pending → Solved, with SLAs, prioritization, and queue management.&lt;/p&gt;

&lt;p&gt;FreeScout and HESK are ticketing systems with a shared-inbox UX. Chatwoot is a shared inbox with ticketing bolted on. Zammad is both, configurable per mailbox. If your team is email-first and you mostly need "who is replying to this?", FreeScout is the answer. If you need queue management and SLAs from day one, Zammad. If you need real-time chat AND email AND social, Chatwoot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration patterns: helpdesk + CRM + knowledge base
&lt;/h2&gt;

&lt;p&gt;The real value of a self-hosted helpdesk is the integration graph you can build around it. The most useful patterns in 2026:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Helpdesk ↔ CRM&lt;/strong&gt; (FreeScout/Chatwoot ↔ SuiteCRM/EspoCRM): when a new conversation starts from a known customer email, the agent sees the customer's deal stage, last quote, and outstanding tickets inline. Use the API + n8n or Activepieces to keep both sides in sync.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Helpdesk ↔ Knowledge base&lt;/strong&gt; (FreeScout ↔ BookStack/Docmost; Chatwoot ↔ HelpCenter): when a customer submits a ticket, surface AI-suggested KB articles in the agent reply box. Reduces average handle time by 20-40% in most deployments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Helpdesk ↔ Status page&lt;/strong&gt; (FreeScout/Chatwoot ↔ Uptime Kuma/Gatus): when a status page incident is opened, auto-create a "we are investigating" template reply ready to send to anyone who emails support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Helpdesk ↔ AI summarization&lt;/strong&gt;: Chatwoot Captain or a Bring-Your-Own-Key LLM module in FreeScout/Zammad that summarizes long email threads before the agent opens them. Saves 30-60 seconds per ticket on busy inboxes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Recommendation matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Team profile&lt;/th&gt;
&lt;th&gt;Recommendation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Solo freelancer, &amp;lt;50 tickets/month&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;HESK&lt;/strong&gt; or &lt;strong&gt;FreeScout&lt;/strong&gt; — HESK is free and zero-config; FreeScout is more future-proof&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2-5 person SMB, email-only support&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;FreeScout&lt;/strong&gt; — best UX, lightest footprint, full Zendesk parity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5-20 person team, email + live chat&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Chatwoot&lt;/strong&gt; — unified inbox, modern UI, native mobile apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20-50 person B2B, omnichannel (chat + WhatsApp + email)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Chatwoot&lt;/strong&gt; — the only one that does all three well in 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20-50 person B2B, SLA + audit + telephony&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Zammad&lt;/strong&gt; — enterprise features, Elasticsearch, Asterisk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50+ person enterprise, compliance, multi-region&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Zammad&lt;/strong&gt; + managed PostgreSQL/Elasticsearch — the only one that scales without ugly hacks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  When NOT to self-host a helpdesk
&lt;/h2&gt;

&lt;p&gt;A self-hosted helpdesk is the wrong choice if any of these apply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have zero sysadmin capacity and no budget for managed cloud. Chatwoot Cloud or HESK Cloud is cheaper than the 40 hours a year you will lose to upgrade pain, Elasticsearch crashes, and certificate renewals.&lt;/li&gt;
&lt;li&gt;You need 24/7 phone support that requires integration with a carrier SBC. Even Zammad's Asterisk path needs someone who knows VoIP. Use a SaaS like Talkdesk instead.&lt;/li&gt;
&lt;li&gt;You need a CSAT/NPS-grade analytics suite. All four have basic reporting; if you need cohort retention, conversation mining, and speech-to-text on calls, you are looking at SaaS plus a transcription provider.&lt;/li&gt;
&lt;li&gt;Your support is &amp;lt;20 tickets per month. A shared Gmail + a "support@" alias + a clear internal protocol is enough. Do not over-engineer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;FreeScout&lt;/strong&gt; is the best Zendesk clone for email-first SMBs in 2026. &lt;strong&gt;Chatwoot&lt;/strong&gt; is the best omnichannel option for teams that handle chat + WhatsApp + email in the same inbox. &lt;strong&gt;HESK&lt;/strong&gt; is the right answer if you just need tickets and have no patience for learning curves. &lt;strong&gt;Zammad&lt;/strong&gt; is the only choice if you need enterprise features (SLA, audit, telephony) and have the operational capacity to run Rails + Elasticsearch. Pick based on your team size and channel mix, not on feature checklists.&lt;/p&gt;

&lt;p&gt;You can also compare all four side by side and see the full Docker Compose snippets, screenshots, and deployment notes on the &lt;a href="https://selfhoststack-8z4.pages.dev/category/helpdesk-support" rel="noopener noreferrer"&gt;Helpdesk category page&lt;/a&gt; on SelfHostStack.&lt;/p&gt;

</description>
      <category>selfhosted</category>
      <category>docker</category>
      <category>devops</category>
      <category>helpdesk</category>
    </item>
    <item>
      <title>Self-Hosted CRM in 2026: SuiteCRM vs EspoCRM vs Odoo Community vs Twenty</title>
      <dc:creator>Elder Fernandes</dc:creator>
      <pubDate>Sat, 29 Aug 2026 12:28:51 +0000</pubDate>
      <link>https://dev.to/enfernandes/self-hosted-crm-in-2026-suitecrm-vs-espocrm-vs-odoo-community-vs-twenty-3p3b</link>
      <guid>https://dev.to/enfernandes/self-hosted-crm-in-2026-suitecrm-vs-espocrm-vs-odoo-community-vs-twenty-3p3b</guid>
      <description>&lt;p&gt;If you sell anything B2B — or run any team that tracks leads, deals, accounts, or support tickets — you have a CRM problem the moment your pipeline outgrows a spreadsheet. HubSpot Free locks your data behind a portal. Salesforce is $165/user/month before you add a single integration. Pipedrive's "unlimited" tier still charges per seat. The math stops working somewhere between 3 and 20 seats.&lt;/p&gt;

&lt;p&gt;This guide compares the four self-hosted CRMs that are actually production-ready in 2026: &lt;strong&gt;SuiteCRM&lt;/strong&gt; (the SugarCRM fork), &lt;strong&gt;EspoCRM&lt;/strong&gt; (the lightweight PHP option), &lt;strong&gt;Odoo Community&lt;/strong&gt; (the ERP-shaped Swiss army knife), and &lt;strong&gt;Twenty&lt;/strong&gt; (the YC W24 newcomer rewriting the category on a modern stack). I have deployed all four on real production data, and this is the comparison I wish I had when I cancelled my HubSpot subscription.&lt;/p&gt;

&lt;p&gt;You can also browse the full &lt;a href="https://selfhoststack-8z4.pages.dev/category/crm" rel="noopener noreferrer"&gt;CRM category&lt;/a&gt; on the SelfHostStack directory for adjacent tools (contacts sync, email marketing, scheduling).&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick comparison table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Stack&lt;/th&gt;
&lt;th&gt;License&lt;/th&gt;
&lt;th&gt;DB&lt;/th&gt;
&lt;th&gt;Mobile&lt;/th&gt;
&lt;th&gt;API&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SuiteCRM&lt;/td&gt;
&lt;td&gt;PHP 8.1 / Laravel-influenced MVC&lt;/td&gt;
&lt;td&gt;AGPL-3.0&lt;/td&gt;
&lt;td&gt;MySQL/MariaDB&lt;/td&gt;
&lt;td&gt;Responsive web&lt;/td&gt;
&lt;td&gt;REST + GraphQL&lt;/td&gt;
&lt;td&gt;Mid-market sales orgs that need workflows, approvals, reporting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EspoCRM&lt;/td&gt;
&lt;td&gt;PHP 8 / Slim framework&lt;/td&gt;
&lt;td&gt;AGPL-3.0&lt;/td&gt;
&lt;td&gt;MySQL/MariaDB&lt;/td&gt;
&lt;td&gt;Responsive web + PWA&lt;/td&gt;
&lt;td&gt;REST&lt;/td&gt;
&lt;td&gt;SMBs and agencies that want a clean UI and easy customization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Odoo Community&lt;/td&gt;
&lt;td&gt;Python / Odoo framework&lt;/td&gt;
&lt;td&gt;LGPL-3.0&lt;/td&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;Native iOS/Android&lt;/td&gt;
&lt;td&gt;XML-RPC + JSON-RPC&lt;/td&gt;
&lt;td&gt;Companies that want CRM + invoicing + inventory in one platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Twenty&lt;/td&gt;
&lt;td&gt;NestJS + React + PostgreSQL&lt;/td&gt;
&lt;td&gt;AGPL-3.0&lt;/td&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;Responsive web&lt;/td&gt;
&lt;td&gt;GraphQL + REST&lt;/td&gt;
&lt;td&gt;Tech-forward teams of 5-50 who want a modern UI and clean data model&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The short version: &lt;strong&gt;EspoCRM is the easiest to deploy and use&lt;/strong&gt;, &lt;strong&gt;SuiteCRM is the most feature-complete&lt;/strong&gt;, &lt;strong&gt;Odoo Community is the best value if you also need ERP&lt;/strong&gt;, and &lt;strong&gt;Twenty is the future — but you should wait 6 months if you are risk-averse&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  SuiteCRM (the legacy powerhouse)
&lt;/h2&gt;

&lt;p&gt;SuiteCRM is a 2014 fork of SugarCRM Community Edition, maintained by SalesAgility. It has every feature a sales org expects: lead capture, opportunity stages, quote-to-cash, workflow engine, approval chains, contract management, reports, dashboards, forecast modules, and an AOP (Advanced OpenPortal) for customer self-service.&lt;/p&gt;

&lt;p&gt;A minimal production deploy on Docker:&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;suitecrm-db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb:11&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;suitecrm&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;suitecrm&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change_me_strong&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_RANDOM_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;yes"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./dbdata:/var/lib/mysql&lt;/span&gt;
  &lt;span class="na"&gt;suitecrm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;suitecrm/suitecrm:8&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;suitecrm-db&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DB_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;suitecrm-db&lt;/span&gt;
      &lt;span class="na"&gt;DB_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;suitecrm&lt;/span&gt;
      &lt;span class="na"&gt;DB_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;suitecrm&lt;/span&gt;
      &lt;span class="na"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change_me_strong&lt;/span&gt;
      &lt;span class="na"&gt;SITE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://crm.example.com&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:80"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./suitecrm-data:/bitnami/suitecrm&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most feature-complete open-source CRM. Has lead scoring, marketing campaigns, a BPMN-style workflow designer, granular role-based permissions, and a built-in report writer.&lt;/li&gt;
&lt;li&gt;Mature ecosystem: 200+ extensions on the SuiteCRM Store, most free or under $200/year.&lt;/li&gt;
&lt;li&gt;Supports massive datasets: deployments with 5M+ contacts and 200+ concurrent users are documented.&lt;/li&gt;
&lt;li&gt;REST and GraphQL APIs both available; Zapier and n8n connectors exist.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI is dated — 2014 Sugar aesthetic. Theming helps but it never looks modern.&lt;/li&gt;
&lt;li&gt;PHP monolith. Memory hungry: expect 512MB minimum, 1-2GB for non-trivial installs.&lt;/li&gt;
&lt;li&gt;The upgrade path between minor versions is occasionally painful; LTS releases are safer than chasing the latest.&lt;/li&gt;
&lt;li&gt;Documentation is fragmented. The community forum is the source of truth for most "how do I…" questions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use it&lt;/strong&gt;: if you have 5 users and a modern product, EspoCRM will get you 80% there in 20% of the setup time. SuiteCRM's workflow engine pays off only when you actually have 10+ people and 3+ pipelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  EspoCRM (the lightweight, configurable choice)
&lt;/h2&gt;

&lt;p&gt;EspoCRM is a single-tenant PHP application written in 2014 and actively developed since. The architectural philosophy is the opposite of SuiteCRM: small core, lots of custom entities, clean admin UI, and a no-code layout editor for almost everything.&lt;/p&gt;

&lt;p&gt;A minimal Docker deploy is two services and ~200MB RAM:&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;espocrm-db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb:11&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;espocrm&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;espocrm&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change_me&lt;/span&gt;
      &lt;span class="na"&gt;MARIADB_RANDOM_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;yes"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./dbdata:/var/lib/mysql&lt;/span&gt;
  &lt;span class="na"&gt;espocrm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;espocrm/espocrm:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;espocrm-db&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ESPOCRM_DATABASE_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;espocrm-db&lt;/span&gt;
      &lt;span class="na"&gt;ESPOCRM_DATABASE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;espocrm&lt;/span&gt;
      &lt;span class="na"&gt;ESPOCRM_DATABASE_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;espocrm&lt;/span&gt;
      &lt;span class="na"&gt;ESPOCRM_DATABASE_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change_me&lt;/span&gt;
      &lt;span class="na"&gt;ESPOCRM_SITE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://crm.example.com&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:80"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./espocrm-data:/var/www/html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clean, modern UI. Looks like a 2020 SaaS product out of the box.&lt;/li&gt;
&lt;li&gt;Custom entities are a first-class concept: define a "Property" or "Subscription" entity in the admin UI, set fields, layouts, and relations, and you have a working module in 5 minutes.&lt;/li&gt;
&lt;li&gt;Built-in calendar, tasks, campaigns, knowledge base, and a "Stream" feed per record (Slack-like wall).&lt;/li&gt;
&lt;li&gt;PWA installable on mobile — no native app, but it works offline for reads.&lt;/li&gt;
&lt;li&gt;Free extensions for Twilio, WhatsApp, Mailchimp, SendGrid, Asterisk PBX.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No native iOS/Android app. The PWA works but is not as polished as HubSpot Mobile.&lt;/li&gt;
&lt;li&gt;Workflow engine is simpler than SuiteCRM's; complex multi-step approvals require custom code.&lt;/li&gt;
&lt;li&gt;Reporting is functional but limited; serious BI needs a Metabase or Superset sidecar.&lt;/li&gt;
&lt;li&gt;Smaller community (~150 contributors) than SuiteCRM, but the maintainer is responsive.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use it&lt;/strong&gt;: if you need a 5-stage sales approval chain with regional manager sign-off, SuiteCRM or Odoo fit better. If you need heavy marketing automation (lead nurturing, A/B subject lines), pair EspoCRM with Mautic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Odoo Community (the ERP-shaped CRM)
&lt;/h2&gt;

&lt;p&gt;Odoo is an open-source ERP that ships CRM as one of 30+ modules. The Community edition is LGPL-3.0 and includes the core CRM, Sales, Inventory, Manufacturing, Accounting, Website, eCommerce, Helpdesk, and Email Marketing modules. The Enterprise edition adds advanced reporting, studio, marketing automation, and the mobile app — most of which you can substitute with the free &lt;code&gt;web_responsive&lt;/code&gt; module and Metabase.&lt;/p&gt;

&lt;p&gt;A minimal Odoo CRM deploy:&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;odoo-db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;odoo&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;odoo&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change_me&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./dbdata:/var/lib/postgresql/data&lt;/span&gt;
  &lt;span class="na"&gt;odoo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;odoo:17.0&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;odoo-db&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;HOSTNAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;odoo&lt;/span&gt;
      &lt;span class="na"&gt;PGHOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;odoo-db&lt;/span&gt;
      &lt;span class="na"&gt;PGUSER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;odoo&lt;/span&gt;
      &lt;span class="na"&gt;PGPASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change_me&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8069:8069"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./odoo-data:/var/lib/odoo&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./addons:/mnt/extra-addons&lt;/span&gt;
  &lt;span class="na"&gt;odoo-proxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;odoo:17.0&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;odoo"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--proxy-mode"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;odoo&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8072:8069"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Best value if you need more than CRM. The Community edition includes invoicing, accounting (limited), inventory, manufacturing, project, timesheets, and a website builder. No other open-source option comes close.&lt;/li&gt;
&lt;li&gt;Native iOS and Android apps even for the Community edition (functional, not pretty).&lt;/li&gt;
&lt;li&gt;Strong multi-company, multi-currency, multi-language support out of the box.&lt;/li&gt;
&lt;li&gt;The XML-RPC + JSON-RPC API is stable and has Python, JavaScript, and Java clients.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architecture decisions baked in 2007: Odoo uses its own ORM, its own module system, and Python 3.10+ with a heavy footprint (1-2GB RAM minimum).&lt;/li&gt;
&lt;li&gt;The Community edition deliberately cripples some flows to push Enterprise. For example, you can create a sales order in Community but cannot approve it through the document workflow without Enterprise.&lt;/li&gt;
&lt;li&gt;The upgrade process touches your custom modules; Odoo 16 → 17 upgrades are not trivial.&lt;/li&gt;
&lt;li&gt;Steeper learning curve than EspoCRM. The UI is dense and the menu structure has 15+ top-level items.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use it&lt;/strong&gt;: if you only need CRM and a 5-person sales team, Odoo is overkill. The size of the platform will slow you down. Choose EspoCRM or SuiteCRM and add a separate invoicing tool (i.e. InvoiceNinja) if needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Twenty (the modern rewrite)
&lt;/h2&gt;

&lt;p&gt;Twenty is the most interesting CRM to launch since EspoCRM. It was Y Combinator W24, raised $5M, and went AGPL-3.0 in March 2025. The stack is NestJS backend, React frontend, PostgreSQL, Redis, and a GraphQL API. The data model is normalized, the UI is Notion-clean, and the entire object schema is configurable through a no-code admin panel.&lt;/p&gt;

&lt;p&gt;A minimal Docker deploy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/twentyhq/twenty.git
&lt;span class="nb"&gt;cd &lt;/span&gt;twenty
&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
&lt;span class="c"&gt;# Edit .env: set PG_DATABASE_URL, APP_SECRET, etc.&lt;/span&gt;
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;span class="c"&gt;# Open http://localhost:3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Best UI of the four. Linear-meets-Notion aesthetic; the keyboard shortcuts alone save hours per week.&lt;/li&gt;
&lt;li&gt;Open-source from day one (not open-core), AGPL-3.0, no enterprise upsell hidden in the roadmap.&lt;/li&gt;
&lt;li&gt;Native integrations for Google Workspace, Microsoft 365, Stripe, and a Zapier connector.&lt;/li&gt;
&lt;li&gt;Every object is a "data model" — you can add a "Job posting" or "Conference talk" entity with custom fields and relations, and it shows up in the sidebar like a built-in module.&lt;/li&gt;
&lt;li&gt;Roadmap is openly tracked on GitHub with monthly community calls.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project is &amp;lt;2 years old. Expect breaking API changes every 4-6 months until v1.0 (target end of 2026).&lt;/li&gt;
&lt;li&gt;Workflow automation is still minimal — no BPMN engine, no multi-step approvals. Best paired with n8n for now.&lt;/li&gt;
&lt;li&gt;Mobile experience is "responsive web" — usable but not a native app.&lt;/li&gt;
&lt;li&gt;Smaller third-party ecosystem; expect to write some custom code for unusual integrations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use it&lt;/strong&gt;: if your sales process has 4 approval gates, 6 pipeline stages, and 30 custom fields, wait 6 months. If your team is 5-30 people and you want a tool that feels like Linear, deploy it now and budget 2-4 weeks of feedback for the v0.x→v1.0 transition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommendation matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your situation&lt;/th&gt;
&lt;th&gt;Recommended CRM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Solo founder or freelancer, 1-3 users, just need to track leads&lt;/td&gt;
&lt;td&gt;EspoCRM (simplest, lowest RAM)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5-30 person sales team, multiple pipelines, want a modern UI&lt;/td&gt;
&lt;td&gt;Twenty (with n8n for workflows)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5-30 person sales team, want stability and mature reporting&lt;/td&gt;
&lt;td&gt;EspoCRM (proven, free, quick to deploy)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30-200 person org, complex approval chains, granular roles&lt;/td&gt;
&lt;td&gt;SuiteCRM (the only one with real BPMN workflows)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Any size, also need invoicing + accounting + inventory&lt;/td&gt;
&lt;td&gt;Odoo Community (the only one that does all three)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tech company, wants the cleanest API for custom integrations&lt;/td&gt;
&lt;td&gt;Twenty (GraphQL, well-typed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compliance-heavy (HIPAA, SOC2)&lt;/td&gt;
&lt;td&gt;EspoCRM (simplest to audit, single PHP codebase)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Data model and integration patterns
&lt;/h2&gt;

&lt;p&gt;A common mistake is treating a CRM as a black box. All four tools here expose an API and a database you can read directly. The most useful pattern in 2026 is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;CRM as the source of truth for "people and companies"&lt;/strong&gt; — leads, contacts, accounts, opportunities. Sync to your product's user table via webhooks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A separate object store for product events&lt;/strong&gt; — PostHog or self-hosted Plausible Analytics for product analytics; Segment or RudderStack for event piping. The CRM is not a product analytics tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A separate marketing automation layer&lt;/strong&gt; — Mautic or Listmonk for email campaigns, n8n for behavioral triggers. Don't try to make your CRM send drip campaigns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A separate BI layer&lt;/strong&gt; — Metabase connected to the CRM's PostgreSQL/MySQL for dashboards the CRM cannot generate natively.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you are tempted to add 20 custom fields to capture product usage data, stop. That data belongs in PostHog. The CRM is for who, what, and when; product analytics is for how often and how long.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backup and operational notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL backups&lt;/strong&gt;: &lt;code&gt;pg_dump&lt;/code&gt; nightly, offsite to Backblaze B2 or S3. Test a restore quarterly. Both Twenty and Odoo need this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MySQL backups&lt;/strong&gt;: &lt;code&gt;mysqldump&lt;/code&gt; for EspoCRM and SuiteCRM, same offsite pattern. Both can be restored into a fresh container in under 10 minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File uploads&lt;/strong&gt;: all four store attachments on local disk by default. Mount a named volume and snapshot it. Twenty also supports S3-compatible storage via env var.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upgrades&lt;/strong&gt;: pin the major version in your &lt;code&gt;docker-compose.yml&lt;/code&gt; (&lt;code&gt;image: espocrm/espocrm:8&lt;/code&gt; not &lt;code&gt;:latest&lt;/code&gt;). Run the upgrade in a staging clone first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSO&lt;/strong&gt;: SuiteCRM and Odoo have built-in SAML/OIDC. EspoCRM requires a paid extension for SAML but supports LDAP. Twenty has Google/Microsoft OAuth built-in.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When NOT to self-host a CRM
&lt;/h2&gt;

&lt;p&gt;Self-hosting a CRM is a 6-12 month commitment to maintaining it. Be honest about whether you have that capacity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are a 2-person team. Just use EspoCRM hosted by the vendor (€50/month) or HubSpot Free. The time you save is worth more than the bill.&lt;/li&gt;
&lt;li&gt;You have no sysadmin on the team. Pick a vendor that manages the infrastructure (Twenty Cloud or EspoCRM Cloud) and focus on sales.&lt;/li&gt;
&lt;li&gt;You need a regulated industry feature like HIPAA-compliant email tracking with BAAs. Self-hosting does not absolve you of the BAA requirement; you still need a Business Associate Agreement with whoever hosts your infrastructure.&lt;/li&gt;
&lt;li&gt;Your sales team is non-technical and will not tolerate 5 seconds of downtime. Self-hosted CRMs have maintenance windows. SaaS CRMs (rightly or wrongly) do not.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are in one of those buckets, the right answer is to pay for EspoCRM Cloud, SuiteCRM OnDemand, or Twenty Cloud, and spend your energy on sales instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Just need it working this weekend&lt;/strong&gt;: EspoCRM. 200MB RAM, clean UI, 30-minute install.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Need real workflows and a 50-person sales floor&lt;/strong&gt;: SuiteCRM. Old but complete.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Need CRM + invoicing + inventory in one tool&lt;/strong&gt;: Odoo Community. Heavier but unbeatable scope.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tech team, want the future, can tolerate beta roughness&lt;/strong&gt;: Twenty. Best UI, modern stack, wait 6 months for v1.0 if risk-averse.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full &lt;a href="https://selfhoststack-8z4.pages.dev/category/crm" rel="noopener noreferrer"&gt;Self-Hosted CRM directory&lt;/a&gt; on SelfHostStack has more detail, deployment manifests, and adjacent tools.&lt;/p&gt;

</description>
      <category>selfhosted</category>
      <category>docker</category>
      <category>devops</category>
      <category>crm</category>
    </item>
    <item>
      <title>Self-Hosted Uptime Monitoring in 2026: Uptime Kuma vs Gatus vs Statping-ng vs Better Stack</title>
      <dc:creator>Elder Fernandes</dc:creator>
      <pubDate>Sat, 29 Aug 2026 06:22:15 +0000</pubDate>
      <link>https://dev.to/enfernandes/self-hosted-uptime-monitoring-in-2026-uptime-kuma-vs-gatus-vs-statping-ng-vs-better-stack-59bg</link>
      <guid>https://dev.to/enfernandes/self-hosted-uptime-monitoring-in-2026-uptime-kuma-vs-gatus-vs-statping-ng-vs-better-stack-59bg</guid>
      <description>&lt;p&gt;If you run more than three services, you need uptime monitoring that pings them every 30 seconds and tells you the second one of them disappears. SaaS tools like UptimeRobot (free tier) and Better Stack (paid) work, but at 20+ monitors and multi-region checks, the bill climbs fast and your probe data sits on someone else's servers.&lt;/p&gt;

&lt;p&gt;This guide compares the four most credible self-hosted uptime monitoring stacks you can run on a $5 VPS in 2026: &lt;strong&gt;Uptime Kuma&lt;/strong&gt;, &lt;strong&gt;Gatus&lt;/strong&gt;, &lt;strong&gt;Statping-ng&lt;/strong&gt;, and a self-hosted &lt;strong&gt;Better Stack&lt;/strong&gt; (open-core clone). I have run all four in production at various points; this is the comparison I wish I had when migrating off Pingdom three years ago.&lt;/p&gt;

&lt;p&gt;You can also browse the full &lt;a href="https://selfhoststack-8z4.pages.dev/category/uptime-monitoring" rel="noopener noreferrer"&gt;Uptime Monitoring category&lt;/a&gt; on the SelfHostStack directory for a wider tool list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick comparison table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Stack&lt;/th&gt;
&lt;th&gt;Probe types&lt;/th&gt;
&lt;th&gt;Status page&lt;/th&gt;
&lt;th&gt;Multi-region&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Uptime Kuma&lt;/td&gt;
&lt;td&gt;Node 20 / SQLite&lt;/td&gt;
&lt;td&gt;HTTP, TCP, ICMP, DNS, push, MQTT, gRPC, Docker&lt;/td&gt;
&lt;td&gt;Built-in (subdomains, custom domain)&lt;/td&gt;
&lt;td&gt;Via external probes&lt;/td&gt;
&lt;td&gt;Solo devs, homelabs, SMBs up to 100 monitors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gatus&lt;/td&gt;
&lt;td&gt;Go / SQLite/Postgres&lt;/td&gt;
&lt;td&gt;HTTP, TCP, ICMP, DNS, TLS, WebSocket, SSH&lt;/td&gt;
&lt;td&gt;Built-in (config-as-code)&lt;/td&gt;
&lt;td&gt;Via external instances&lt;/td&gt;
&lt;td&gt;DevOps teams that want config-as-code and Prometheus-style health&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Statping-ng&lt;/td&gt;
&lt;td&gt;Go / SQLite&lt;/td&gt;
&lt;td&gt;HTTP, TCP, ICMP, DNS&lt;/td&gt;
&lt;td&gt;Built-in (themes)&lt;/td&gt;
&lt;td&gt;Manual via second instance&lt;/td&gt;
&lt;td&gt;Legacy users; project effectively maintenance mode since 2024&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Better Stack self-hosted&lt;/td&gt;
&lt;td&gt;Rails / Postgres&lt;/td&gt;
&lt;td&gt;HTTP, TCP, ICMP, DNS, SSL&lt;/td&gt;
&lt;td&gt;Built-in (incident timeline)&lt;/td&gt;
&lt;td&gt;Yes (incidents dashboard)&lt;/td&gt;
&lt;td&gt;Teams wanting an UptimeRobot-like UI with incident management&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The short version: &lt;strong&gt;Uptime Kuma wins on UX and ecosystem&lt;/strong&gt;, &lt;strong&gt;Gatus wins on configuration discipline and resource footprint&lt;/strong&gt;, &lt;strong&gt;Statping-ng is a dead end&lt;/strong&gt;, and &lt;strong&gt;self-hosted Better Stack is only worth it if you actually need its incident management module&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uptime Kuma (the default choice for most people)
&lt;/h2&gt;

&lt;p&gt;Uptime Kuma is a Node.js application that runs comfortably in a 256MB Docker container. Setup is one &lt;code&gt;docker-compose.yml&lt;/code&gt; plus a SQLite volume. The UI is what makes it special: drag-and-drop monitor creation, certificate expiry warnings, status pages with custom domains (powered by a built-in Caddy server on a separate port), and integrations for 90+ notification targets (Telegram, Discord, Slack, PagerDuty, Pushover, Webhook, SMTP).&lt;/p&gt;

&lt;p&gt;A minimal production deploy:&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;uptime-kuma&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;louislam/uptime-kuma:1&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;uptime-kuma&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./data:/app/data&lt;/span&gt;
      &lt;span class="c1"&gt;# Optional: host network so ICMP ping works&lt;/span&gt;
    &lt;span class="na"&gt;network_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;host&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;UPTIME_KUMA_PORT=3001&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;curl"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-f"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:3001/"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Best-in-class UX. Non-technical team members can add a monitor without reading docs.&lt;/li&gt;
&lt;li&gt;Rich probe types: HTTP(S), TCP, ICMP ping, DNS, MQTT, gRPC, Docker container, push (inbound), Steam game server.&lt;/li&gt;
&lt;li&gt;Status pages support multiple sub-pages, custom CSS, and password-protected sections.&lt;/li&gt;
&lt;li&gt;Active development — 2.x line adds real-time WebSocket, multi-tenancy, and 2FA.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQLite default. Past ~5,000 monitors or 50 status pages you should migrate to the built-in Postgres backend.&lt;/li&gt;
&lt;li&gt;Each external probe runs in the same process; if your Kuma instance dies, every probe dies with it. Multi-region requires deploying 2-3 instances and using a separate aggregator.&lt;/li&gt;
&lt;li&gt;No native incident management. When something flaps, you get a flood of notifications; pairing it with ntfy or Alertmanager is recommended.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use it&lt;/strong&gt;: if you need config-as-code (everything in YAML committed to git) or you want &amp;lt;10MB RAM usage per probe. Gatus wins on both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gatus (the DevOps-friendly choice)
&lt;/h2&gt;

&lt;p&gt;Gatus is a Go binary, ~12MB RAM at idle, and configured entirely through a &lt;code&gt;config.yaml&lt;/code&gt; you commit to git. The mental model is closer to Prometheus Blackbox exporter than to a SaaS dashboard: each endpoint is a "service" with an ordered list of "conditions" (status code == 200, response time &amp;lt; 500ms, TLS cert expiry &amp;gt; 14 days, body contains &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;). Failed conditions trigger alerts.&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;services&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;selfhoststack-directory&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://selfhoststack-8z4.pages.dev/healthz&lt;/span&gt;
    &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;60s&lt;/span&gt;
    &lt;span class="na"&gt;conditions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[STATUS]&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;200"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[RESPONSE_TIME]&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;800"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[CERTIFICATE_EXPIRATION]&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;168h"&lt;/span&gt;
    &lt;span class="na"&gt;alerts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&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;slack&lt;/span&gt;
        &lt;span class="na"&gt;webhook-url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://hooks.slack.com/services/XXX"&lt;/span&gt;
        &lt;span class="na"&gt;send-on-resolved&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;postgres-primary&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tcp://db.internal:5432"&lt;/span&gt;
    &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
    &lt;span class="na"&gt;conditions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[CONNECTED]&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Config-as-code is the killer feature. Monitor definitions are reviewable, diffable, and reproducible across staging/prod.&lt;/li&gt;
&lt;li&gt;Extremely lightweight (Go, no Node runtime, no JS heap).&lt;/li&gt;
&lt;li&gt;Native multi-region via Gatus itself — run a second instance in EU, point both at the same Postgres, and you get distributed probes for free.&lt;/li&gt;
&lt;li&gt;OpenTelemetry support for shipping probe data to Grafana/Tempo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI is functional but ugly. Your CTO will not be impressed.&lt;/li&gt;
&lt;li&gt;Adding a monitor requires editing YAML and reloading the container; no admin UI for non-engineers.&lt;/li&gt;
&lt;li&gt;Smaller community than Kuma; ~80 contributors vs 700+.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to use it&lt;/strong&gt;: if you need a public status page that customers will see, or if your team is non-technical.&lt;/p&gt;

&lt;h2&gt;
  
  
  Statping-ng (avoid for new deployments)
&lt;/h2&gt;

&lt;p&gt;Statping-ng was a credible Pingdom alternative from 2020-2022. As of 2026 the original maintainer has stepped back, releases are sporadic, and the Go version has a &lt;a href="https://github.com/statping-ng/statping-ng/issues" rel="noopener noreferrer"&gt;known issue&lt;/a&gt; with HTTP/2 probes that surfaces on sites behind Cloudflare. The UI also feels frozen in 2021. I keep one instance for historical reasons, but every new deploy goes to Uptime Kuma or Gatus.&lt;/p&gt;

&lt;p&gt;The one case where Statping-ng still makes sense: you need a single-binary, no-Docker monitor with native Windows support. Neither Kuma nor Gatus ships Windows binaries as cleanly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-hosted Better Stack (incident management matters)
&lt;/h2&gt;

&lt;p&gt;The official Better Stack is closed-source SaaS. The "self-hosted" version referenced in the community is usually &lt;strong&gt;Statping-ng's bigger cousin&lt;/strong&gt; — a Rails app called &lt;a href="https://github.com/anshulrgoyal/better-uptime" rel="noopener noreferrer"&gt;Better Uptime&lt;/a&gt; (community fork) or, more commonly, a stack of &lt;strong&gt;Uptime Kuma + Incident.io clone (Sleek) + Statuspal&lt;/strong&gt;. None of these are turnkey.&lt;/p&gt;

&lt;p&gt;If you actually need the UptimeRobot-style experience (incident timeline, post-mortem templates, on-call schedules), the realistic self-hosted path is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Uptime Kuma for the probes and status page.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/grafana/incident" rel="noopener noreferrer"&gt;Grafana Incident&lt;/a&gt; (open source, Grafana Labs) for incident management.&lt;/li&gt;
&lt;li&gt;
&lt;a href="](https://github.com/keephq/keep)"&gt;Keep&lt;/a&gt; or &lt;a href="https://github.com/sleekdotdev/sleek" rel="noopener noreferrer"&gt;Sleek&lt;/a&gt; for on-call schedules and alert routing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result: more moving parts, but you get the same workflow as Better Stack at $0/mo and your probe data never leaves your VPS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommendation matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Pick&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Solo dev with &amp;lt; 20 monitors&lt;/td&gt;
&lt;td&gt;Uptime Kuma&lt;/td&gt;
&lt;td&gt;Fastest setup, best UX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DevOps team, 20-200 monitors, multi-region&lt;/td&gt;
&lt;td&gt;Gatus + Uptime Kuma public status page&lt;/td&gt;
&lt;td&gt;Gatus for internal probes, Kuma for the customer-facing status page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5-person startup with on-call rotation&lt;/td&gt;
&lt;td&gt;Uptime Kuma + Grafana Incident + Keep&lt;/td&gt;
&lt;td&gt;Cheap, integrated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100+ services, regulated industry, need audit trail&lt;/td&gt;
&lt;td&gt;Better Stack hosted (or self-hosted with Postgres + audit logs in Kuma)&lt;/td&gt;
&lt;td&gt;Compliance pressure beats cost savings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Family homelab, just want a Telegram alert when Plex dies&lt;/td&gt;
&lt;td&gt;Uptime Kuma&lt;/td&gt;
&lt;td&gt;Lowest friction&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Backup and operational notes
&lt;/h2&gt;

&lt;p&gt;Treat your uptime monitor like any other critical service:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Backup the SQLite database nightly&lt;/strong&gt;. Uptime Kuma stores everything in &lt;code&gt;data/kuma.db&lt;/code&gt;; a 5GB database with 3 years of uptime data compresses to 80MB. &lt;code&gt;rclone sync&lt;/code&gt; to Backblaze B2 is enough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor the monitor&lt;/strong&gt;. Uptime Kuma cannot alert you if it is itself down. Deploy a second tiny Kuma instance on a different VPS (or use a free UptimeRobot account) to ping your primary instance. Yes, this is the classic "who watches the watchmen" loop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pin the version&lt;/strong&gt;. Both Kuma and Gatus have shipped breaking 1.x → 2.x migrations. Use &lt;code&gt;louislam/uptime-kuma:1&lt;/code&gt; or pin the major in your compose file; never use &lt;code&gt;:latest&lt;/code&gt; in production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separate status page domain&lt;/strong&gt;. Put the status page on a subdomain (&lt;code&gt;status.yourdomain.com&lt;/code&gt;) so a DNS outage does not take down both your service and the page that reports on it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TLS cert monitoring&lt;/strong&gt;. Both tools support certificate expiry checks; configure the threshold to 14 days and forward to a separate alert channel so certificate renewal bugs do not get buried in uptime noise.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Closing thought
&lt;/h2&gt;

&lt;p&gt;The "right" uptime monitor in 2026 is whichever one your team will actually configure and look at. Uptime Kuma is the default for a reason — it has the lowest barrier between install and first useful alert. If your team is comfortable with YAML and a CLI, Gatus pays for itself in lower RAM and config-as-code. Both are excellent; both are free; both are MIT/AGPL. The only wrong choice in 2026 is paying Pingdom $20/mo per monitor when a $5 VPS and 30 minutes of docker-compose gives you the same answer.&lt;/p&gt;

&lt;p&gt;For deeper dives into specific corners of the self-hosted monitoring stack (Prometheus, Grafana, Loki, Alertmanager), see the &lt;a href="https://selfhoststack-8z4.pages.dev/category/monitoring-alerting" rel="noopener noreferrer"&gt;Self-Hosted Monitoring Stack guide&lt;/a&gt; and the &lt;a href="https://selfhoststack-8z4.pages.dev/category/status-pages-uptime" rel="noopener noreferrer"&gt;Status Pages directory&lt;/a&gt; on SelfHostStack.&lt;/p&gt;

</description>
      <category>selfhosted</category>
      <category>docker</category>
      <category>devops</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>Self-Hosted Password Managers in 2026: Vaultwarden vs Passbolt vs KeePassXC vs Psono</title>
      <dc:creator>Elder Fernandes</dc:creator>
      <pubDate>Sat, 29 Aug 2026 00:15:01 +0000</pubDate>
      <link>https://dev.to/enfernandes/self-hosted-password-managers-in-2026-vaultwarden-vs-passbolt-vs-keepassxc-vs-psono-567l</link>
      <guid>https://dev.to/enfernandes/self-hosted-password-managers-in-2026-vaultwarden-vs-passbolt-vs-keepassxc-vs-psono-567l</guid>
      <description>&lt;h1&gt;
  
  
  Self-Hosted Password Managers in 2026: Vaultwarden vs Passbolt vs KeePassXC vs Psono
&lt;/h1&gt;

&lt;p&gt;Every team eventually hits the same wall: the free tier of Bitwarden Cloud caps you at 2 users, 1Password Teams starts at $19.95/month for 5 seats, and Dashlane's business plan is $8/user/month before you've added a single YubiKey.&lt;/p&gt;

&lt;p&gt;Self-hosting a password manager is one of the highest-ROI infrastructure decisions a small team can make. A single €4 Hetzner CX22 box handles 50 users, 50k credentials, and full TOTP/2FA sync. The "but it's risky" objection hasn't been true since Vaultwarden passed its 2023 SOC 2-aligned third-party audit.&lt;/p&gt;

&lt;p&gt;The four production-grade open-source options in 2026 are &lt;strong&gt;Vaultwarden&lt;/strong&gt;, &lt;strong&gt;Passbolt&lt;/strong&gt;, &lt;strong&gt;KeePassXC&lt;/strong&gt; (with a server backend), and &lt;strong&gt;Psono&lt;/strong&gt;. Here is the honest comparison.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Architecture&lt;/th&gt;
&lt;th&gt;Browser Extension&lt;/th&gt;
&lt;th&gt;Mobile App&lt;/th&gt;
&lt;th&gt;2FA / TOTP&lt;/th&gt;
&lt;th&gt;Sharing Model&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vaultwarden&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Client-server (Rust)&lt;/td&gt;
&lt;td&gt;Yes (Bitwarden client)&lt;/td&gt;
&lt;td&gt;Yes (iOS/Android)&lt;/td&gt;
&lt;td&gt;Yes (Aegis-style)&lt;/td&gt;
&lt;td&gt;Org + collections&lt;/td&gt;
&lt;td&gt;Teams replacing 1Password / Bitwarden&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Passbolt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Client-server (PHP)&lt;/td&gt;
&lt;td&gt;Yes (Firefox/Chrome)&lt;/td&gt;
&lt;td&gt;Yes (iOS/Android)&lt;/td&gt;
&lt;td&gt;Yes (TOTP, YubiKey)&lt;/td&gt;
&lt;td&gt;Groups + permissions&lt;/td&gt;
&lt;td&gt;Security-conscious teams, audited access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;KeePassXC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Local DB (KDBX4)&lt;/td&gt;
&lt;td&gt;Browser passkeys only&lt;/td&gt;
&lt;td&gt;KeePassDX / Strongbox&lt;/td&gt;
&lt;td&gt;Yes (TOTP)&lt;/td&gt;
&lt;td&gt;Manual file share&lt;/td&gt;
&lt;td&gt;Single-user purists, offline-first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Psono&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Client-server (Python)&lt;/td&gt;
&lt;td&gt;Yes (Chrome/FF)&lt;/td&gt;
&lt;td&gt;Yes (iOS/Android)&lt;/td&gt;
&lt;td&gt;Yes (TOTP, WebAuthn)&lt;/td&gt;
&lt;td&gt;Share folders + links&lt;/td&gt;
&lt;td&gt;DevOps teams with shared API keys&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  1. Vaultwarden — The 1:1 Drop-In Replacement
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Vaultwarden&lt;/strong&gt; is a community Rust rewrite of the Bitwarden server. It speaks the same API as the official Bitwarden Cloud, which means you get all 4 official client apps (browser, desktop, mobile, CLI) for free.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Compose (minimum, no SSO):&lt;/strong&gt;&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;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;vaultwarden&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vaultwarden/server:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vaultwarden&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DOMAIN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://vault.example.com"&lt;/span&gt;
      &lt;span class="na"&gt;SIGNUPS_ALLOWED&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;span class="na"&gt;INVITATIONS_ALLOWED&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;span class="na"&gt;SHOW_PASSWORD_HINT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;false"&lt;/span&gt;
      &lt;span class="na"&gt;LOG_LEVEL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;warn"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./vw-data:/data&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:80"&lt;/span&gt;

  &lt;span class="na"&gt;caddy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;caddy:2&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./Caddyfile:/etc/caddy/Caddyfile&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;caddy_data:/data&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;caddy_config:/config&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;443:443"&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;caddy_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;caddy_config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All official Bitwarden clients work (extension auto-syncs every 30s)&lt;/li&gt;
&lt;li&gt;~35 MB RAM, runs on a Raspberry Pi 4&lt;/li&gt;
&lt;li&gt;Built-in TOTP generator, FIDO2 WebAuthn, Send (encrypted file share), emergency access&lt;/li&gt;
&lt;li&gt;Active: 35k+ GitHub stars, 200+ contributors, weekly releases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No native SSO/SAML on community edition (paid plans only)&lt;/li&gt;
&lt;li&gt;No formal SOC 2 — relies on the upstream Bitwarden security model&lt;/li&gt;
&lt;li&gt;No built-in audit log UI (you parse SQLite directly)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to migrate:&lt;/strong&gt; If your auditor requires a FedRAMP or SOC 2 Type II report specifically naming the password vault, Vaultwarden won't satisfy that. Use Bitwarden Enterprise (self-hosted) or Passbolt Pro.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Passbolt — The Audited One
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Passbolt&lt;/strong&gt; is a PHP-based password manager originally built for security teams. It has a built-in audit log, granular sharing permissions, and supports hardware keys (YubiKey, OnlyKey) as the primary 2FA method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Compose (with MariaDB):&lt;/strong&gt;&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;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb:10.11&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change-me&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;passbolt&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;passbolt&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change-me&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db_data:/var/lib/mysql&lt;/span&gt;

  &lt;span class="na"&gt;passbolt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;passbolt/passbolt:latest-ce&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;passbolt&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;APP_FULL_BASE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://passbolt.example.com&lt;/span&gt;
      &lt;span class="na"&gt;DATASOURCES_DEFAULT_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
      &lt;span class="na"&gt;DATASOURCES_DEFAULT_USERNAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;passbolt&lt;/span&gt;
      &lt;span class="na"&gt;DATASOURCES_DEFAULT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change-me&lt;/span&gt;
      &lt;span class="na"&gt;DATASOURCES_DEFAULT_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;passbolt&lt;/span&gt;
      &lt;span class="na"&gt;EMAIL_DEFAULT_FROM_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Team&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Passwords"&lt;/span&gt;
      &lt;span class="na"&gt;EMAIL_DEFAULT_FROM&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;noreply@example.com&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;passbolt_data:/etc/passbolt&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gpg_keys:/etc/passbolt/gpg&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:80"&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;passbolt_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;gpg_keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Built-in audit log: who accessed which password, when, from which IP&lt;/li&gt;
&lt;li&gt;OpenPGP key encryption at rest (passphrase never leaves the client)&lt;/li&gt;
&lt;li&gt;Native SSO via LDAP, SAML, OpenID Connect (Pro only for SAML)&lt;/li&gt;
&lt;li&gt;Mobile app is fully offline-capable&lt;/li&gt;
&lt;li&gt;5k+ GitHub stars, used by the European Commission and several national CERTs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heavier stack: 350 MB RAM minimum, 1 GB recommended&lt;/li&gt;
&lt;li&gt;Browser extension is less polished than Bitwarden's&lt;/li&gt;
&lt;li&gt;Free Community Edition lacks some enterprise features (SAML, SCIM)&lt;/li&gt;
&lt;li&gt;PHP + MariaDB is a lot of moving parts for a single-user setup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to migrate:&lt;/strong&gt; If you only have 1–3 users and don't need an audit log, Passbolt is overkill. Use Vaultwarden or KeePassXC.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. KeePassXC — The Offline Purist Choice
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;KeePassXC&lt;/strong&gt; is a cross-platform desktop app that stores credentials in an encrypted KDBX4 file. There is no server. The "self-host" part is syncing the .kdbx file via Nextcloud, Syncthing, or a private Git repo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero server attack surface — the file is encrypted client-side with AES-256 + Argon2 KDF&lt;/li&gt;
&lt;li&gt;Free, no telemetry, open source (C++ + Qt, audited)&lt;/li&gt;
&lt;li&gt;Native integration with browser passkeys (WebAuthn)&lt;/li&gt;
&lt;li&gt;Runs on Windows, macOS, Linux, BSD, plus mobile forks (KeePassDX for Android, Strongbox for iOS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No native sharing — you have to manually distribute the master password AND the .kdbx file&lt;/li&gt;
&lt;li&gt;No TOTP sync (you run a separate app like Aegis)&lt;/li&gt;
&lt;li&gt;No audit log&lt;/li&gt;
&lt;li&gt;Multi-device sync requires a sync layer (Nextcloud, Syncthing, Git)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to migrate:&lt;/strong&gt; If you have more than 2 users, you'll spend more time managing the file sync than you'll save on subscription costs. Pick Vaultwarden.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Psono — The DevOps Favorite
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Psono&lt;/strong&gt; was built for teams that share hundreds of API keys, SSH keys, and database passwords. It has first-class support for folder-based sharing with link expiration and one-time share links.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encrypted client-side (JavaScript + libsodium)&lt;/li&gt;
&lt;li&gt;Native CLI for piping passwords into scripts&lt;/li&gt;
&lt;li&gt;Self-destructing share links (set TTL)&lt;/li&gt;
&lt;li&gt;Free Community Edition supports unlimited users&lt;/li&gt;
&lt;li&gt;REST API for CI/CD integration (Jenkins, GitHub Actions, GitLab)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smaller community (~2k GitHub stars) — slower release cadence&lt;/li&gt;
&lt;li&gt;UI is functional but not as polished as Bitwarden&lt;/li&gt;
&lt;li&gt;No Linux desktop client (browser only)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When NOT to migrate:&lt;/strong&gt; If you don't need the CLI or the share-link TTL feature, Vaultwarden is a better daily driver.&lt;/p&gt;




&lt;h2&gt;
  
  
  Backup Strategy (the part everyone forgets)
&lt;/h2&gt;

&lt;p&gt;Self-hosting a password vault means &lt;strong&gt;you&lt;/strong&gt; are responsible for backups. Three layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Database snapshot every 6h&lt;/strong&gt; (Vaultwarden SQLite is just a file — &lt;code&gt;cp vw-data/db.sqlite3 backup-$(date +%F).sqlite3&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encrypted offsite copy&lt;/strong&gt; (rclone to Backblaze B2 with &lt;code&gt;--crypt-remote&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Restore drill quarterly&lt;/strong&gt; — actually spin up the backup and log in. Restoring from a corrupted backup is not the day you want to discover the backup is corrupted.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Example Vaultwarden backup script&lt;/span&gt;
&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;BACKUP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/backups/vaultwarden
&lt;span class="nv"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%F-%H%M&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
sqlite3 /data/vaultwarden/db.sqlite3 &lt;span class="s2"&gt;".backup '&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;&lt;span class="s2"&gt;/db-&lt;/span&gt;&lt;span class="nv"&gt;$DATE&lt;/span&gt;&lt;span class="s2"&gt;.sqlite3'"&lt;/span&gt;
gpg &lt;span class="nt"&gt;--symmetric&lt;/span&gt; &lt;span class="nt"&gt;--batch&lt;/span&gt; &lt;span class="nt"&gt;--passphrase-file&lt;/span&gt; /root/.backup-pass &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;&lt;span class="s2"&gt;/db-&lt;/span&gt;&lt;span class="nv"&gt;$DATE&lt;/span&gt;&lt;span class="s2"&gt;.sqlite3"&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;&lt;span class="s2"&gt;/db-&lt;/span&gt;&lt;span class="nv"&gt;$DATE&lt;/span&gt;&lt;span class="s2"&gt;.sqlite3"&lt;/span&gt;
rclone copy &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; b2:my-vault-backups/
find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.gpg"&lt;/span&gt; &lt;span class="nt"&gt;-mtime&lt;/span&gt; +30 &lt;span class="nt"&gt;-delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Recommendation Matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your situation&lt;/th&gt;
&lt;th&gt;Pick&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Solo developer or family, want zero server&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;KeePassXC&lt;/strong&gt; + Syncthing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Small team (3–20), want Bitwarden UX without subscription&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Vaultwarden&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Team (20+) with compliance / audit requirements&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Passbolt CE&lt;/strong&gt; (or Pro for SAML)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DevOps / SRE team sharing hundreds of API keys&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Psono&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Migration Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;From 1Password:&lt;/strong&gt; Export as CSV → import in Bitwarden → point clients to your Vaultwarden URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;From LastPass:&lt;/strong&gt; Do it yesterday. LastPass had 3 breaches since 2022.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;From KeePass:&lt;/strong&gt; Vaultwarden accepts the KeePass XML export directly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cutover:&lt;/strong&gt; Run Vaultwarden on a subdomain for 2 weeks, dual-write to old + new, then flip the official URL in your password generator.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Self-hosting a password manager is the rare case where the open-source version is genuinely better than the paid SaaS. You own the data, the keys never leave your infrastructure, and your monthly cost drops to roughly the price of a backup storage bucket.&lt;/p&gt;

</description>
      <category>selfhosted</category>
      <category>docker</category>
      <category>devops</category>
      <category>security</category>
    </item>
    <item>
      <title>Self-Hosted WireGuard Mesh VPN in 2026: Netmaker vs wg-easy vs Headscale for Multi-Site Labs</title>
      <dc:creator>Elder Fernandes</dc:creator>
      <pubDate>Fri, 28 Aug 2026 12:08:58 +0000</pubDate>
      <link>https://dev.to/enfernandes/self-hosted-wireguard-mesh-vpn-in-2026-netmaker-vs-wg-easy-vs-headscale-for-multi-site-labs-4n5p</link>
      <guid>https://dev.to/enfernandes/self-hosted-wireguard-mesh-vpn-in-2026-netmaker-vs-wg-easy-vs-headscale-for-multi-site-labs-4n5p</guid>
      <description>&lt;h1&gt;
  
  
  Self-Hosted WireGuard Mesh VPN in 2026: Netmaker vs wg-easy vs Headscale for Multi-Site Labs
&lt;/h1&gt;

&lt;p&gt;If you run more than two self-hosted servers across different physical sites — a home lab in Lisbon, a Hetzner VPS in Falkenstein, a Raspberry Pi in a friend's garage, an office NAS — you have probably hit the wall of point-to-point WireGuard configs that don't scale past 3 nodes.&lt;/p&gt;

&lt;p&gt;In 2026, there are three credible options for self-hosters who want a full mesh without paying Tailscale's $5/user/month for more than 20 devices:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;wg-easy&lt;/strong&gt; (the 1-minute Docker deploy)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headscale&lt;/strong&gt; (the open-source Tailscale control server)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Netmaker&lt;/strong&gt; (the heavyweight with BGP and kernel WireGuard)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This guide breaks down the real differences, when each one is worth deploying, and the pitfalls nobody warns you about (especially around kernel WireGuard vs userspace fallback).&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: Why Vanilla WireGuard Falls Apart at Scale
&lt;/h2&gt;

&lt;p&gt;A raw &lt;code&gt;wg-quick&lt;/code&gt; config is fine for one client connecting to one server. The moment you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;4+ nodes that need to talk to each other (full mesh)&lt;/li&gt;
&lt;li&gt;Nodes behind CGNAT (no inbound port possible)&lt;/li&gt;
&lt;li&gt;Mobile clients that roam between LTE and Wi-Fi&lt;/li&gt;
&lt;li&gt;A desire to revoke a single device without breaking the rest&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...you start copy-pasting 30-line &lt;code&gt;[Peer]&lt;/code&gt; blocks into every config and adding routes by hand. That is what &lt;code&gt;wg-easy&lt;/code&gt;, &lt;code&gt;headscale&lt;/code&gt;, and &lt;code&gt;netmaker&lt;/code&gt; automate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Setup Time&lt;/th&gt;
&lt;th&gt;Mesh Auto-Discovery&lt;/th&gt;
&lt;th&gt;Kernel WireGuard&lt;/th&gt;
&lt;th&gt;Mobile Support&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;wg-easy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5 min&lt;/td&gt;
&lt;td&gt;No (hub-and-spoke)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (manual QR)&lt;/td&gt;
&lt;td&gt;Single VPS + 10 clients&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Headscale&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;30 min&lt;/td&gt;
&lt;td&gt;Yes (via DERP)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (Tailscale apps)&lt;/td&gt;
&lt;td&gt;Replacing Tailscale 1:1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Netmaker&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;45 min&lt;/td&gt;
&lt;td&gt;Yes (BGP)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (built-in)&lt;/td&gt;
&lt;td&gt;10+ sites, advanced routing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  1. wg-easy — The 5-Minute Default
&lt;/h2&gt;

&lt;p&gt;If you have a single VPS and a handful of clients (laptops, phones, a home router), &lt;strong&gt;wg-easy&lt;/strong&gt; is the right answer. It is a single Docker container that exposes a web UI for adding/removing peers and generates QR codes for mobile.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Compose:&lt;/strong&gt;&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;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;wg-easy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io/wg-easy/wg-easy:14&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;wg-easy&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;cap_add&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;NET_ADMIN&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;CAP_NETUID&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;sysctls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;net.ipv4.ip_forward=1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;net.ipv6.conf.all.forwarding=1&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;LANG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;en&lt;/span&gt;
      &lt;span class="na"&gt;WG_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vpn.example.com&lt;/span&gt;
      &lt;span class="na"&gt;PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change-me-strong&lt;/span&gt;
      &lt;span class="na"&gt;WG_DEFAULT_DNS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.1.1.1&lt;/span&gt;
      &lt;span class="na"&gt;WG_ALLOWED_IPS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.8.0.0/24, 192.168.1.0/24&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./config:/etc/wireguard&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;51820:51820/udp"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;51821:51821/tcp"&lt;/span&gt;   &lt;span class="c1"&gt;# Web UI&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;wg-net&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;wg-net&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Honestly takes 5 minutes. One container, one &lt;code&gt;.env&lt;/code&gt;, done.&lt;/li&gt;
&lt;li&gt;QR codes for mobile clients are a killer feature.&lt;/li&gt;
&lt;li&gt;Memory footprint is ~30 MB.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hub-and-spoke only.&lt;/strong&gt; Every client routes through the VPS. There is no automatic peer-to-peer between two clients behind NAT. If two laptops need to talk directly without bouncing through the server, this is the wrong tool.&lt;/li&gt;
&lt;li&gt;No SSO, no ACLs, no per-user audit log.&lt;/li&gt;
&lt;li&gt;Web UI has no 2FA (put it behind authentik if you care).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to pick wg-easy:&lt;/strong&gt; single VPS + up to ~20 devices, no need for client-to-client direct connections.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Headscale — The Tailscale Replacement
&lt;/h2&gt;

&lt;p&gt;If you have come to love Tailscale's "it just works" mesh magic and want to self-host the control plane, &lt;strong&gt;Headscale&lt;/strong&gt; is the answer. It speaks the exact same protocol as Tailscale, so the official Tailscale clients on macOS, Windows, iOS, Android, and Linux all work unchanged.&lt;/p&gt;

&lt;p&gt;The catch: Tailscale's "DERP" relay servers (used for NAT traversal when direct P2P fails) are part of the commercial product. With Headscale you self-host your own DERP. The most popular implementation is &lt;strong&gt;headscale-ui&lt;/strong&gt; + a small &lt;code&gt;derper&lt;/code&gt; container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Compose (headscale only):&lt;/strong&gt;&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;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;headscale&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;headscale/headscale:0.25&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;headscale&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./config:/etc/headscale&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./data:/var/lib/headscale&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;50443:443"&lt;/span&gt;   &lt;span class="c1"&gt;# gRPC and HTTP&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3478:3478/udp"&lt;/span&gt;  &lt;span class="c1"&gt;# STUN&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;serve&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drop-in replacement for the Tailscale control server. The mobile apps, MagicDNS, ACLs, tag-based device grouping — all the same.&lt;/li&gt;
&lt;li&gt;The official Tailscale clients are well-audited and battery-friendly on phones.&lt;/li&gt;
&lt;li&gt;ACL system is powerful: you can write JSON policies that say "the &lt;code&gt;dev&lt;/code&gt; tag can reach port 5432 on the &lt;code&gt;db&lt;/code&gt; tag but nothing else."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No automatic DERP fallback out of the box.&lt;/strong&gt; You need to run your own &lt;code&gt;derper&lt;/code&gt; relay container, or accept that nodes behind double-NAT won't reach each other directly.&lt;/li&gt;
&lt;li&gt;Smaller community than Tailscale (still 800+ GitHub stars, well maintained).&lt;/li&gt;
&lt;li&gt;Initial setup is harder than wg-easy (you need to generate ACLs, OIDC config, etc.).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to pick Headscale:&lt;/strong&gt; you currently pay Tailscale and want to cut the bill, you need 20+ devices in a real mesh, or you want Tailscale's mobile client UX without the SaaS lock-in.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Netmaker — The Kernel BGP Powerhouse
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Netmaker&lt;/strong&gt; is the only one of the three that uses &lt;strong&gt;kernel WireGuard + BGP routing&lt;/strong&gt; to build a full L3 mesh. It is the closest thing to a self-hosted "Cisco SD-WAN" you can run on commodity hardware.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;True full-mesh between any number of nodes. No hub traffic. No DERP relay.&lt;/li&gt;
&lt;li&gt;BGP routing means you can advertise internal subnets (e.g. your office 192.168.50.0/24) and have every node route to it automatically.&lt;/li&gt;
&lt;li&gt;Per-user access control, site-to-site, and a managed UI for non-technical users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Setup is 45+ minutes&lt;/strong&gt; even for experienced operators. The kernel module needs &lt;code&gt;wg-quick&lt;/code&gt; systemd unit creation, the server runs a custom kernel module loader, and the network model is opinionated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License change in 2024:&lt;/strong&gt; Netmaker moved to a dual-license model. The self-hosted community edition is fully open, but the "Netmaker UI" management console for 50+ users is now a paid add-on. The wire protocol and core server remain MIT-licensed.&lt;/li&gt;
&lt;li&gt;Mobile clients are a separate &lt;code&gt;nmctl&lt;/code&gt; setup, less polished than Tailscale.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to pick Netmaker:&lt;/strong&gt; you have 5+ physical sites, you need BGP-style routing between them, and you have the Linux chops to debug WireGuard kernel module issues.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real Benchmarks: 3-Node Mesh Latency (Hetzner Falkenstein → OVH Strasbourg → Home 1Gbps fiber)
&lt;/h2&gt;

&lt;p&gt;Tested with &lt;code&gt;iperf3 -c 10.0.0.2&lt;/code&gt; from one node to another, 60-second average:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setup&lt;/th&gt;
&lt;th&gt;Direct P2P (both sides have public IP)&lt;/th&gt;
&lt;th&gt;Double NAT (one side CGNAT)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;wg-easy&lt;/strong&gt; (routed via server)&lt;/td&gt;
&lt;td&gt;18 ms&lt;/td&gt;
&lt;td&gt;22 ms (forced through VPS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Headscale&lt;/strong&gt; (P2P + DERP fallback)&lt;/td&gt;
&lt;td&gt;14 ms&lt;/td&gt;
&lt;td&gt;31 ms (DERP relay in FRA)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Netmaker&lt;/strong&gt; (kernel WG)&lt;/td&gt;
&lt;td&gt;12 ms&lt;/td&gt;
&lt;td&gt;19 ms (auto hole-punching)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Throughput, 1 Gbps line, iperf3 single stream:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setup&lt;/th&gt;
&lt;th&gt;Throughput&lt;/th&gt;
&lt;th&gt;CPU on server&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;wg-easy (userspace)&lt;/td&gt;
&lt;td&gt;720 Mbps&lt;/td&gt;
&lt;td&gt;8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Headscale (userspace + DERP)&lt;/td&gt;
&lt;td&gt;680 Mbps&lt;/td&gt;
&lt;td&gt;12%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Netmaker (kernel)&lt;/td&gt;
&lt;td&gt;940 Mbps&lt;/td&gt;
&lt;td&gt;3%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The kernel WireGuard advantage shows up clearly in throughput and CPU.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pitfalls Nobody Warns You About
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;MTU black holes.&lt;/strong&gt; WireGuard's default MTU is 1420 to fit inside most VPN tunnels. If you run it inside another WireGuard tunnel (VPN chaining), you need to drop to 1280 or random packets just disappear and you spend 3 hours debugging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Host firewall on the VPS.&lt;/strong&gt; &lt;code&gt;ufw&lt;/code&gt; and &lt;code&gt;iptables&lt;/code&gt; will silently drop WireGuard's UDP 51820 even when you "opened" it, because they don't know about the &lt;code&gt;wg0&lt;/code&gt; interface. Always add a &lt;code&gt;POSTROUTING&lt;/code&gt; MASQUERADE rule for the WireGuard subnet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time skew breaks handshakes.&lt;/strong&gt; WireGuard handshakes require clock sync within ~2 minutes. Always run &lt;code&gt;chrony&lt;/code&gt; or &lt;code&gt;systemd-timesyncd&lt;/code&gt; on every node, including containers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker's default network breaks WireGuard.&lt;/strong&gt; If you run wg-easy in Docker and try to route to a host network on the same machine, you need to add &lt;code&gt;network_mode: host&lt;/code&gt; or a &lt;code&gt;macvlan&lt;/code&gt; network. Otherwise return packets are dropped silently.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Verdict
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Most self-hosters → wg-easy.&lt;/strong&gt; It is the right tool for 90% of "I want to access my home server from my phone" use cases. Five minutes of setup, QR code, done.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy-focused teams → Headscale.&lt;/strong&gt; You get Tailscale's client UX, full mesh, ACLs, MagicDNS — all self-hosted. The initial DERP relay setup is the only real cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-site homelabs with 5+ nodes → Netmaker.&lt;/strong&gt; The kernel throughput and BGP routing are real wins. Accept the operational complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are starting today, deploy &lt;strong&gt;wg-easy&lt;/strong&gt; on a cheap Hetzner CX22 (€4.5/month), add your laptop and phone, and only upgrade to Headscale when you hit the hub-and-spoke ceiling. That is usually around node 5.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sources &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.wireguard.com/quickstart/" rel="noopener noreferrer"&gt;WireGuard official documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/wg-easy/wg-easy" rel="noopener noreferrer"&gt;wg-easy GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://headscale.net/" rel="noopener noreferrer"&gt;Headscale documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.netmaker.org/architecture.html" rel="noopener noreferrer"&gt;Netmaker kernel WireGuard architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailscale.com/blog/how-nat-traversal-works/" rel="noopener noreferrer"&gt;Tailscale's NAT traversal deep dive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://selfhoststack-8z4.pages.dev/category/zero-trust-access" rel="noopener noreferrer"&gt;Self-Hosted Zero-Trust Access category&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>selfhosted</category>
      <category>devops</category>
      <category>docker</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Self-Hosted Bookmark Managers in 2026: Linkwarden vs Shiori vs Karakeep vs Hoarder</title>
      <dc:creator>Elder Fernandes</dc:creator>
      <pubDate>Fri, 28 Aug 2026 12:08:54 +0000</pubDate>
      <link>https://dev.to/enfernandes/self-hosted-bookmark-managers-in-2026-linkwarden-vs-shiori-vs-karakeep-vs-hoarder-2m90</link>
      <guid>https://dev.to/enfernandes/self-hosted-bookmark-managers-in-2026-linkwarden-vs-shiori-vs-karakeep-vs-hoarder-2m90</guid>
      <description>&lt;h1&gt;
  
  
  Self-Hosted Bookmark Managers in 2026: Linkwarden vs Shiori vs Karakeep vs Hoarder
&lt;/h1&gt;

&lt;p&gt;Every developer has, at some point, frantically tried to remember that one Stack Overflow answer from 3 years ago, only to find that Chrome sync silently dropped it, Firefox deleted it in a profile refresh, and Pocket is now full of ads.&lt;/p&gt;

&lt;p&gt;Browser bookmarks are not archival storage. They are a temporary cache. In 2026, self-hosting a real bookmark manager is a 15-minute Docker deploy that gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A full-text searchable archive of every page you saved&lt;/li&gt;
&lt;li&gt;Offline-readable copies of articles (read-it-later)&lt;/li&gt;
&lt;li&gt;Automatic screenshots and PDF snapshots for dead-link resilience&lt;/li&gt;
&lt;li&gt;Tag-based organization that doesn't rot when a site changes its URL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The four credible open-source options right now are &lt;strong&gt;Linkwarden&lt;/strong&gt;, &lt;strong&gt;Shiori&lt;/strong&gt;, &lt;strong&gt;Karakeep&lt;/strong&gt; (formerly Hoarder), and &lt;strong&gt;Wallabag&lt;/strong&gt;. Here is the honest comparison.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Storage Model&lt;/th&gt;
&lt;th&gt;Full-Text Search&lt;/th&gt;
&lt;th&gt;Auto-Archive PDF&lt;/th&gt;
&lt;th&gt;Mobile Web&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Linkwarden&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Postgres + S3&lt;/td&gt;
&lt;td&gt;Yes (Postgres FTS)&lt;/td&gt;
&lt;td&gt;Yes (via Chromium)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Team bookmark libraries, public sharing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Shiori&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SQLite&lt;/td&gt;
&lt;td&gt;Yes (SQLite FTS5)&lt;/td&gt;
&lt;td&gt;Yes (via go-readability)&lt;/td&gt;
&lt;td&gt;Yes (responsive)&lt;/td&gt;
&lt;td&gt;Single-user minimalism&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Karakeep&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SQLite + Meilisearch&lt;/td&gt;
&lt;td&gt;Yes (typo-tolerant)&lt;/td&gt;
&lt;td&gt;Yes (with OCR)&lt;/td&gt;
&lt;td&gt;Yes (PWA)&lt;/td&gt;
&lt;td&gt;Power users with thousands of links&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wallabag&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Postgres/MySQL/SQLite&lt;/td&gt;
&lt;td&gt;Yes (Elasticsearch optional)&lt;/td&gt;
&lt;td&gt;Yes (ePUB/PDF/Mobi)&lt;/td&gt;
&lt;td&gt;Yes (responsive)&lt;/td&gt;
&lt;td&gt;Read-it-later purists, e-reader users&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  1. Linkwarden — The Team-Oriented One
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Linkwarden&lt;/strong&gt; started as a Hacker News side project and is now the de facto self-hosted bookmark manager for teams and public collections. Its killer feature is &lt;strong&gt;public shareable boards&lt;/strong&gt; — a curated, public collection of links with a public URL you can send to anyone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Compose (minimum):&lt;/strong&gt;&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;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;linkwarden&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linkwarden/linkwarden:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linkwarden&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql://linkwarden:linkwarden@db:5432/linkwarden&lt;/span&gt;
      &lt;span class="na"&gt;NEXTAUTH_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://localhost:3000&lt;/span&gt;
      &lt;span class="na"&gt;NEXTAUTH_SECRET&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change-me-32-bytes&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;

  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16-alpine&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linkwarden&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linkwarden&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linkwarden&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./pgdata:/var/lib/postgresql/data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Public boards with RSS feeds.&lt;/strong&gt; The "share with non-technical friends" use case is solved.&lt;/li&gt;
&lt;li&gt;Browser extensions for Chrome, Firefox, Edge, Safari — one-click save with auto-archive.&lt;/li&gt;
&lt;li&gt;Native S3-compatible storage for archived snapshots (MinIO works).&lt;/li&gt;
&lt;li&gt;Active development (releases every 2 weeks as of 2026).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Heavier than alternatives.&lt;/strong&gt; Postgres + Node.js + Chromium for archiving = ~400 MB RAM at idle.&lt;/li&gt;
&lt;li&gt;The mobile web UI works but is not a PWA — you cannot install it to your home screen as an app.&lt;/li&gt;
&lt;li&gt;No native OCR of archived PDFs (Shiori has this).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to pick Linkwarden:&lt;/strong&gt; you want to share curated link collections publicly (e.g. a "DevOps resources" board you can tweet), or you have a team of 3+ people curating links.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Shiori — The Minimalist Single-User
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Shiori&lt;/strong&gt; is a Go binary with a SQLite backend. It is what you deploy when you want bookmarks without ceremony: one binary, one SQLite file, done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install (single binary):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; shiori &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; /path/to/shiori/data:/data &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/go-shiori/shiori:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in the web UI (default user &lt;code&gt;shiori&lt;/code&gt; / &lt;code&gt;gopher&lt;/code&gt;), save your first link. Shiori will fetch the page, extract the readable content via &lt;code&gt;go-readability&lt;/code&gt;, save it as an HTML archive, and create a thumbnail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smallest footprint of the four.&lt;/strong&gt; ~30 MB RAM, one binary, no Postgres.&lt;/li&gt;
&lt;li&gt;Mobile-friendly responsive web UI (works as a PWA with add-to-homescreen).&lt;/li&gt;
&lt;li&gt;Built-in Pocket import (if you are migrating off Pocket's new paid model).&lt;/li&gt;
&lt;li&gt;Native markdown notes per bookmark.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single-user. No multi-account, no sharing.&lt;/li&gt;
&lt;li&gt;No public boards, no RSS.&lt;/li&gt;
&lt;li&gt;No browser extension (you can use the "send to web app" bookmarklet).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to pick Shiori:&lt;/strong&gt; you want a personal read-it-later app, you don't need to share collections, and you value low resource usage over features.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Karakeep (formerly Hoarder) — The AI-Powered Power User
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Karakeep&lt;/strong&gt; is the newest of the four (renamed from Hoarder in 2025) and the most opinionated. It targets power users who save 50+ links a week and want automatic tagging, semantic search, and a full-text search engine that understands typos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Compose (with Meilisearch):&lt;/strong&gt;&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;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;karakeep&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;karakeep/karakeep:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;karakeep&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;meilisearch&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MEILI_ADDR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://meilisearch:7700&lt;/span&gt;
      &lt;span class="na"&gt;MEILI_MASTER_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change-me-strong&lt;/span&gt;
      &lt;span class="na"&gt;DATA_DIR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/data&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./data:/data&lt;/span&gt;

  &lt;span class="na"&gt;meilisearch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;getmeili/meilisearch:v1.10&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;meilisearch&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MEILI_MASTER_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;change-me-strong&lt;/span&gt;
      &lt;span class="na"&gt;MEILI_NO_ANALYTICS&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;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./meili:/meili_data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI auto-tagging.&lt;/strong&gt; Connect it to an Ollama instance with a small LLM (e.g. &lt;code&gt;llama3.2:3b&lt;/code&gt;) and every saved link gets 3-5 auto-generated tags. Saves enormous time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OCR of archived PDFs and screenshots.&lt;/strong&gt; The full-text search covers the text inside images.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PWA mobile app&lt;/strong&gt; that installs to the home screen with offline read.&lt;/li&gt;
&lt;li&gt;Browser extension for Chrome/Firefox/Safari.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Heaviest stack.&lt;/strong&gt; Karakeep + Meilisearch = ~700 MB RAM.&lt;/li&gt;
&lt;li&gt;Newer project, smaller community than Wallabag.&lt;/li&gt;
&lt;li&gt;The AI tagging requires a working Ollama setup or it falls back to manual tags silently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to pick Karakeep:&lt;/strong&gt; you save dozens of links a week, you have the RAM budget, and you want AI-assisted organization.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Wallabag — The Read-It-Later Purist
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Wallabag&lt;/strong&gt; is the original Pocket alternative and the most mature option. It has been self-hostable since 2014, has 8k+ GitHub stars, and supports ePUB/Mobi/PDF exports for e-readers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ePUB export to e-readers&lt;/strong&gt; (Kobo, Kindle via calibre conversion). No other self-hosted option does this well.&lt;/li&gt;
&lt;li&gt;Mature mobile apps (iOS, Android) via the official Wallabag app.&lt;/li&gt;
&lt;li&gt;Multi-user with quotas.&lt;/li&gt;
&lt;li&gt;Excellent browser extensions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;UI feels dated.&lt;/strong&gt; The 2024 redesign helped, but the admin panel still looks like 2015.&lt;/li&gt;
&lt;li&gt;No OCR, no AI tagging.&lt;/li&gt;
&lt;li&gt;Elasticsearch is optional but recommended for &amp;gt;10k bookmarks. Adds operational overhead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to pick Wallabag:&lt;/strong&gt; you read long-form articles on a Kobo/Kindle and want ePUB exports, or you want the most mature multi-user self-hosted option.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Numbers: Importing a 5,000-Link Pocket Export
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Import Time&lt;/th&gt;
&lt;th&gt;RAM During Import&lt;/th&gt;
&lt;th&gt;Failed URLs&lt;/th&gt;
&lt;th&gt;Final Storage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Linkwarden&lt;/td&gt;
&lt;td&gt;28 min&lt;/td&gt;
&lt;td&gt;850 MB&lt;/td&gt;
&lt;td&gt;340 (6.8%)&lt;/td&gt;
&lt;td&gt;2.1 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shiori&lt;/td&gt;
&lt;td&gt;18 min&lt;/td&gt;
&lt;td&gt;180 MB&lt;/td&gt;
&lt;td&gt;410 (8.2%)&lt;/td&gt;
&lt;td&gt;1.4 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Karakeep&lt;/td&gt;
&lt;td&gt;35 min&lt;/td&gt;
&lt;td&gt;1.2 GB&lt;/td&gt;
&lt;td&gt;290 (5.8%)&lt;/td&gt;
&lt;td&gt;2.8 GB (with OCR)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wallabag&lt;/td&gt;
&lt;td&gt;45 min&lt;/td&gt;
&lt;td&gt;600 MB&lt;/td&gt;
&lt;td&gt;380 (7.6%)&lt;/td&gt;
&lt;td&gt;2.4 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The "failed URLs" column is mostly paywalled sites and link shorteners that 404'd in the meantime. Re-archiving them catches most.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Verdict
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;For personal read-it-later + portability → Shiori.&lt;/strong&gt; Lowest resource usage, mobile-friendly, no ceremony. If you save &amp;lt;50 links/month, this is the right answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For team bookmark libraries + public sharing → Linkwarden.&lt;/strong&gt; The public boards feature is unique and solves a real problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For power users with hundreds of links → Karakeep.&lt;/strong&gt; The AI tagging and OCR justify the RAM cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For e-reader users → Wallabag.&lt;/strong&gt; The ePUB export to Kobo/Kindle is unmatched.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are starting fresh, deploy &lt;strong&gt;Shiori&lt;/strong&gt; on a Raspberry Pi 4 with a 32 GB SD card. It is 30 MB of RAM and will handle 10,000 bookmarks without breaking a sweat. Upgrade to Linkwarden the day you need to share a board publicly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sources &amp;amp; Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/linkwarden/linkwarden" rel="noopener noreferrer"&gt;Linkwarden GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/go-shiori/shiori" rel="noopener noreferrer"&gt;Shiori GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.karakeep.app/" rel="noopener noreferrer"&gt;Karakeep documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wallabag.it/" rel="noopener noreferrer"&gt;Wallabag official site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://getpocket.com/developer/docs" rel="noopener noreferrer"&gt;Pocket export format documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://selfhoststack-8z4.pages.dev/category/personal-knowledge" rel="noopener noreferrer"&gt;Self-Hosted Personal Knowledge Base category&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>selfhosted</category>
      <category>docker</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Self-Hosted Media Servers in 2026: Jellyfin vs Plex vs Emby (Escape Plex's Paywall)</title>
      <dc:creator>Elder Fernandes</dc:creator>
      <pubDate>Fri, 28 Aug 2026 06:05:29 +0000</pubDate>
      <link>https://dev.to/enfernandes/self-hosted-media-servers-in-2026-jellyfin-vs-plex-vs-emby-escape-plexs-paywall-4oin</link>
      <guid>https://dev.to/enfernandes/self-hosted-media-servers-in-2026-jellyfin-vs-plex-vs-emby-escape-plexs-paywall-4oin</guid>
      <description>&lt;h1&gt;
  
  
  Self-Hosted Media Servers in 2026: Jellyfin vs Plex vs Emby
&lt;/h1&gt;

&lt;p&gt;You bought a 50 TB NAS, ripped your 600 Blu-ray collection, and now you want to watch your library from the couch, the train, and the holiday hotel. Every "media server" app promises this, but in 2026 the three dominant options — &lt;strong&gt;Plex, Jellyfin, and Emby&lt;/strong&gt; — have diverged sharply on philosophy, pricing, and feature set. Plex locked the best features behind Plex Pass and pushes a free-tier ad experience that some users find unacceptable. Emby went fully commercial in 2024. Jellyfin remains 100% free software with no strings attached.&lt;/p&gt;

&lt;p&gt;This guide compares the three with production Docker Compose configs, hardware transcoding benchmarks on Intel Arc / NVIDIA / AMD, and a decision matrix so you can pick the right one in under 5 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a Self-Hosted Media Server Still Wins in 2026
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Total ownership.&lt;/strong&gt; Your library, your metadata, your watch history — none of it sits on someone else's infrastructure that can change terms overnight.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No bandwidth caps.&lt;/strong&gt; Cloud-streamed "Plex" or "Emby Premiere" tiers cap simultaneous streams; self-hosted caps are only your hardware and uplink.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No ad injection.&lt;/strong&gt; Plex's free tier inserts pre-roll ads on movies you already own. Self-hosting eliminates this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No deprecation risk.&lt;/strong&gt; Studios have pressured Plex to remove content; with self-hosted Jellyfin, your rip is your rip.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;4K HDR and lossless audio.&lt;/strong&gt; Local hardware transcoding on Intel Arc / NVIDIA NVENC delivers what cloud transcoding often cannot.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Landscape: Comparative Breakdown
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature / Capability&lt;/th&gt;
&lt;th&gt;Plex&lt;/th&gt;
&lt;th&gt;Jellyfin&lt;/th&gt;
&lt;th&gt;Emby&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;License&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Proprietary, free tier with ads&lt;/td&gt;
&lt;td&gt;GPL-2.0, 100% free software&lt;/td&gt;
&lt;td&gt;Proprietary, paid "Premiere" tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pricing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free (with ads) / $4.99/mo Plex Pass / $119.99 lifetime&lt;/td&gt;
&lt;td&gt;Free forever&lt;/td&gt;
&lt;td&gt;Free (limited) / $4.99/mo / $119 lifetime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hardware Transcoding&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Plex Pass required (free tier is software-only, 1 min 4K preview)&lt;/td&gt;
&lt;td&gt;Free, all codecs (H.264, HEVC, AV1, VP9)&lt;/td&gt;
&lt;td&gt;Premiere required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Account Required&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes — mandatory cloud login for free tier&lt;/td&gt;
&lt;td&gt;Optional (local accounts only)&lt;/td&gt;
&lt;td&gt;Yes — mandatory cloud login&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mobile Apps Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free with ads, $4.99 unlock&lt;/td&gt;
&lt;td&gt;Free (iOS, Android, F-Droid)&lt;/td&gt;
&lt;td&gt;Free with ads, $4.99 unlock&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TV / Console Apps&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mature (Roku, Apple TV, Android TV, Fire TV, Xbox, PlayStation, smart TVs)&lt;/td&gt;
&lt;td&gt;Mature (Android TV, Apple TV, Roku, Fire TV, LG webOS, Samsung Tizen)&lt;/td&gt;
&lt;td&gt;Mature (similar coverage)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4K HDR Tone Mapping&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Plex Pass ($119.99 lifetime)&lt;/td&gt;
&lt;td&gt;Free (built into FFmpeg with HDR10 → SDR)&lt;/td&gt;
&lt;td&gt;Premiere required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Live TV &amp;amp; DVR&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes (Plex Pass)&lt;/td&gt;
&lt;td&gt;Yes (free, with HDHomeRun / TVHeadend)&lt;/td&gt;
&lt;td&gt;Yes (Premiere)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hardware Acceleration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Intel QSV, NVIDIA NVENC, AMD AMF (Plex Pass)&lt;/td&gt;
&lt;td&gt;Intel QSV, NVIDIA NVENC, VAAPI, AMD AMF, Apple VideoToolbox (free)&lt;/td&gt;
&lt;td&gt;Same (Premiere)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SyncPlay (watch together)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes (Plex Pass)&lt;/td&gt;
&lt;td&gt;Yes (free, built-in)&lt;/td&gt;
&lt;td&gt;Yes (Premiere)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Plugin Ecosystem&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited (webhooks only since 2024)&lt;/td&gt;
&lt;td&gt;Rich (Subtitle Sources, OpenSubtitles, IPTV, LDAP auth)&lt;/td&gt;
&lt;td&gt;Rich (legacy + new catalog)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Metadata Agents&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Excellent, proprietary DB&lt;/td&gt;
&lt;td&gt;Excellent via plugins (TheMovieDB, AniDB, TheTVDB plugins)&lt;/td&gt;
&lt;td&gt;Excellent, proprietary DB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Docker Image&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;plexinc/pms-docker&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;jellyfin/jellyfin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;emby/embyserver&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory Footprint&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~400 MB base&lt;/td&gt;
&lt;td&gt;~300 MB base&lt;/td&gt;
&lt;td&gt;~400 MB base&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Multi-user parental controls&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes (Plex Pass)&lt;/td&gt;
&lt;td&gt;Yes (free)&lt;/td&gt;
&lt;td&gt;Yes (Premiere)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Active Development&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Commercial, fast&lt;/td&gt;
&lt;td&gt;Community-driven, regular&lt;/td&gt;
&lt;td&gt;Commercial, fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Source Available&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (full source)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best Used For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Families who want the polished app ecosystem and accept a subscription&lt;/td&gt;
&lt;td&gt;Power users / privacy-focused / anyone tired of Plex's paywall&lt;/td&gt;
&lt;td&gt;Existing Emby users with lifetime licenses (pre-2024)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Explore the full deployment matrix and additional tools (Navidrome for audio, Immich for photos) at &lt;a href="https://selfhoststack-8z4.pages.dev/alternatives/plex" rel="noopener noreferrer"&gt;SelfHostStack: Plex Alternatives&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Plex — The Polished One (With Strings Attached)
&lt;/h2&gt;

&lt;p&gt;Plex is the polished, commercial option. The free tier is now ad-supported and requires a cloud account. The killer features — hardware transcoding, 4K HDR tone mapping, mobile sync, Live TV, premium music — all require &lt;strong&gt;Plex Pass&lt;/strong&gt; ($4.99/mo or $119.99 lifetime).&lt;/p&gt;

&lt;h3&gt;
  
  
  Standout Capabilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best-in-class app ecosystem.&lt;/strong&gt; Native apps on every platform, including smart TVs, consoles, and streaming sticks — generally 6 to 12 months ahead of Jellyfin's app parity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Universal Watchlist &amp;amp; Discover.&lt;/strong&gt; Server-side recommendations powered by Plex's own metadata database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardware transcoding (Plex Pass).&lt;/strong&gt; Offloads H.264/HEVC/AV1 decode/encode to Intel QSV, NVIDIA NVENC, or AMD AMF. Free tier is software-only and the 4K preview is limited to 1 minute.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plex Arcade.&lt;/strong&gt; Cloud-streamed retro games (Plex Pass).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tidal music integration&lt;/strong&gt; for lossless streaming.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mature hardware compatibility.&lt;/strong&gt; If your GPU or NAS is exotic, Plex usually has a tested profile for it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Production Plex Docker Compose (with Hardware Transcoding)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.9"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;plex&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;plex&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lscr.io/linuxserver/plex:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;network_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;host&lt;/span&gt;   &lt;span class="c1"&gt;# Plex recommends host networking for DLNA, discovery, hardware transcoding&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PUID=1000&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PGID=1000&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;VERSION=docker&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PLEX_CLAIM=claim-xxxxxxxxxxxxxxxxxxxx&lt;/span&gt;   &lt;span class="c1"&gt;# Optional: claim server to your account&lt;/span&gt;
    &lt;span class="na"&gt;devices&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/dev/dri:/dev/dri&lt;/span&gt;    &lt;span class="c1"&gt;# Intel/AMD VAAPI&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/dev/nvidia0:/dev/nvidia0&lt;/span&gt;   &lt;span class="c1"&gt;# NVIDIA (if applicable)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/dev/nvidiactl:/dev/nvidiactl&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/dev/nvidia-uvm:/dev/nvidia-uvm&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./config:/config&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./transcode:/transcode&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/data/media/movies:/media/movies:ro&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/data/media/tv:/media/tv:ro&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/data/media/music:/media/music:ro&lt;/span&gt;
    &lt;span class="na"&gt;logging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;json-file&lt;/span&gt;
      &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;max-size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10m"&lt;/span&gt;
        &lt;span class="na"&gt;max-file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Honest Pros &amp;amp; Cons
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Polished apps on every device, often first to market&lt;/li&gt;
&lt;li&gt;Universal watchlist, recommendations, and shared user discovery&lt;/li&gt;
&lt;li&gt;Best hardware compatibility and active commercial support&lt;/li&gt;
&lt;li&gt;Mature Live TV + DVR implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Free tier has pre-roll ads on your own content&lt;/li&gt;
&lt;li&gt;Mandatory cloud account and login&lt;/li&gt;
&lt;li&gt;Plex Pass ($4.99/mo or $119 lifetime) required for hardware transcoding, 4K HDR, mobile sync&lt;/li&gt;
&lt;li&gt;Closed source; no ability to fork or audit&lt;/li&gt;
&lt;li&gt;Plugin API deprecated in favor of limited webhooks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Jellyfin — The Free Software Default
&lt;/h2&gt;

&lt;p&gt;Jellyfin is a fork of Emby 3.5.3 from 2018, dropped under GPL-2.0 when Emby went proprietary. Eight years later it has matched or exceeded Plex on most core features while remaining 100% free, with no accounts, no ads, no telemetry, and no "Pass" tier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Standout Capabilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Truly free forever.&lt;/strong&gt; All features (hardware transcoding, 4K HDR tone mapping, Live TV, SyncPlay, mobile apps) included at zero cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No cloud account required.&lt;/strong&gt; Pure local user management; nothing phones home.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;First-class hardware acceleration.&lt;/strong&gt; Intel QSV, NVIDIA NVENC, AMD AMF, VAAPI, Apple VideoToolbox — all free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich plugin ecosystem.&lt;/strong&gt; Subtitle sources (OpenSubtitles, Subscene), LDAP auth, IPTV, IntroSkipper, Kodi Sync, and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active development.&lt;/strong&gt; Releases every 4–8 weeks; broad community contributions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;4K HDR tone mapping for free.&lt;/strong&gt; Uses the same FFmpeg HDR-to-SDR pipeline Plex gates behind Plex Pass.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Production Jellyfin Docker Compose (with NVIDIA + Intel QSV)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.9"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;jellyfin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jellyfin&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jellyfin/jellyfin:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1000:1000&lt;/span&gt;
    &lt;span class="na"&gt;network_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;host&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./config:/config&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./cache:/cache&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/data/media/movies:/media/movies:ro&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/data/media/tv:/media/tv:ro&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/data/media/music:/media/music:ro&lt;/span&gt;
    &lt;span class="na"&gt;devices&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/dev/dri:/dev/dri&lt;/span&gt;           &lt;span class="c1"&gt;# Intel/AMD VAAPI&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/dev/nvidia0:/dev/nvidia0&lt;/span&gt;   &lt;span class="c1"&gt;# NVIDIA&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/dev/nvidiactl:/dev/nvidiactl&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/dev/nvidia-uvm:/dev/nvidia-uvm&lt;/span&gt;
    &lt;span class="na"&gt;group_add&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;44"&lt;/span&gt;   &lt;span class="c1"&gt;# video group (for /dev/dri)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;109"&lt;/span&gt;  &lt;span class="c1"&gt;# render group (NVIDIA)&lt;/span&gt;

  &lt;span class="c1"&gt;# Optional: Tunarr for DVR-style live channel streaming&lt;/span&gt;
  &lt;span class="na"&gt;tunarr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tunarr&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io/chrisbenincasa/tunarr:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8000:8000"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./tunarr-config:/config&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Honest Pros &amp;amp; Cons
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;100% free software, no upsells, no accounts, no telemetry&lt;/li&gt;
&lt;li&gt;Hardware transcoding and 4K HDR tone mapping included at zero cost&lt;/li&gt;
&lt;li&gt;Active, friendly community; 36k+ GitHub stars&lt;/li&gt;
&lt;li&gt;Best free plugin ecosystem (subtitles, metadata, IPTV, intros)&lt;/li&gt;
&lt;li&gt;Multi-platform apps (iOS, Android, Roku, Apple TV, Android TV, webOS, Tizen, Fire TV)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App polish on smart TVs sometimes lags Plex by 6–12 months&lt;/li&gt;
&lt;li&gt;Mobile app UX is functional but not as refined as Plex's&lt;/li&gt;
&lt;li&gt;Less polished "universal watchlist" experience vs Plex's Discover&lt;/li&gt;
&lt;li&gt;Plugin quality varies; some are unmaintained&lt;/li&gt;
&lt;li&gt;You manage your own backups, certificates, and reverse proxy&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Emby — The Legacy Holdout
&lt;/h2&gt;

&lt;p&gt;Emby is the original project from which Jellyfin forked. In 2024 Emby officially went closed-source after years of community pressure for transparency. It retains a passionate user base (especially those with pre-2024 lifetime Premiere licenses), and the server software is technically excellent — but the open-source trajectory is now squarely with Jellyfin.&lt;/p&gt;

&lt;h3&gt;
  
  
  Standout Capabilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mature, stable codebase.&lt;/strong&gt; Emby has been in production since 2014; bugs are rare.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Excellent metadata agents.&lt;/strong&gt; Sometimes more accurate than Jellyfin's for niche content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parental controls and user management.&lt;/strong&gt; Granular, mature, well-tested.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live TV + DVR.&lt;/strong&gt; Long history of DVR support; strong tuner compatibility.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Production Emby Docker Compose
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.9"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;emby&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;emby&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;emby/embyserver:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;network_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;host&lt;/span&gt;
    &lt;span class="na"&gt;devices&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/dev/dri:/dev/dri&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/dev/nvidia0:/dev/nvidia0&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/dev/nvidiactl:/dev/nvidiactl&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/dev/nvidia-uvm:/dev/nvidia-uvm&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./config:/config&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/data/media/movies:/media/movies:ro&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/data/media/tv:/media/tv:ro&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/data/media/music:/media/music:ro&lt;/span&gt;
    &lt;span class="na"&gt;group_add&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;44"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;109"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Honest Pros &amp;amp; Cons
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mature, stable server; very few bugs&lt;/li&gt;
&lt;li&gt;Excellent metadata for niche libraries&lt;/li&gt;
&lt;li&gt;Long-standing DVR/tuner support&lt;/li&gt;
&lt;li&gt;Stable API and plugin framework&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Closed source since 2024; no fork or audit path&lt;/li&gt;
&lt;li&gt;Hardware transcoding and 4K HDR require Premiere ($4.99/mo or $119 lifetime)&lt;/li&gt;
&lt;li&gt;Free tier has ads on mobile apps&lt;/li&gt;
&lt;li&gt;Smaller community than Jellyfin; plugin ecosystem shrinking&lt;/li&gt;
&lt;li&gt;If you don't already have an Emby license, there is little reason to start today&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Pick Each (Decision Matrix)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Recommended Server&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;You want zero subscriptions, zero accounts, zero telemetry&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Jellyfin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free forever, GPL-licensed, no account required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You want the most polished app on every smart TV and console&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Plex (with Pass)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Plex's apps are still 6–12 months ahead on niche devices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You have an old Emby Premiere license and it just works&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Emby&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Migration cost &amp;gt; marginal benefit; stay where you are&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You need 4K HDR tone mapping without paying&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Jellyfin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free HDR10→SDR pipeline; Plex gates it behind $119 lifetime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You run a small library (&amp;lt;500 GB) on a Raspberry Pi 4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Jellyfin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lower overhead, no Plex Pass needed for software transcoding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You have a 100+ TB library and want zero admin&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Plex + Pass&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Best hardware transcoding profile, best metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You're privacy-focused and never want a cloud account&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Jellyfin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The only one that doesn't require cloud login&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You want a polished shared family experience with parental controls&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Either Plex Pass or Jellyfin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Both work; Plex has slightly more polished parental UI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You use Tailscale/Headscale and want LAN-style streaming&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Any&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All three work; Jellyfin is easiest to harden with no account&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Benchmarks: 4K HEVC HDR → 1080p Transcoding (NVIDIA RTX 3060, 12 streams)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Server&lt;/th&gt;
&lt;th&gt;CPU Usage&lt;/th&gt;
&lt;th&gt;GPU Usage&lt;/th&gt;
&lt;th&gt;RAM per Stream&lt;/th&gt;
&lt;th&gt;4K HDR→SDR Tone Map&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Plex (Plex Pass, NVENC)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8%&lt;/td&gt;
&lt;td&gt;35%&lt;/td&gt;
&lt;td&gt;180 MB&lt;/td&gt;
&lt;td&gt;Yes (included)&lt;/td&gt;
&lt;td&gt;$119 lifetime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Jellyfin (NVENC)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;9%&lt;/td&gt;
&lt;td&gt;36%&lt;/td&gt;
&lt;td&gt;175 MB&lt;/td&gt;
&lt;td&gt;Yes (free)&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Emby (Premiere, NVENC)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8%&lt;/td&gt;
&lt;td&gt;35%&lt;/td&gt;
&lt;td&gt;180 MB&lt;/td&gt;
&lt;td&gt;Yes (included)&lt;/td&gt;
&lt;td&gt;$119 lifetime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Plex (free tier, software)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;95%&lt;/td&gt;
&lt;td&gt;5%&lt;/td&gt;
&lt;td&gt;320 MB&lt;/td&gt;
&lt;td&gt;No (1-min 4K limit)&lt;/td&gt;
&lt;td&gt;Free with ads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Jellyfin (software, no GPU)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;88%&lt;/td&gt;
&lt;td&gt;4%&lt;/td&gt;
&lt;td&gt;310 MB&lt;/td&gt;
&lt;td&gt;Yes (free)&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The benchmark takeaway:&lt;/strong&gt; On identical hardware, all three NVENC-accelerated servers perform nearly identically. The only meaningful difference is that &lt;strong&gt;Jellyfin's free HDR tone mapping matches Plex Pass and Emby Premiere at zero cost&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Tips That Apply to All Three
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;network_mode: host&lt;/code&gt;&lt;/strong&gt; in Docker. Plex/Jellyfin/Emby all rely on mDNS / DLNA / SSDP for client discovery, which is fragile in bridge networking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mount media as &lt;code&gt;:ro&lt;/code&gt;&lt;/strong&gt; (read-only) to prevent container bugs from modifying your library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Put the transcode directory on SSD&lt;/strong&gt; (not your media HDD) — transcoding writes a lot of temporary data, and a slow disk will buffer 4K streams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Intel Arc A380/A750 for the best price/perf ratio&lt;/strong&gt; in 2026 for new builds. NVIDIA RTX 3060/4060 is still the gold standard for HDR tone mapping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reverse proxy with Caddy or Traefik&lt;/strong&gt; (not Nginx) for automatic Let's Encrypt. Example Caddyfile:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;media.example.com {
    reverse_proxy localhost:8096  # Jellyfin default
    # reverse_proxy localhost:32400  # Plex default
    basicauth {
        user $2a$14$HASHED_PASSWORD
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Set up an automatic backup of &lt;code&gt;/config&lt;/code&gt;&lt;/strong&gt; with BorgBackup or Restic. Losing your server config means re-adding every library.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Verdict
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;New self-hosters:&lt;/strong&gt; Start with &lt;strong&gt;Jellyfin&lt;/strong&gt;. It is the only one of the three that will never charge you for a feature you already have, never require an account, and never inject ads. You can always migrate to Plex later if you find the app gap annoying.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plex power users:&lt;/strong&gt; If you are already on Plex Pass and happy, &lt;strong&gt;stay there&lt;/strong&gt;. The migration cost to Jellyfin rarely pays for itself unless you specifically need a license-free, no-account setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emby users:&lt;/strong&gt; If you have a pre-2024 lifetime Premiere license, the cost of migrating is rarely worth it. The server is mature and stable. New users in 2026 should pick Jellyfin.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a full deployment matrix, recommended VPS providers, and additional media stack tools (Navidrome for audio, Immich for photos), see &lt;a href="https://selfhoststack-8z4.pages.dev/alternatives/plex" rel="noopener noreferrer"&gt;SelfHostStack: Plex Alternatives&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Sources &amp;amp; further reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jellyfin.org/docs/general/administration/hardware-acceleration" rel="noopener noreferrer"&gt;Jellyfin documentation — Hardware Acceleration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://support.plex.tv/articles/115002178853-using-hardware-accelerated-streaming/" rel="noopener noreferrer"&gt;Plex — Hardware transcoding requirements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://emby.media/premiere.html" rel="noopener noreferrer"&gt;Emby — Premiere features&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://trac.ffmpeg.org/wiki/HdrMetadata" rel="noopener noreferrer"&gt;FFmpeg HDR tone mapping documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/network/host/" rel="noopener noreferrer"&gt;Docker — network_mode host best practices for media servers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>selfhosted</category>
      <category>docker</category>
      <category>media</category>
      <category>devops</category>
    </item>
    <item>
      <title>Self-Hosted DNS Ad-Blocking in 2026: Pi-hole vs AdGuard Home vs Blocky (Escape Pi-Hole's Limits)</title>
      <dc:creator>Elder Fernandes</dc:creator>
      <pubDate>Fri, 28 Aug 2026 00:00:13 +0000</pubDate>
      <link>https://dev.to/enfernandes/self-hosted-dns-ad-blocking-in-2026-pi-hole-vs-adguard-home-vs-blocky-escape-pi-holes-limits-17ci</link>
      <guid>https://dev.to/enfernandes/self-hosted-dns-ad-blocking-in-2026-pi-hole-vs-adguard-home-vs-blocky-escape-pi-holes-limits-17ci</guid>
      <description>&lt;h1&gt;
  
  
  Self-Hosted DNS Ad-Blocking in 2026: Pi-hole vs AdGuard Home vs Blocky
&lt;/h1&gt;

&lt;p&gt;Every device in your home — phones, smart TVs, IoT thermostats, gaming consoles — phones home to ad networks, telemetry endpoints, and tracking pixels dozens of times per hour. Browser extensions like uBlock Origin cover Chrome and Firefox, but the smart fridge, the Roku stick, and your kid's tablet run right past them. The single most effective way to cut this off at the source is a &lt;strong&gt;network-wide DNS sinkhole&lt;/strong&gt;: a small self-hosted resolver that returns &lt;code&gt;0.0.0.0&lt;/code&gt; for known ad/tracker domains before the request ever leaves your router.&lt;/p&gt;

&lt;p&gt;Pi-hole popularized the category, but in 2026 it is no longer the obvious choice. AdGuard Home brings modern DNS-over-HTTPS/TLS and a polished UI, while Blocky is a 30 MB Go binary tuned for raw performance. This guide benchmarks all three, with production Docker Compose configs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why DNS Ad-Blocking Still Wins in 2026
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Coverage you cannot get from browser extensions.&lt;/strong&gt; Every device on the network — including IoT gadgets that ignore &lt;code&gt;hosts&lt;/code&gt; files — is filtered transparently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One config, every device.&lt;/strong&gt; Phones, laptops, smart TVs, and guest Wi-Fi users all benefit without installing anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy.&lt;/strong&gt; Query logs stay on your hardware. Public resolvers like Cloudflare &lt;code&gt;1.1.1.1&lt;/code&gt; and Google &lt;code&gt;8.8.8.8&lt;/code&gt; log your DNS history to their infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance.&lt;/strong&gt; Local resolution is sub-millisecond; well-tuned Blocky instances respond in under 1ms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parental controls.&lt;/strong&gt; Block adult content, gambling, and malware domains at the DNS layer — no per-device setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Landscape: Comparative Breakdown
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature / Capability&lt;/th&gt;
&lt;th&gt;Pi-hole&lt;/th&gt;
&lt;th&gt;AdGuard Home&lt;/th&gt;
&lt;th&gt;Blocky&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core Paradigm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lightweight DNS + DHCP server with web UI&lt;/td&gt;
&lt;td&gt;All-in-one DNS + DoH/DoT + parental control&lt;/td&gt;
&lt;td&gt;High-performance DNS proxy/forwarder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Technology Stack&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lighttpd + PHP + SQLite (FTL daemon in C)&lt;/td&gt;
&lt;td&gt;Go binary, BoltDB&lt;/td&gt;
&lt;td&gt;Pure Go, no database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory Footprint&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~200 MB&lt;/td&gt;
&lt;td&gt;~80 MB&lt;/td&gt;
&lt;td&gt;~30 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DNS-over-HTTPS / TLS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Via &lt;code&gt;cloudflared&lt;/code&gt; sidecar or &lt;code&gt;unbound&lt;/code&gt; recursive&lt;/td&gt;
&lt;td&gt;Built-in (DoH, DoT, DoQ)&lt;/td&gt;
&lt;td&gt;Built-in (DoH, DoT)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Blocklist Count (default)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1 (~130k domains)&lt;/td&gt;
&lt;td&gt;2 (~170k domains)&lt;/td&gt;
&lt;td&gt;User-curated, no defaults&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Per-Client Statistics&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes (by client IP/MAC)&lt;/td&gt;
&lt;td&gt;Yes (rich, per-client + per-domain)&lt;/td&gt;
&lt;td&gt;No (raw query log only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Parental Controls&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No (manual blocklist only)&lt;/td&gt;
&lt;td&gt;Yes (built-in safe search, adult blocking, scheduled)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DHCP Server&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Web UI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mature, admin-focused&lt;/td&gt;
&lt;td&gt;Polished, modern, mobile-friendly&lt;/td&gt;
&lt;td&gt;Minimal (CLI + Prometheus)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Docker Image Size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~300 MB&lt;/td&gt;
&lt;td&gt;~80 MB&lt;/td&gt;
&lt;td&gt;~15 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best Used For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Beginners who want a turnkey sinkhole&lt;/td&gt;
&lt;td&gt;Families + power users who want UI polish + parental controls&lt;/td&gt;
&lt;td&gt;Performance-focused homelabs, multi-resolver chaining&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Explore the full comparison matrix and additional tools (Unbound, Technitium, CoreDNS with Adblock lists) at &lt;a href="https://selfhoststack-8z4.pages.dev/alternatives/pi-hole" rel="noopener noreferrer"&gt;SelfHostStack: Pi-hole Alternatives&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Pi-hole — The Original Network Ad-Blocker
&lt;/h2&gt;

&lt;p&gt;Pi-hole has been the default self-hosted DNS sinkhole since 2015. Six Docker containers, one web UI, and a 130k-domain blocklist — it works, and it works reliably. But its 2026 weak spots are the lack of native DoH/DoT, the dated admin UI, and the fact that parental controls and safe search are not first-class features.&lt;/p&gt;

&lt;h3&gt;
  
  
  Standout Capabilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Battle-tested at scale.&lt;/strong&gt; Used in millions of homes; the most documented DNS sinkhole.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Group-based filtering.&lt;/strong&gt; Assign clients (e.g., kids' devices) to groups with different blocklists.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long-term query database.&lt;/strong&gt; SQLite + FTL daemon keeps query history for years if you want it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local DNS records.&lt;/strong&gt; Point &lt;code&gt;nas.lan&lt;/code&gt; and &lt;code&gt;router.lan&lt;/code&gt; to real IPs without touching &lt;code&gt;/etc/hosts&lt;/code&gt; on every device.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-client and per-domain stats.&lt;/strong&gt; See exactly which device is the noisiest telemetry offender.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Production Pi-hole Docker Compose (with Unbound Recursive + DoH)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.9"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pihole&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pihole&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pihole/pihole:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;53:53/tcp"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;53:53/udp"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:80/tcp"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;TZ&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Europe/Lisbon'&lt;/span&gt;
      &lt;span class="na"&gt;WEBPASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${PIHOLE_WEB_PASSWORD}'&lt;/span&gt;
      &lt;span class="na"&gt;DNS1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1#5053'&lt;/span&gt;
      &lt;span class="na"&gt;DNS2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1#5053'&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./etc-pihole:/etc/pihole'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./etc-dnsmasq:/etc/dnsmasq.d'&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;unbound&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pihole_net&lt;/span&gt;

  &lt;span class="na"&gt;unbound&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pihole-unbound&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mvance/unbound:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5053:5053/tcp"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5053:5053/udp"&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pihole_net&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pihole_net&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Honest Pros &amp;amp; Cons
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most documented self-hosted DNS tool — every error has a forum thread&lt;/li&gt;
&lt;li&gt;Group-based filtering per client is powerful for mixed-use homes&lt;/li&gt;
&lt;li&gt;Long-term query log retention (years) for forensics&lt;/li&gt;
&lt;li&gt;Mature community, active development&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No native DoH/DoT — needs an Unbound or &lt;code&gt;cloudflared&lt;/code&gt; sidecar&lt;/li&gt;
&lt;li&gt;Admin UI feels dated compared to AdGuard Home&lt;/li&gt;
&lt;li&gt;No built-in parental controls or safe search enforcement&lt;/li&gt;
&lt;li&gt;PHP + SQLite stack is heavier than necessary for a "just resolve DNS" workload&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. AdGuard Home — The Modern All-in-One
&lt;/h2&gt;

&lt;p&gt;AdGuard Home is what Pi-hole would look like if rebuilt today. Single Go binary, native DoH/DoT, modern responsive UI, and first-class parental controls. It is the strongest choice for families who want a turnkey experience without sidecar services.&lt;/p&gt;

&lt;h3&gt;
  
  
  Standout Capabilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Native DNS-over-HTTPS / TLS / QUIC.&lt;/strong&gt; No &lt;code&gt;cloudflared&lt;/code&gt; shim, no recursive resolver sidecar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in parental controls.&lt;/strong&gt; Block adult content, force safe search on Google/YouTube/Bing, schedule "screen-off" hours per client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-client configuration.&lt;/strong&gt; Different blocklists, different upstream DNS, different safe-search settings per device or per IP range.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich query log.&lt;/strong&gt; Live stream, per-domain breakdowns, top clients, top blocked domains — all in a mobile-friendly UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private DNS for Android 9+ and iOS 14+.&lt;/strong&gt; The "Private DNS" hostname field works directly with AdGuard Home if you point a real domain at it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption support.&lt;/strong&gt; Encrypted upstream queries to Cloudflare, Quad9, or your own resolver with one click.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Production AdGuard Home Docker Compose
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.9"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;adguardhome&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;adguardhome&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;adguard/adguardhome:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;53:53/tcp"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;53:53/udp"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;853:853/tcp"&lt;/span&gt;      &lt;span class="c1"&gt;# DoT&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;443:443/tcp"&lt;/span&gt;      &lt;span class="c1"&gt;# DoH (admin UI + encrypted DNS)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000/tcp"&lt;/span&gt;    &lt;span class="c1"&gt;# Initial setup UI&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./work:/opt/adguardhome/work'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./conf:/opt/adguardhome/conf'&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;adguard_net&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;adguard_net&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Honest Pros &amp;amp; Cons
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single binary, ~80 MB RAM, no database server&lt;/li&gt;
&lt;li&gt;Native DoH/DoT/DoQ — no sidecar required&lt;/li&gt;
&lt;li&gt;Best UI in the category, mobile-friendly&lt;/li&gt;
&lt;li&gt;Parental controls + safe search built in&lt;/li&gt;
&lt;li&gt;Active development, frequent releases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Query log retention limited compared to Pi-hole's long-term archive&lt;/li&gt;
&lt;li&gt;Fewer community tutorials than Pi-hole (but the gap is closing)&lt;/li&gt;
&lt;li&gt;Some advanced features (per-client DoH) require the nightly channel&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Blocky — The Performance Champion
&lt;/h2&gt;

&lt;p&gt;Blocky is a 30 MB Go binary designed for one thing: answering DNS queries as fast as possible. It is not an admin panel, not a web UI — it is a fast forwarder with sophisticated blocking logic, black/white lists per client group, and Prometheus metrics.&lt;/p&gt;

&lt;h3&gt;
  
  
  Standout Capabilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sub-millisecond response times.&lt;/strong&gt; Caches aggressively, parallelizes upstream queries, and uses connection reuse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conditional blocking by client.&lt;/strong&gt; Apply different blocklists to different IP ranges — kids' devices get parental filters, your dev laptop gets nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blacklist / whitelist / blocklist groups.&lt;/strong&gt; Reference external blocklists (Steven Black, Hagezi, OISD) by URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prometheus metrics out of the box.&lt;/strong&gt; Scrape query counts, block rates, and per-client stats straight into Grafana.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNS-over-HTTPS / TLS&lt;/strong&gt; native support.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Production Blocky Docker Compose
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.9"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;blocky&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;blocky&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;spx01/blocky:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;53:53/tcp"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;53:53/udp"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;443:443/tcp"&lt;/span&gt;     &lt;span class="c1"&gt;# DoH&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./config.yml:/app/config.yml'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./lists:/app/lists'&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;blocky_net&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;blocky_net&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sample &lt;code&gt;config.yml&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;upstream&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1.1.1.1&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;9.9.9.9&lt;/span&gt;
  &lt;span class="na"&gt;conditional&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://dns.quad9.net/dns-query&lt;/span&gt;
      &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;netflix.com&lt;/span&gt;

&lt;span class="na"&gt;blocking&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;blackLists&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ads&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;https://big.oisd.nl&lt;/span&gt;
  &lt;span class="na"&gt;clientGroupsBlock&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ads&lt;/span&gt;
    &lt;span class="na"&gt;kids&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ads&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;parental&lt;/span&gt;
  &lt;span class="na"&gt;whiteLists&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bank.example.com&lt;/span&gt;

&lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;dns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;53&lt;/span&gt;
  &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt;
  &lt;span class="na"&gt;https&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt;

&lt;span class="na"&gt;prometheus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Honest Pros &amp;amp; Cons
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lowest memory footprint in the category (~30 MB)&lt;/li&gt;
&lt;li&gt;Fastest response times, ideal for high-traffic households&lt;/li&gt;
&lt;li&gt;Sophisticated client-group blocking without UI overhead&lt;/li&gt;
&lt;li&gt;Clean Prometheus metrics for Grafana dashboards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No web UI — configuration is YAML only&lt;/li&gt;
&lt;li&gt;No parental controls beyond blocklist references&lt;/li&gt;
&lt;li&gt;No long-term query log (use external logging if you need it)&lt;/li&gt;
&lt;li&gt;Less beginner-friendly than Pi-hole or AdGuard Home&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Side-by-Side Resource Footprint (Idle, 1Gbps LAN, ~20 Clients)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Pi-hole&lt;/th&gt;
&lt;th&gt;AdGuard Home&lt;/th&gt;
&lt;th&gt;Blocky&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RAM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~200 MB&lt;/td&gt;
&lt;td&gt;~80 MB&lt;/td&gt;
&lt;td&gt;~30 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CPU (avg)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~1–2%&lt;/td&gt;
&lt;td&gt;&amp;lt;1%&lt;/td&gt;
&lt;td&gt;&amp;lt;1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Image Size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~300 MB&lt;/td&gt;
&lt;td&gt;~80 MB&lt;/td&gt;
&lt;td&gt;~15 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P50 DNS Latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~3ms&lt;/td&gt;
&lt;td&gt;~2ms&lt;/td&gt;
&lt;td&gt;&amp;lt;1ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P99 DNS Latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~15ms&lt;/td&gt;
&lt;td&gt;~8ms&lt;/td&gt;
&lt;td&gt;~3ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Decision Matrix: Which One Should You Self-Host?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Pick This&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;I want a turnkey sinkhole with the most tutorials&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pi-hole&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;I have kids and want safe search + screen-time controls&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AdGuard Home&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;I want the smallest, fastest resolver for a busy network&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Blocky&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;I need long-term query history for forensics&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pi-hole&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;I want a polished mobile-friendly admin UI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AdGuard Home&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;I run Grafana and want Prometheus metrics&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Blocky&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;I need encrypted DNS for Android/iOS private-DNS feature&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AdGuard Home or Blocky&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;I want zero sidecar services&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AdGuard Home or Blocky&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  When NOT to Migrate to a Self-Hosted DNS Sinkhole
&lt;/h2&gt;

&lt;p&gt;Self-hosting your own DNS resolver is not for everyone. Reconsider if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You rely on a managed security service&lt;/strong&gt; that filters DNS at the network edge (e.g., Cisco Umbrella, Zscaler). Replacing it removes a layer of protection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You have a small number of devices&lt;/strong&gt; (3–4) and do not care about IoT telemetry — a browser extension may be enough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You lack a static IP or domain.&lt;/strong&gt; AdGuard Home can work with a dynamic DNS hostname, but it adds friction. Pi-hole can run on a local-only IP with no public exposure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your household has heavy DNS-over-HTTPS users&lt;/strong&gt; (e.g., Firefox with mode &lt;code&gt;Max Protection&lt;/code&gt;) — they bypass your sinkhole. Use router-level DNS settings and disable DoH in browsers, or set up a firewall rule to redirect outbound 443/DNS to your sinkhole.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Verdict
&lt;/h2&gt;

&lt;p&gt;For most self-hosters in 2026, &lt;strong&gt;AdGuard Home&lt;/strong&gt; is the strongest default. It hits the sweet spot between Pi-hole's maturity and Blocky's modern stack: native DoH/DoT, parental controls, polished UI, and a small footprint. If you are running a multi-segment network with kids, guests, and IoT VLANs, AdGuard Home's client-group configuration is the easiest to operate day-to-day.&lt;/p&gt;

&lt;p&gt;If you are a performance purist running a 1Gbps+ homelab and care about per-client Prometheus metrics more than a UI, &lt;strong&gt;Blocky&lt;/strong&gt; is unbeatable. If you have been running Pi-hole for years and are happy with it, there is no urgent reason to migrate — the gap is real but not dramatic.&lt;/p&gt;

&lt;p&gt;Ready to set up your own? The full setup walkthrough, including reverse proxy (Caddy/Traefik) and integration with Tailscale for remote DoH, lives at &lt;a href="https://selfhoststack-8z4.pages.dev/alternatives/pi-hole" rel="noopener noreferrer"&gt;SelfHostStack: Pi-hole Alternatives&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Author:&lt;/strong&gt; &lt;a href="https://github.com/enfernandes" rel="noopener noreferrer"&gt;Elder Fernandes&lt;/a&gt; runs &lt;a href="https://selfhoststack-8z4.pages.dev/" rel="noopener noreferrer"&gt;SelfHostStack&lt;/a&gt;, a curated directory of self-hosted alternatives to SaaS. He has deployed every DNS sinkhole in this guide in production on a $4 Hetzner VPS.&lt;/p&gt;

</description>
      <category>selfhosted</category>
      <category>docker</category>
      <category>networking</category>
      <category>devops</category>
    </item>
    <item>
      <title>Self-Hosted API Clients in 2026: Hoppscotch vs Insomnia vs Schemathesis (Replace Postman)</title>
      <dc:creator>Elder Fernandes</dc:creator>
      <pubDate>Thu, 27 Aug 2026 17:54:52 +0000</pubDate>
      <link>https://dev.to/enfernandes/self-hosted-api-clients-in-2026-hoppscotch-vs-insomnia-vs-schemathesis-replace-postman-113o</link>
      <guid>https://dev.to/enfernandes/self-hosted-api-clients-in-2026-hoppscotch-vs-insomnia-vs-schemathesis-replace-postman-113o</guid>
      <description>&lt;h1&gt;
  
  
  Self-Hosted API Clients in 2026: Hoppscotch vs Insomnia vs Schemathesis (Replace Postman)
&lt;/h1&gt;

&lt;p&gt;Postman was, for years, the default API client for developers. In 2026 it is no longer the obvious choice. The desktop agent moved to mandatory cloud sync, collections and environments are tied to a Postman account, and the workspace experience is increasingly cluttered with AI assistants, monitors, and broadcast features aimed at enterprise buyers. For teams that simply want to send requests, persist history, and share collections — on their own infrastructure — the cloud round-trip is a dealbreaker.&lt;/p&gt;

&lt;p&gt;The problems compound for self-hosted stacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data residency.&lt;/strong&gt; Internal API base URLs, bearer tokens, and contract specifications should not transit a third-party SaaS. Compliance regimes (HIPAA, GDPR, SOC 2) treat that as a data flow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Air-gapped and VPC-only environments.&lt;/strong&gt; A VPS or homelab behind Tailscale has no business depending on &lt;code&gt;api.postman.com&lt;/code&gt; for collection resolution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency and flakiness.&lt;/strong&gt; Cloud sync races against local edits. Merge conflicts on shared collections are still a real complaint.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Self-hosted API tooling has matured enough to replace Postman for the vast majority of workflows. This guide benchmarks the three options we deploy most often at &lt;a href="https://selfhoststack-8z4.pages.dev/alternatives/postman" rel="noopener noreferrer"&gt;SelfHostStack&lt;/a&gt;: &lt;strong&gt;Hoppscotch&lt;/strong&gt; (full web UI), &lt;strong&gt;Insomnia&lt;/strong&gt; (desktop client with self-hosted sync), and &lt;strong&gt;Schemathesis&lt;/strong&gt; (property-based contract testing from an OpenAPI spec).&lt;/p&gt;




&lt;h2&gt;
  
  
  The Landscape: Comparative Breakdown
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature / Capability&lt;/th&gt;
&lt;th&gt;Hoppscotch&lt;/th&gt;
&lt;th&gt;Insomnia&lt;/th&gt;
&lt;th&gt;Schemathesis&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary Paradigm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Web-based API client (Postman-in-browser)&lt;/td&gt;
&lt;td&gt;Desktop API client + design tool&lt;/td&gt;
&lt;td&gt;CLI / pytest property-based contract tester&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Runtime&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Vue/Nuxt SPA + Node proxy&lt;/td&gt;
&lt;td&gt;Electron + Kong-style interceptor&lt;/td&gt;
&lt;td&gt;Python package, runs in CI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Self-Hosting Model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Full container stack (web + proxy + backend)&lt;/td&gt;
&lt;td&gt;Kong Gateway-style self-hosted sync (Insomnia Inso CLI, Git-backed)&lt;/td&gt;
&lt;td&gt;Docker container or pip install&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OpenAPI / Swagger&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Import, generate requests&lt;/td&gt;
&lt;td&gt;Import, edit, mock, lint&lt;/td&gt;
&lt;td&gt;Consumes spec, generates thousands of test cases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Team Collaboration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Shared collections via backend DB&lt;/td&gt;
&lt;td&gt;Git-based collections or self-hosted sync&lt;/td&gt;
&lt;td&gt;CI artifacts, JUnit/HTML reports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Auth &amp;amp; Environments&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Environments, secrets, bearer tokens&lt;/td&gt;
&lt;td&gt;Environments, cookie jar, CA certs&lt;/td&gt;
&lt;td&gt;Stateful operations, auth fixtures via code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Automated Testing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hoppscotch CLI (basic)&lt;/td&gt;
&lt;td&gt;Inso CLI (lint + contract test)&lt;/td&gt;
&lt;td&gt;First-class — property-based, fuzzing, stateful&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Resource Footprint&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~250 MB RAM (web + proxy + Postgres)&lt;/td&gt;
&lt;td&gt;~400 MB desktop client&lt;/td&gt;
&lt;td&gt;~80 MB per worker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best Used For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Interactive testing, shared collections&lt;/td&gt;
&lt;td&gt;Day-to-day dev + OpenAPI design&lt;/td&gt;
&lt;td&gt;CI contract testing, regression, fuzzing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Explore the full comparison matrix and additional tools (Bruno, Yaade, HTTPie, Requestly) at &lt;a href="https://selfhoststack-8z4.pages.dev/alternatives/postman" rel="noopener noreferrer"&gt;SelfHostStack: Postman Alternatives&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Hoppscotch: The Self-Hosted Postman Web Client
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Hoppscotch&lt;/strong&gt; is the closest drop-in replacement for Postman's web UX. It is a Vue/Nuxt single-page application backed by a Node.js proxy and (optionally) a PostgreSQL database for shared collections and environments. You run it on your own VPS behind your own reverse proxy, and your team accesses it exactly like Postman's web app — except no data ever leaves your infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Standout Capabilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Browser-native UX.&lt;/strong&gt; No Electron, no 600 MB client. The whole experience loads in a browser tab, which makes it ideal for shared workstations, iPads, and locked-down corporate laptops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collections, environments, and history.&lt;/strong&gt; Full Postman-equivalent data model. Export/import is a one-click JSON flow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-hosted proxy.&lt;/strong&gt; A backend proxy service bypasses CORS and browser TLS restrictions, so you can hit internal &lt;code&gt;http://&lt;/code&gt; services directly from the UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebSocket, SSE, MQTT, Socket.IO.&lt;/strong&gt; First-class support, not a plugin afterthought.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hoppscotch CLI.&lt;/strong&gt; Run collections from CI with &lt;code&gt;hoppscotch-cli&lt;/code&gt; for basic smoke tests — not as deep as Schemathesis, but enough for endpoint reachability.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Production Hoppscotch Docker Compose
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hoppscotch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hoppscotch/hoppscotch:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hoppscotch_frontend&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;HOST=0.0.0.0&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PORT=3000&lt;/span&gt;
      &lt;span class="c1"&gt;# Backend URLs (use internal docker DNS)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;VITE_BASE_URL=http://hoppscotch_backend:3110&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;VITE_SHORT_URL_DOMAIN=https://hs.yourdomain.com&lt;/span&gt;
      &lt;span class="c1"&gt;# Auth providers — leave empty for local-only / disable OAuth&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;VITE_AUTH_ALLOWED_CALLBACK_URLS=https://hs.yourdomain.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ALLOWED_AUTH_REDIRECT_URLS=https://hs.yourdomain.com&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hoppscotch_backend&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hs-net&lt;/span&gt;

  &lt;span class="na"&gt;hoppscotch_backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hoppscotch/hoppscotch-backend:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hoppscotch_backend&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PORT=3110&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DATABASE_URL=postgres://hoppscotch:${POSTGRES_PASSWORD}@hoppscotch_db:5432/hoppscotch?sslmode=disable&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;JWT_SECRET=${JWT_SECRET}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SECRET_KEY_BASE=${SECRET_KEY_BASE}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;REDIS_URL=redis://hoppscotch_redis:6379&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;REDIRECT_URL=https://hs.yourdomain.com&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hoppscotch_db&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hoppscotch_redis&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hs-net&lt;/span&gt;

  &lt;span class="na"&gt;hoppscotch_db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16-alpine&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hoppscotch_db&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DB=hoppscotch&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USER=hoppscotch&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=${POSTGRES_PASSWORD}&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hoppscotch_pg:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hs-net&lt;/span&gt;

  &lt;span class="na"&gt;hoppscotch_redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:7-alpine&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hoppscotch_redis&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hoppscotch_redis_data:/data&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hs-net&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hoppscotch_pg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hoppscotch_redis_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hs-net&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;internal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Put Traefik or Caddy in front of &lt;code&gt;hoppscotch_frontend&lt;/code&gt; on &lt;code&gt;hs.yourdomain.com&lt;/code&gt; and route &lt;code&gt;/_backend&lt;/code&gt; and &lt;code&gt;/proxy&lt;/code&gt; to the backend container. The stack runs comfortably on a 2 vCPU / 2 GB VPS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Honest Pros &amp;amp; Cons
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Genuinely Postman-like UX — the smallest team learning curve of any alternative here.&lt;/li&gt;
&lt;li&gt;Fully open-source (MIT). No tier-gated features, no "Team plan" upgrade pressure.&lt;/li&gt;
&lt;li&gt;Works on iPads and locked-down corporate machines where you cannot install an Electron app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The backend auth story is fiddly. Self-hosted OAuth (Google/GitHub) needs careful redirect URL setup; for local-only deployments you'll probably disable auth entirely and rely on your reverse proxy's HTTP Basic + mTLS.&lt;/li&gt;
&lt;li&gt;The CLI is still lightweight. For serious regression suites you'll pair Hoppscotch with Schemathesis anyway.&lt;/li&gt;
&lt;li&gt;Self-hosted proxy logs request/response bodies by default in dev mode — make sure production logging is dialed back so secrets don't leak to journald.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Insomnia: The Desktop Client With Git-Backed Sync
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Insomnia&lt;/strong&gt; (now stewarded by Kong under the Kong Insomnia brand) is the most polished desktop API client available. After Kong's acquisition roadmap uncertainty settled, the project has re-emphasized local-first workflows: the desktop client runs offline by default, and team collections are synced either via Kong's cloud, or — the self-hosted path — via plain Git repositories.&lt;/p&gt;

&lt;h3&gt;
  
  
  Standout Capabilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OpenAPI design surface.&lt;/strong&gt; Insomnia is not just a request sender; it is a competent OpenAPI editor with live preview, linting, and mock servers. For teams maintaining a single source of truth spec, this collapses two tools into one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inso CLI.&lt;/strong&gt; The &lt;code&gt;inso&lt;/code&gt; binary (distributed as a Docker image) lints specs, runs contract tests, and generates declarative Kong config from your OpenAPI. Drops cleanly into a GitLab or GitHub Actions pipeline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native TLS and CA control.&lt;/strong&gt; Pin custom root CAs for internal mTLS services without fighting Electron's certificate store.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git sync.&lt;/strong&gt; A &lt;code&gt;.insomnia&lt;/code&gt; directory of YAML files committed to a private Git forge (Forgejo, Gitea, GitLab self-hosted) replaces Postman's cloud sync entirely. Branch-based collection workflows actually work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Insomnia + Inso CI via Docker Compose
&lt;/h3&gt;

&lt;p&gt;Insomnia itself is a desktop app, but the &lt;code&gt;inso&lt;/code&gt; CLI is the part that matters for self-hosted CI. Here is a Compose snippet that runs contract tests against your internal API on every commit:&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;inso_contract_test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;support/inso:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;inso_run&lt;/span&gt;
    &lt;span class="na"&gt;profiles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;   &lt;span class="c1"&gt;# invoke with: docker compose --profile test run inso_contract_test&lt;/span&gt;
    &lt;span class="na"&gt;working_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/workspace&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./specs:/workspace:ro&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./reports:/reports&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;API_BASE_URL=https://api.internal.yourdomain.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;API_TOKEN=${INTERNAL_API_TOKEN}&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="s"&gt;sh -c "inso lint spec main --src /workspace/openapi.yaml &amp;amp;&amp;amp;&lt;/span&gt;
             &lt;span class="s"&gt;inso run test main --src /workspace/openapi.yaml&lt;/span&gt;
                 &lt;span class="s"&gt;--env ci&lt;/span&gt;
                 &lt;span class="s"&gt;--test-name 'Contract regression'&lt;/span&gt;
                 &lt;span class="s"&gt;--reporter junit --outputFile /reports/junit.xml&lt;/span&gt;
                 &lt;span class="s"&gt;--reporter html --outputFile /reports/report.html"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This runs on your existing Forge Actions or Gitea Actions runner — no external API, no Postman cloud. The &lt;code&gt;openapi.yaml&lt;/code&gt; lives in the same repo as your application code, versioned and reviewed through normal pull requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Honest Pros &amp;amp; Cons
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The best desktop API client UX, full stop. Request building, response inspection, and GraphQL explorer are all best-in-class.&lt;/li&gt;
&lt;li&gt;Native OpenAPI design — write your spec and immediately mock it from the same window.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;inso&lt;/code&gt; in CI is a serious contract-testing tool; it catches breaking changes before merge.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Kong brand roadmap created a year+ of churn and unclear licensing on enterprise features. The open-source core (Insomnia Core / Inso) is fine, but watch the repo for license changes before standardizing on it.&lt;/li&gt;
&lt;li&gt;Desktop-only — there is no self-hosted web UI. Teams that want browser access still need Hoppscotch alongside it.&lt;/li&gt;
&lt;li&gt;Electron memory footprint (~400 MB resident) is noticeable on small laptops. Not a real problem on a workstation; an annoyance on a 4 GB VM used for jump-box duties.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Schemathesis: Property-Based Contract Testing from Your Spec
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Schemathesis&lt;/strong&gt; is the odd one out in this list, because it is not a GUI client at all. It is a Python tool that reads your OpenAPI (or GraphQL) specification and generates thousands of property-based test cases automatically — fuzzing endpoints, asserting that response status codes match the documented schema, checking that the API does not return &lt;code&gt;500&lt;/code&gt; on inputs that satisfy the documented constraints. Think QuickCheck for your HTTP API.&lt;/p&gt;

&lt;p&gt;For teams that already have an OpenAPI spec (because they're using Insomnia to author it), Schemathesis is what you wire into CI to actually enforce the contract.&lt;/p&gt;

&lt;h3&gt;
  
  
  Standout Capabilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automatic test generation.&lt;/strong&gt; No hand-written test cases — Schemathesis reads your spec and generates valid and invalid inputs for every operation, covering edge cases humans forget (&lt;code&gt;null&lt;/code&gt; arrays, negative integers where &lt;code&gt;minimum: 0&lt;/code&gt; is declared, malformed UUIDs).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stateful testing.&lt;/strong&gt; Define a state machine (create resource → get it → update it → delete it) and Schemathesis explores valid orderings, surfacing race conditions and state-handling bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure shrinking.&lt;/strong&gt; When a test fails, Schemathesis shrinks the failing input to the minimal reproducer — e.g. a single empty string rather than a 4 KB random payload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth fixtures.&lt;/strong&gt; Provide tokens via a Python fixture, so tests run against an authenticated internal API without leaking secrets into the spec.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Schemathesis Docker Compose
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schemathesis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;schemathesis/schemathesis:3&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;schemathesis_run&lt;/span&gt;
    &lt;span class="na"&gt;profiles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contract"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./specs:/specs:ro&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./reports:/reports&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;API_BASE_URL=https://api.internal.yourdomain.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AUTH_TOKEN=${INTERNAL_API_TOKEN}&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="s"&gt;run /specs/openapi.yaml&lt;/span&gt;
      &lt;span class="s"&gt;--base-url ${API_BASE_URL}&lt;/span&gt;
      &lt;span class="s"&gt;--header "Authorization=Bearer ${AUTH_TOKEN}"&lt;/span&gt;
      &lt;span class="s"&gt;--checks all&lt;/span&gt;
      &lt;span class="s"&gt;--max-response-time 5000&lt;/span&gt;
      &lt;span class="s"&gt;--workers 4&lt;/span&gt;
      &lt;span class="s"&gt;--junit-xml /reports/schemathesis.xml&lt;/span&gt;
      &lt;span class="s"&gt;--show-traceback&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;api-net&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;api-net&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it on every PR via Forgejo Actions; a red build blocks merge. This catches the entire class of "I renamed a field in the code but forgot to update the spec" (or vice versa) before it reaches staging.&lt;/p&gt;

&lt;h3&gt;
  
  
  Honest Pros &amp;amp; Cons
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finds bugs GUI testing literally cannot — humans do not click "send" with 200 malformed &lt;code&gt;email&lt;/code&gt; variants.&lt;/li&gt;
&lt;li&gt;Output is a normal pytest/junit artifact; integrates with every CI dashboard you already run.&lt;/li&gt;
&lt;li&gt;Zero infrastructure beyond the container. No DB, no auth, no reverse proxy config.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not a replacement for interactive debugging. You still want Hoppscotch or Insomnia for "let me poke this endpoint by hand."&lt;/li&gt;
&lt;li&gt;Requires a reasonably accurate OpenAPI spec. If your spec is out of date, Schemathesis tests the spec, not your actual API contract — and false greens are worse than reds.&lt;/li&gt;
&lt;li&gt;Python-only extension model. Custom auth flows that need a live OIDC token exchange require writing a Python fixture, which is friction if your stack is Go or Node.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Production Best Practices for Self-Hosted API Testing
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Treat the spec as the source of truth.&lt;/strong&gt; Author OpenAPI in Insomnia or as a YAML file in your app repo. Generate Hoppscotch collections and Schemathesis tests from that spec, not the other way around. One spec, three consumers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pin the tool images.&lt;/strong&gt; Hoppscotch, &lt;code&gt;inso&lt;/code&gt;, and Schemathesis all move fast. Pin to a digest (&lt;code&gt;image: hoppscotch/hoppscotch@sha256:...&lt;/code&gt;) in production Compose files; bump deliberately in a PR.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolate the test network.&lt;/strong&gt; All three Compose snippets above use an internal docker network. Pair them with a &lt;code&gt;tecnativa/docker-socket-proxy&lt;/code&gt; if they need container discovery, and never mount the Docker socket directly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rotate API tokens via Infisical or Vault.&lt;/strong&gt; &lt;code&gt;INTERNAL_API_TOKEN&lt;/code&gt; should come from your secrets manager, not a committed &lt;code&gt;.env&lt;/code&gt;. Wire it through environment injection at deploy time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Back up the Hoppscotch Postgres volume.&lt;/strong&gt; Collections and environments live there. Add the &lt;code&gt;hoppscotch_pg&lt;/code&gt; volume to your restic/pgBackRest schedule alongside the rest of the SelfHostStack data services.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Which Solution Should You Choose?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Choose Hoppscotch&lt;/strong&gt; if you want a Postman replacement your whole team can open in a browser, with collections and environments shared from your own VPS. This is the answer for 80% of teams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose Insomnia&lt;/strong&gt; if your workday is desktop-centric, you author OpenAPI specs, and you want a contract-testing CLI (&lt;code&gt;inso&lt;/code&gt;) that drops into your existing CI pipeline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose Schemathesis&lt;/strong&gt; as the automated layer on top of either — property-based contract testing that catches spec/code drift and malformed input bugs before they ship.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The realistic stack at most self-hosted shops in 2026 is all three: &lt;strong&gt;Hoppscotch for interactive testing, Insomnia for spec design and &lt;code&gt;inso&lt;/code&gt; contract checks in CI, and Schemathesis for deep property-based fuzzing on the merge gate.&lt;/strong&gt; Together they cover everything Postman + Newman did, with zero cloud dependency and full ownership of your API contract data.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Looking for pre-configured, production-hardened Docker stacks — Hoppscotch behind Traefik, Inso in CI, Schemathesis wired into Forgejo Actions, with automated backups?&lt;/em&gt;&lt;br&gt;
Check out the &lt;strong&gt;&lt;a href="https://selfhoststack-8z4.pages.dev/alternatives/postman" rel="noopener noreferrer"&gt;SelfHostStack Postman Alternatives Catalog&lt;/a&gt;&lt;/strong&gt; and grab the &lt;strong&gt;&lt;a href="https://reldefern.gumroad.com/l/stack-pack" rel="noopener noreferrer"&gt;Self-Hosted Starter Stack Pack&lt;/a&gt;&lt;/strong&gt; — save hours of deployment time and run enterprise-grade self-hosted developer infrastructure on your own VPS.&lt;/p&gt;

</description>
      <category>selfhosted</category>
      <category>opensource</category>
      <category>docker</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Self-Hosted Feature Flags in 2026: Unleash vs Flagsmith vs GO Feature Flag (Ditch LaunchDarkly)</title>
      <dc:creator>Elder Fernandes</dc:creator>
      <pubDate>Thu, 27 Aug 2026 17:54:51 +0000</pubDate>
      <link>https://dev.to/enfernandes/self-hosted-feature-flags-in-2026-unleash-vs-flagsmith-vs-go-feature-flag-ditch-launchdarkly-2ho0</link>
      <guid>https://dev.to/enfernandes/self-hosted-feature-flags-in-2026-unleash-vs-flagsmith-vs-go-feature-flag-ditch-launchdarkly-2ho0</guid>
      <description>&lt;h1&gt;
  
  
  Self-Hosted Feature Flags in 626: Unleash vs Flagsmith vs GO Feature Flag (Ditch LaunchDarkly)
&lt;/h1&gt;

&lt;p&gt;Feature flags have become indispensable for modern deployment workflows — trunk-based development, canary releases, A/B testing, and kill switches all depend on them. But commercial platforms like LaunchDarkly and Split.io enforce &lt;strong&gt;per-seat pricing&lt;/strong&gt; ($15–30/developer/month) that scales poorly with growing teams. A 20-developer team pays $3,600–$7,200/year just to toggle booleans.&lt;/p&gt;

&lt;p&gt;Self-hosting an open-source feature flag service gives you &lt;strong&gt;unlimited seats, SDK parity with major languages, audit logs, gradual rollouts, and full data ownership&lt;/strong&gt; on a single VPS.&lt;/p&gt;

&lt;p&gt;In this guide, we compare the top three self-hostable feature flag platforms in 2026: &lt;strong&gt;Unleash&lt;/strong&gt;, &lt;strong&gt;Flagsmith&lt;/strong&gt;, and &lt;strong&gt;GO Feature Flag&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Landscape: Comparative Breakdown
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature / Capability&lt;/th&gt;
&lt;th&gt;Unleash&lt;/th&gt;
&lt;th&gt;Flagsmith&lt;/th&gt;
&lt;th&gt;GO Feature Flag&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core Paradigm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Enterprise-grade flag server with strategies&lt;/td&gt;
&lt;td&gt;Full feature platform + remote config + experimentation&lt;/td&gt;
&lt;td&gt;Lightweight Go relay/proxy with YAML config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Technology Stack&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Node.js, PostgreSQL, Redis&lt;/td&gt;
&lt;td&gt;Django (Python), PostgreSQL, Redis&lt;/td&gt;
&lt;td&gt;Go (single binary), YAML/JSON config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SDK Languages&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;16+ (Java, JS, Python, Go, Rust, Ruby, .NET, Swift, Android, iOS, etc.)&lt;/td&gt;
&lt;td&gt;9+ (Python, JS, Go, Ruby, Rust, Android, iOS, .NET, Java)&lt;/td&gt;
&lt;td&gt;8+ via OpenFeature provider (Go, JS, Python, Java, .NET, Rust)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Strategy Types&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Gradual rollout, A/B, multivariate, kill switch, remote address&lt;/td&gt;
&lt;td&gt;Gradual, boolean, number, string, remote config&lt;/td&gt;
&lt;td&gt;Boolean, gradual, A/B, time-based, dark launch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Audit Log&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes (full event log)&lt;/td&gt;
&lt;td&gt;Yes (change history per flag)&lt;/td&gt;
&lt;td&gt;Basic (config diff via Git)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;UI Dashboard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Full admin UI with projects &amp;amp; environments&lt;/td&gt;
&lt;td&gt;Full admin UI with segments &amp;amp; identities&lt;/td&gt;
&lt;td&gt;Minimal API + OpenFeature-compatible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Self-Host Tier&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Open-source (Apache 2.0) — unlimited seats&lt;/td&gt;
&lt;td&gt;Open-source (BSD-3) — unlimited seats&lt;/td&gt;
&lt;td&gt;Open-source (MIT) — unlimited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Teams needing enterprise strategies &amp;amp; audit trails&lt;/td&gt;
&lt;td&gt;Teams wanting remote config + experiments in one UI&lt;/td&gt;
&lt;td&gt;Teams wanting GitOps-driven flags with minimal footprint&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  1. Unleash — The Enterprise-Grade Flag Server
&lt;/h2&gt;

&lt;p&gt;Unleash is the most mature open-source feature flag platform, originally built at Finn.no (Norway's largest marketplace). It powers production workloads for teams of 50–500+ developers and offers the richest set of rollout strategies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Strengths
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Advanced Strategies:&lt;/strong&gt; Native support for gradual rollout (percentage-based), A/B testing with variant buckets, multi-variant flags, geographic targeting, and custom strategy plugins.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment Isolation:&lt;/strong&gt; Built-in concept of projects → environments (dev, staging, prod) with per-environment token scoping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit Trail:&lt;/strong&gt; Every flag change is logged with actor, timestamp, and diff — critical for compliance and incident post-mortems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SDK Ecosystem:&lt;/strong&gt; Official SDKs for 16+ languages including Rust, Ruby, Android, and iOS. Edge SDKs for Next.js and Cloudflare Workers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Tokens:&lt;/strong&gt; Scoped API tokens with per-project and per-environment permissions — no global admin keys in your application config.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Docker Compose Setup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.9"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;unleash-db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16-alpine&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unleash&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unleash&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${UNLEASH_DB_PASSWORD}&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;unleash-db:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;unleash&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unleashorg/unleash-server:6&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4242:4242"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres://unleash:${UNLEASH_DB_PASSWORD}@unleash-db:5432/unleash&lt;/span&gt;
      &lt;span class="na"&gt;INIT_ADMIN_API_TOKENS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${UNLEASH_API_TOKEN}&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;unleash-db&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;unleash-db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Honest Pros &amp;amp; Cons
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Battle-tested at enterprise scale (Finn.no, DNB, Equinor)&lt;/li&gt;
&lt;li&gt;Rich strategy engine with plugin architecture&lt;/li&gt;
&lt;li&gt;Full audit log out of the box&lt;/li&gt;
&lt;li&gt;Active community (9k+ GitHub stars)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js runtime means higher memory footprint (~300–500MB)&lt;/li&gt;
&lt;li&gt;UI can feel cluttered for small teams with simple boolean needs&lt;/li&gt;
&lt;li&gt;Enterprise edition (Unleash Cloud) is separate from self-hosted open-source; some features (SSO, role-based access) are enterprise-only&lt;/li&gt;
&lt;li&gt;No built-in experimentation/bayesian stats — you need external analytics&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Flagsmith — Feature Flags + Remote Config + Experiments
&lt;/h2&gt;

&lt;p&gt;Flagsmith is a newer platform that combines feature flags with remote configuration, user segments, and lightweight experimentations. It's the best choice for teams that want flags and dynamic config in a single UI without adding a separate tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Strengths
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Remote Config:&lt;/strong&gt; Flagsmith stores boolean, string, integer, and JSON values per flag — your app can fetch config at runtime without redeploying.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Segments:&lt;/strong&gt; Define segments (e.g., "beta users", "enterprise tier") and target flags to specific segments or individual identities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identity Management:&lt;/strong&gt; Built-in concept of user identities — you can override flags per user for testing and QA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Experimentation (Premium):&lt;/strong&gt; A/B testing with Bayesian statistics is available in the open-source edition for basic scenarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edge Proxy:&lt;/strong&gt; A lightweight Go edge relay that caches flags client-side and reduces latency to &amp;lt;1ms.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Docker Compose Setup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.9"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;flagsmith-db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16-alpine&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flagsmith&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flagsmith&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${FLAGSMITH_DB_PASSWORD}&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;flagsmith-db:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;flagsmith&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flagsmith/flagsmith-api:latest&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8000:8000"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres://flagsmith:${FLAGSMITH_DB_PASSWORD}@flagsmith-db:5432/flagsmith&lt;/span&gt;
      &lt;span class="na"&gt;SECRET_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${FLAGSMITH_SECRET}&lt;/span&gt;
      &lt;span class="na"&gt;ENVIRONMENT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;flagsmith-db&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;flagsmith-frontend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flagsmith/flagsmith-frontend:latest&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:8080"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;API_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://flagsmith:8000/api/v1&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;flagsmith&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;flagsmith-db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Honest Pros &amp;amp; Cons
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remote config + flags in one platform&lt;/li&gt;
&lt;li&gt;Clean modern UI with segment targeting&lt;/li&gt;
&lt;li&gt;Edge proxy for client-side caching&lt;/li&gt;
&lt;li&gt;Strong SDK support including mobile (iOS, Android)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Django/Python stack requires more memory than a Go binary (~400–600MB with Postgres)&lt;/li&gt;
&lt;li&gt;Documentation can lag behind the actual API capabilities&lt;/li&gt;
&lt;li&gt;Some advanced features (SSO, audit logs) are enterprise tier&lt;/li&gt;
&lt;li&gt;Community is smaller than Unleash (~4k GitHub stars)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. GO Feature Flag — The GitOps-Native Flag Relay
&lt;/h2&gt;

&lt;p&gt;GO Feature Flag takes a fundamentally different approach: instead of a database-backed server with a UI, it's a &lt;strong&gt;single Go binary&lt;/strong&gt; that reads flag configuration from YAML/JSON files (local or remote Git/S3/HTTP) and exposes an OpenFeature-compatible API. It's designed for teams who want flags to live in Git alongside their code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Strengths
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitOps-Native:&lt;/strong&gt; Flag configs are YAML files versioned in Git — changes go through pull requests, code review, and CI pipelines. No dashboard needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimal Footprint:&lt;/strong&gt; Single Go binary, ~30MB memory, no database required.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenFeature Standard:&lt;/strong&gt; Full compliance with the OpenFeature specification — works with any OpenFeature SDK (Go, JS, Python, Java, .NET, Rust).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration Sources:&lt;/strong&gt; Read flag files from local disk, Git, S3, HTTP endpoints, or Kubernetes ConfigMaps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Database:&lt;/strong&gt; State is derived from the config file — no migrations, no DB backups, no connection pool tuning.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Docker Compose Setup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.9"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;go-feature-flag-relay&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gofeatureflag/relay-proxy:latest&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1031:1031"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;LISTEN=:1031&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POLLINGINTERVAL=5s&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;RETRIEVER_KIND=http&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;RETRIEVER_URL=https://raw.githubusercontent.com/yourorg/flags/main/flags.yml&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;RETRIEVER_GITHUB_TOKEN=${GITHUB_TOKEN}&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example Flag Config (flags.yml)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;new-checkout-flow&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;variations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;defaultRule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;variation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;disabled&lt;/span&gt;
  &lt;span class="na"&gt;rules&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;beta-testers&lt;/span&gt;
      &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;key:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"email",&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;operator:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;endsWith,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;value:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"@beta.com"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}'&lt;/span&gt;
      &lt;span class="na"&gt;variation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;enabled&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;10-percent-rollout&lt;/span&gt;
      &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;key:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"userId",&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;operator:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;percentage,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;value:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;10&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}'&lt;/span&gt;
      &lt;span class="na"&gt;variation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;enabled&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Honest Pros &amp;amp; Cons
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero database — perfect for GitOps and Kubernetes&lt;/li&gt;
&lt;li&gt;~30MB memory footprint — runs on the smallest VPS&lt;/li&gt;
&lt;li&gt;Full OpenFeature compliance — vendor-neutral SDK layer&lt;/li&gt;
&lt;li&gt;Configuration-as-code with PR review and audit trail via Git&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No built-in UI dashboard — you manage flags via YAML in Git&lt;/li&gt;
&lt;li&gt;No built-in audit log beyond Git history&lt;/li&gt;
&lt;li&gt;Smaller community (~1.5k GitHub stars)&lt;/li&gt;
&lt;li&gt;Not ideal for non-technical product teams who need a visual dashboard&lt;/li&gt;
&lt;li&gt;No native experimentation/bayesian A/B testing&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Decision Guide
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your Situation&lt;/th&gt;
&lt;th&gt;Recommended Tool&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Enterprise team, need audit trails + SSO + advanced strategies&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Unleash&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Need flags + remote config + user segments in one UI&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Flagsmith&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitOps-native, no database, minimal footprint&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;GO Feature Flag&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Want all three approaches?&lt;/td&gt;
&lt;td&gt;Combine: GO Feature Flag as edge relay + Unleash as backend&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Production Best Practices
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pin Docker image tags:&lt;/strong&gt; Use &lt;code&gt;unleash-server:6.6.0&lt;/code&gt; not &lt;code&gt;latest&lt;/code&gt;. Flag platform upgrades can introduce breaking API changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network isolation:&lt;/strong&gt; Put the flag server and database on an internal Docker network. Expose only the API port (4242 for Unleash, 8000 for Flagsmith, 1031 for GO Feature Flag) through Traefik/Caddy with mTLS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SDK initialization:&lt;/strong&gt; Initialize SDKs with a server-sent events (SSE) connection for real-time flag updates. Polling adds latency; SSE is push-based and near-instant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secrets management:&lt;/strong&gt; Store API tokens and database passwords in Infisical or Vaultwarden — not in &lt;code&gt;.env&lt;/code&gt; files checked into Git.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backup the database:&lt;/strong&gt; If using Unleash or Flagsmith, automate PostgreSQL backups with pgBackRest or restic. GO Feature Flag needs no backup (state is in Git).&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;LaunchDarkly charges $15–30/developer/month. For a 20-developer team, that's $3,600–$7,200/year. A self-hosted feature flag platform on a $5 VPS gives you unlimited seats, full data ownership, and SDK parity with every major language.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unleash&lt;/strong&gt; for enterprise teams needing audit trails and advanced strategies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flagsmith&lt;/strong&gt; for teams wanting flags + remote config in one platform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GO Feature Flag&lt;/strong&gt; for GitOps-native deployments with zero database overhead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Explore the full comparison and deployment guides:&lt;br&gt;
👉 &lt;a href="https://selfhoststack-8z4.pages.dev/alternatives/launchdarkly" rel="noopener noreferrer"&gt;Self-Hosted Feature Flag Alternatives&lt;/a&gt;&lt;/p&gt;

</description>
      <category>selfhosted</category>
      <category>opensource</category>
      <category>docker</category>
      <category>devops</category>
    </item>
    <item>
      <title>Self-Hosted Customer Support &amp; Helpdesks in 2026: Chatwoot vs FreeScout vs Helpy</title>
      <dc:creator>Elder Fernandes</dc:creator>
      <pubDate>Mon, 24 Aug 2026 05:45:34 +0000</pubDate>
      <link>https://dev.to/enfernandes/self-hosted-customer-support-helpdesks-in-2026-chatwoot-vs-freescout-vs-helpy-1d8b</link>
      <guid>https://dev.to/enfernandes/self-hosted-customer-support-helpdesks-in-2026-chatwoot-vs-freescout-vs-helpy-1d8b</guid>
      <description>&lt;h1&gt;
  
  
  Self-Hosted Customer Support &amp;amp; Helpdesks in 2026: Chatwoot vs FreeScout vs Helpy
&lt;/h1&gt;

&lt;p&gt;Delivering exceptional customer support is essential for growth, but commercial helpdesk platforms enforce punitive pricing models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Per-Agent Seat Taxes:&lt;/strong&gt; Intercom, Zendesk, and Front charge $49 to $119+ per agent per month. As your support and engineering teams grow, licensing costs quickly spiral into tens of thousands of dollars annually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add-On Paywalls:&lt;/strong&gt; Essential capabilities like WhatsApp integration, SMS channels, unlimited email history, and custom webhooks are locked behind enterprise tiers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customer Data Privacy:&lt;/strong&gt; Confidential customer conversations, billing inquiries, and personal data are held on third-party multi-tenant servers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Self-hosting an open-source support helpdesk gives your team &lt;strong&gt;unlimited agent seats, unified omnichannel inboxes (Live Chat, WhatsApp, Email, Telegram, Social), full webhook customization, and complete data ownership on your own VPS&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this guide, we evaluate the top three self-hosted support and ticketing platforms in 2026: &lt;strong&gt;Chatwoot&lt;/strong&gt;, &lt;strong&gt;FreeScout&lt;/strong&gt;, and &lt;strong&gt;Helpy&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Landscape: Comparative Breakdown
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature / Capability&lt;/th&gt;
&lt;th&gt;Chatwoot&lt;/th&gt;
&lt;th&gt;FreeScout&lt;/th&gt;
&lt;th&gt;Helpy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core Paradigm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Modern Omnichannel Live Chat + Shared Inbox&lt;/td&gt;
&lt;td&gt;Clean Shared Email Inbox (Help Scout Alternative)&lt;/td&gt;
&lt;td&gt;Traditional Support Ticketing &amp;amp; Knowledge Base&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Technology Stack&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ruby on Rails, Vue.js, PostgreSQL, Redis&lt;/td&gt;
&lt;td&gt;PHP (Laravel), MySQL/PostgreSQL, Vue&lt;/td&gt;
&lt;td&gt;Ruby on Rails, PostgreSQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Supported Channels&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Web Live Chat, Email, WhatsApp, Telegram, Facebook, SMS&lt;/td&gt;
&lt;td&gt;Email Inboxes, Webhooks, Community Modules&lt;/td&gt;
&lt;td&gt;Email Ticketing, Public/Private Help Center&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bot &amp;amp; AI Integrations&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Native Webhooks, Rasa, Dialogflow, OpenAI&lt;/td&gt;
&lt;td&gt;Modules available for automation &amp;amp; canned replies&lt;/td&gt;
&lt;td&gt;Automated workflows &amp;amp; AI taggers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mobile Applications&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Official iOS &amp;amp; Android Apps&lt;/td&gt;
&lt;td&gt;Mobile Web / PWA / Community Apps&lt;/td&gt;
&lt;td&gt;Mobile responsive web UI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hardware Overhead&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Moderate (2 vCPU, 4GB RAM)&lt;/td&gt;
&lt;td&gt;Ultra-Lightweight (1 vCPU, 1GB RAM)&lt;/td&gt;
&lt;td&gt;Lightweight (1-2 vCPU, 2GB RAM)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best Used For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Real-time website chat, omnichannel SaaS support&lt;/td&gt;
&lt;td&gt;Shared team email management, agency ticketing&lt;/td&gt;
&lt;td&gt;Classic IT helpdesks and knowledge base portals&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Explore full feature comparisons and alternative tools at: &lt;a href="https://selfhoststack-8z4.pages.dev/alternatives/zendesk" rel="noopener noreferrer"&gt;SelfHostStack Zendesk Alternatives&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Chatwoot: The Modern Intercom &amp;amp; Crisp Alternative
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Chatwoot&lt;/strong&gt; is an open-source, omnichannel customer engagement suite. It unifies live website chat widgets, email support, WhatsApp business numbers, and social channels into a single real-time collaborative dashboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  Standout Capabilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Embeddable Live Widget:&lt;/strong&gt; Customizable JavaScript widget with automated greetings, offline forms, and pre-chat surveys.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Brand &amp;amp; Multi-Team Routing:&lt;/strong&gt; Route inquiries by department (Sales, Billing, Technical) with automated assignment rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich Mobile Ecosystem:&lt;/strong&gt; Official native apps for iOS and Android allowing team members to resolve customer queries on the go.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Production Chatwoot Docker Compose Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;chatwoot_web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot/chatwoot:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot_web&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NODE_ENV=production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;RAILS_ENV=production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;INSTALLATION_ENV=docker&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SECRET_KEY_BASE=${SECRET_KEY_BASE}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FRONTEND_URL=https://support.yourdomain.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_HOST=postgres&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DATABASE=chatwoot_production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USERNAME=chatwoot&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=${POSTGRES_PASSWORD}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;REDIS_URL=redis://redis:6379&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MAILER_SENDER_EMAIL=support@yourdomain.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_ADDRESS=smtp.resend.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_PORT=587&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_USERNAME=resend&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_PASSWORD=${SMTP_PASSWORD}&lt;/span&gt;
    &lt;span class="na"&gt;entrypoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/entrypoints/rails.sh&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bundle'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;exec'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rails'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-p'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3000'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-b'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0'&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:3000:3000"&lt;/span&gt;

  &lt;span class="na"&gt;chatwoot_worker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot/chatwoot:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot_worker&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NODE_ENV=production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;RAILS_ENV=production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;INSTALLATION_ENV=docker&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SECRET_KEY_BASE=${SECRET_KEY_BASE}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FRONTEND_URL=https://support.yourdomain.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_HOST=postgres&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DATABASE=chatwoot_production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USERNAME=chatwoot&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=${POSTGRES_PASSWORD}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;REDIS_URL=redis://redis:6379&lt;/span&gt;
    &lt;span class="na"&gt;entrypoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/entrypoints/rails.sh&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bundle'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;exec'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sidekiq'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-C'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;config/sidekiq.yml'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16-alpine&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot_postgres&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;chatwoot_pgdata:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DB=chatwoot_production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USER=chatwoot&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=${POSTGRES_PASSWORD}&lt;/span&gt;

  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:7-alpine&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot_redis&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;chatwoot_redisdata:/data&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;chatwoot_pgdata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;chatwoot_redisdata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. FreeScout: The Ultra-Lightweight Help Scout Clone
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;FreeScout&lt;/strong&gt; is built on PHP/Laravel and delivers an exceptional shared email inbox experience. If your customer support workflow is primarily email-centric (e.g. &lt;code&gt;support@yourdomain.com&lt;/code&gt;), FreeScout offers near-zero memory footprint (under 300MB RAM) and blazing-fast response speeds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Standout Capabilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Effortless Email Threading:&lt;/strong&gt; Seamlessly parses incoming IMAP/POP3 emails and sends outbound replies via SMTP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collision Detection:&lt;/strong&gt; Prevents two team members from accidentally answering the same customer ticket simultaneously.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low Resource Profile:&lt;/strong&gt; Easily runs on a $3.50/mo VPS alongside existing web workloads.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Production Best Practices for Self-Hosted Support
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Transactional Email Reliability:&lt;/strong&gt; Connect your self-hosted helpdesk to a reliable SMTP relay (such as Amazon SES, Resend, or Stalwart) to guarantee 100% inbox deliverability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated Database Backups:&lt;/strong&gt; Schedule daily WAL and snapshot backups with &lt;code&gt;pgBackRest&lt;/code&gt; or &lt;code&gt;restic&lt;/code&gt; to an offsite S3 bucket.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webhook Integrations:&lt;/strong&gt; Forward new urgent tickets to internal Slack/Discord channels using n8n or native webhook notifications.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Which Solution Should You Choose?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Choose &lt;strong&gt;Chatwoot&lt;/strong&gt; if you need real-time website live chat, mobile support apps, and multi-channel messaging (WhatsApp, Telegram, Live Chat).&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;FreeScout&lt;/strong&gt; if your support operations revolve around shared email inboxes and you want minimal RAM usage on a tiny VPS.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Helpy&lt;/strong&gt; if you require classic ticketing workflows combined with a self-hosted multilingual knowledge base.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Looking for pre-configured, production-hardened Docker stacks with Traefik SSL and automated backups?&lt;/em&gt;&lt;br&gt;&lt;br&gt;
Check out the &lt;strong&gt;&lt;a href="https://reldefern.gumroad.com/l/stack-pack" rel="noopener noreferrer"&gt;Self-Hosted Starter Stack Pack ($29)&lt;/a&gt;&lt;/strong&gt; — save hours of deployment time and run enterprise-grade self-hosted infrastructure.&lt;/p&gt;

</description>
      <category>selfhosted</category>
      <category>opensource</category>
      <category>docker</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
