<?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: Own The Stack</title>
    <description>The latest articles on DEV Community by Own The Stack (@ownthestack).</description>
    <link>https://dev.to/ownthestack</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%2F3970464%2F61546a8b-ee57-4266-930f-c994118cc31d.jpg</url>
      <title>DEV Community: Own The Stack</title>
      <link>https://dev.to/ownthestack</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ownthestack"/>
    <language>en</language>
    <item>
      <title>Block Ads on Every Device, Everywhere!</title>
      <dc:creator>Own The Stack</dc:creator>
      <pubDate>Sun, 07 Jun 2026 13:07:57 +0000</pubDate>
      <link>https://dev.to/ownthestack/block-ads-on-every-device-everywhere-427h</link>
      <guid>https://dev.to/ownthestack/block-ads-on-every-device-everywhere-427h</guid>
      <description>&lt;h1&gt;
  
  
  Block Ads on Every Device, Everywhere
&lt;/h1&gt;

&lt;p&gt;Most ad-blocking setups only work at home. You configure a DNS server on your router, enjoy a cleaner internet experience, then leave your Wi-Fi network and lose all of it. Your phone switches to mobile data, your laptop joins a coffee shop network, and suddenly you are right back to dealing with intrusive ads, trackers, telemetry requests, and analytics endpoints.&lt;/p&gt;

&lt;p&gt;I wanted an infrastructure setup that followed me everywhere. Not just on my home network, and not just when connected to Wi-Fi. I needed it on every device, on every network, everywhere. This is how I built it using AdGuard Home and Tailscale—and why the simplest design ended up being the superior engineering choice.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is Tailscale?
&lt;/h2&gt;

&lt;p&gt;Before diving into the implementation, it is worth understanding why Tailscale makes this architecture possible. Tailscale is a zero-config VPN built on top of the WireGuard protocol that creates a secure, private mesh network between all of your connected nodes, known as a Tailnet.&lt;/p&gt;

&lt;p&gt;You can install it seamlessly on your laptop, phone, desktop, VPS, or home server. Once configured, they can securely communicate regardless of where they are physically located. Your phone on mobile data can route directly to your server at home, and your laptop in a coffee shop can securely reach a VPS in another country. Everything behaves as if it is sitting on the exact same local private network topology.&lt;/p&gt;

&lt;p&gt;Each device on the mesh network receives a stable, private IP address in the &lt;code&gt;100.x.x.x&lt;/code&gt; range. Crucially for our use case, Tailscale allows you to centrally manage DNS settings for every single device connected to your Tailnet. Instead of configuring custom DNS servers separately across multiple operating systems, we configure it once in our Tailscale coordinator panel and let it distribute everywhere automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  Option 1: The Five-Second Setup
&lt;/h2&gt;

&lt;p&gt;If all you want is robust ad blocking without running or maintaining any of your own compute infrastructure, AdGuard provides public DNS servers that can be integrated directly into your Tailnet.&lt;/p&gt;

&lt;p&gt;To set this up, open your Tailscale Admin Console, navigate to &lt;strong&gt;DNS&lt;/strong&gt;, and locate the &lt;strong&gt;Global Nameservers&lt;/strong&gt; section. Add the following public upstream IP addresses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;94.140.14.14&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;94.140.15.15&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once added, toggle the &lt;strong&gt;Override Local DNS&lt;/strong&gt; option to &lt;strong&gt;On&lt;/strong&gt;. Every device connected to your Tailnet will immediately begin using AdGuard's public upstream resolvers for all outbound traffic.&lt;/p&gt;

&lt;p&gt;For many users, this zero-maintenance approach is more than enough. However, the obvious downside is that you lose absolute control over your traffic. You cannot build custom blocklists, view granular query logs, write local DNS split-horizon overrides, or manage device-specific filtering rules. If you prefer owning your stack completely, self-hosting is the path forward.&lt;/p&gt;




&lt;h2&gt;
  
  
  Option 2: Self-Hosted AdGuard Home
&lt;/h2&gt;

&lt;p&gt;Running a dedicated AdGuard Home instance gives you absolute data sovereignty and complete control over your network's DNS filtering layers. The computational footprint is incredibly lightweight. A minimal cloud VPS with roughly 512MB of RAM is plenty of overhead to handle a personal DNS server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying AdGuard Home Securely
&lt;/h3&gt;

&lt;p&gt;Many standard deployment guides tell you to map ports directly out to the host using &lt;code&gt;"53:53/udp"&lt;/code&gt;. On Linux hosts, Docker manipulates &lt;code&gt;iptables&lt;/code&gt; directly and completely bypasses standard host firewalls like &lt;code&gt;ufw&lt;/code&gt;. This unintentionally exposes your DNS port to the public internet, making your VPS a prime target for weaponized DNS Amplification DDoS attacks.&lt;/p&gt;

&lt;p&gt;To circumvent this risk completely, we can leverage Docker's &lt;code&gt;host&lt;/code&gt; networking mode. This forces the container to share the host's network interfaces directly, allowing us to safely bind AdGuard Home exclusively to our private Tailscale interface during the initial configuration wizard.&lt;/p&gt;

&lt;p&gt;Create your deployment file:&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;adguardhome&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;adguard/adguardhome&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;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&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;./adguard_data:/opt/adguardhome/work&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./adguard_conf:/opt/adguardhome/conf&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;3000:3000/tcp"&lt;/span&gt;  &lt;span class="c1"&gt;# This will be your permanent Admin UI port&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="c1"&gt;# This maps the setup wizard/web service to 8080&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;# DNS-over-TLS (optional but good for tech gadgets)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the stack in detached mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the container refuses to bind or fails to start, an existing system service is likely already listening on port 53. The most common culprits on modern Linux distributions are &lt;code&gt;systemd-resolved&lt;/code&gt; or &lt;code&gt;dnsmasq&lt;/code&gt;. You must stop, disable, or reconfigure the conflicting service on the host before AdGuard Home can successfully claim the port.&lt;/p&gt;




&lt;h2&gt;
  
  
  Connecting AdGuard Home to Tailscale
&lt;/h2&gt;

&lt;p&gt;Once the container is initialized, access the setup wizard by pointing your browser to your server's IP address at port 3000: &lt;code&gt;http://YOUR_SERVER_IP:3000&lt;/code&gt;. Complete the prompts to establish your admin credentials and choose your interfaces.&lt;/p&gt;

&lt;p&gt;With AdGuard up and running, it is time to link it globally to your network:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your Tailscale Admin Console and copy your VPS's private &lt;strong&gt;Tailscale IP&lt;/strong&gt; (the &lt;code&gt;100.x.x.x&lt;/code&gt; address).&lt;/li&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;DNS&lt;/strong&gt; configuration tab.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Global Nameservers&lt;/strong&gt;, click &lt;strong&gt;Add Nameserver&lt;/strong&gt; and choose &lt;strong&gt;Custom&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Paste your private server IP, save the configuration, and enable &lt;strong&gt;Override Local DNS&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Always use the Tailscale network interface IP rather than the server's public IP address. This guarantees that your raw DNS payloads travel strictly inside an encrypted WireGuard tunnel, completely isolated from the open internet. Your laptop, phone, tablet, and desktop will now route their lookups through your private instance, regardless of where you travel.&lt;/p&gt;




&lt;h2&gt;
  
  
  What DNS Blocking Can and Can't Do
&lt;/h2&gt;

&lt;p&gt;DNS filtering is an incredibly effective tool, but it is not magic. It excels at dropping queries to known tracking domains, blocking background application telemetry, and filtering advertisements on platforms that do not support standard browser extensions.&lt;/p&gt;

&lt;p&gt;However, it cannot reliably strip out video advertisements on platforms like YouTube, nor can it stop ads served directly from the same domain hosting the content. Think of network-level DNS filtering as an essential, high-performance first layer of defense rather than a complete alternative to client-side browser extensions like uBlock Origin.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Operational Reality
&lt;/h2&gt;

&lt;p&gt;There is an unavoidable architectural reality to this setup. If your self-hosted DNS server drops offline or the container panics, your internet access effectively breaks. Because almost every app and web page initialization begins with a synchronous DNS lookup, a failure here causes everything to fail in strange, silent ways.&lt;/p&gt;

&lt;p&gt;Fortunately, your emergency exit playbook is simple: &lt;strong&gt;Turn off Tailscale.&lt;/strong&gt; Disconnecting your client device from your Tailnet instantly drops the operating system back to the local network's native DNS configuration, bringing you back online immediately.&lt;/p&gt;

&lt;p&gt;When encountering this reliability challenge, the immediate engineering instinct is to add a public fallback resolver like &lt;code&gt;1.1.1.1&lt;/code&gt; in the Tailscale dashboard. However, this disrupts your filtering strategy entirely. Operating systems do not gracefully fail over; instead, they often query multiple configured nameservers in parallel or round-robin between them, causing ads to slip past your filter even when your server is completely healthy.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Over-Engineering Rabbit Hole
&lt;/h2&gt;

&lt;p&gt;You could build an enterprise-grade high-availability system to mitigate this risk. You could spin up redundant global nodes, synchronize configurations automatically using open-source sync tools, and manage complex internal load balancers.&lt;/p&gt;

&lt;p&gt;But for a personal project, that introduces massive architectural complexity to solve a failure that might happen once a year. The management overhead of the infrastructure quickly outgrows the practical utility of the tool.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Control&lt;/th&gt;
&lt;th&gt;Reliability&lt;/th&gt;
&lt;th&gt;Complexity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Public AdGuard DNS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Very Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Self-Hosted AdGuard Home&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;High&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Moderate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Low&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Multi-Server Infrastructure&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A cleaner, more pragmatic engineering tradeoff is keeping a single, hardened AdGuard Home instance backed by a clear recovery plan. Simple systems fail in highly predictable ways, require zero configuration synchronization, and are easy to maintain. Sometimes, owning the stack isn't about deploying the most complex distributed architecture—it is about knowing exactly where complexity pays for itself, and where it doesn't.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why I Bypassed the Cloud Treadmill to Build a 100% Independent Self-Hosted Stack</title>
      <dc:creator>Own The Stack</dc:creator>
      <pubDate>Fri, 05 Jun 2026 22:03:23 +0000</pubDate>
      <link>https://dev.to/ownthestack/why-i-bypassed-the-cloud-treadmill-to-build-a-100-independent-self-hosted-stack-3d1b</link>
      <guid>https://dev.to/ownthestack/why-i-bypassed-the-cloud-treadmill-to-build-a-100-independent-self-hosted-stack-3d1b</guid>
      <description>&lt;p&gt;Philosophy doesn't mean much without execution. If I’m going to advocate for data sovereignty and owning your data, I need to show you exactly what my architecture stands on.&lt;/p&gt;

&lt;p&gt;My project, OWNTHESTACK.co, isn't deployed to a massive managed web service, it doesn't use third-party serverless infrastructure, and it doesn't store media in an invisible corporate bucket. It runs entirely on an independent, flat-rate virtual private server (VPS) running minimal Linux.&lt;/p&gt;

&lt;p&gt;Here is the exact containerized layout and setup powering the application.&lt;br&gt;
The Design Philosophy&lt;/p&gt;

&lt;p&gt;The goal: maximum control, absolute data ownership, and strict network privacy. The host operating system remains completely clean. Everything is modular, portable, and tightly locked down inside isolated internal container environments.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Core Engine (.NET 8 &amp;amp; React)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The backend processing engine is a clean .NET 8 application. Modern .NET is incredibly fast, memory-efficient, and runs flawlessly inside isolated Linux containers. It handles text payloads and securely encrypted administration sessions. The frontend uses lightweight static production assets served with near-zero resource overhead.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Personal Data Control (PostgreSQL 16)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every word of text, metadata tag, and background layout setting lives in a localized PostgreSQL 16 data engine running locally inside an isolated container with an explicit disk mount. Backups are raw, automated compressed files controlled by simple shell scripts that back up exactly what matters to an encrypted storage destination I control.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Independent Media Storage (MinIO)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Inline graphics don't stream from a generic public media host or a third-party asset SaaS. They stream straight out of a local MinIO storage vault container running on our hardware using secure, short-lived cryptographic links.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reversing the Firewall (Cloudflare Tunnels)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the most critical privacy and security boundary. If you run an external network port scan on this server's public IP address, port 80 and port 443 are completely closed. Instead of opening the server to the wide-open internet and constantly fighting off automated bot scans, the server runs a secure outbound tunnel daemon. It establishes an encrypted, outbound-only pipeline to the network edge. Web traffic routes securely down this outbound pipe straight to our internal container environment. If it doesn't originate from this authenticated channel, it cannot touch our data.&lt;/p&gt;

&lt;p&gt;I am documenting my entire journey of migrating off corporate platforms, sharing raw configs, and analyzing self-hosted infrastructure. Follow along or subscribe to the raw logs at &lt;a href="https://ownthestack.co/posts/architecture" rel="noopener noreferrer"&gt;OwnTheStack.co&lt;/a&gt;&lt;/p&gt;

</description>
      <category>selfhosted</category>
      <category>architecture</category>
      <category>dotnet</category>
      <category>devops</category>
    </item>
    <item>
      <title>What Am I Actually Depending On? A Practical Approach to Data Sovereignty</title>
      <dc:creator>Own The Stack</dc:creator>
      <pubDate>Fri, 05 Jun 2026 21:57:47 +0000</pubDate>
      <link>https://dev.to/ownthestack/what-am-i-actually-depending-on-a-practical-approach-to-data-sovereignty-dd8</link>
      <guid>https://dev.to/ownthestack/what-am-i-actually-depending-on-a-practical-approach-to-data-sovereignty-dd8</guid>
      <description>&lt;p&gt;Most of us don’t really own our digital lives.&lt;/p&gt;

&lt;p&gt;Our photos live in cloud libraries. Our documents sit in someone else’s storage systems. Our passwords are managed by services we log into, not systems we control. It’s convenient, fast, and mostly invisible.&lt;/p&gt;

&lt;p&gt;But at some point, I started asking a simple question: what am I actually depending on here?&lt;/p&gt;

&lt;p&gt;The more systems I looked into, the more I realized how much personal data flows through platforms I don’t control. What gets stored, how it’s used, where it’s replicated, and who ultimately has access to it is often hidden behind terms of service most people never read. Convenience often comes with tradeoffs that are easy to ignore until they matter.&lt;br&gt;
Thinking Differently About Data Management&lt;/p&gt;

&lt;p&gt;I decided to evaluate where my information lives, how it’s backed up, how portable it is, and what happens if I ever want to leave a service. Not in an extreme way, but in a practical one: reducing dependency, increasing clarity, and keeping control where it matters.&lt;/p&gt;

&lt;p&gt;I broke things. A lot of things. I rebuilt them. I migrated setups that didn’t scale. I replaced tools I thought I needed with simpler systems I could actually explain. And slowly, I started to care less about convenience at any cost, and more about understanding the ground I was standing on.&lt;/p&gt;

&lt;p&gt;The goal isn’t to reject modern tools or pretend everything should be self-hosted. It’s to understand what we use well enough to choose it deliberately instead of passively accepting vendor lock-in.&lt;/p&gt;

&lt;p&gt;Over the next few weeks, I’m putting out raw logs covering:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Self-hosting &amp;amp; app deployment

Data ownership &amp;amp; portability

Docker orchestration &amp;amp; Linux systems

Networking &amp;amp; outbound secure tunnels

Backups &amp;amp; monitoring
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;No schedules, no marketing noise. Just raw building, breaking, and learning what holds up. Check out the project architecture at &lt;a href="//ownthestack.co"&gt;ownthestack.co&lt;/a&gt;&lt;/p&gt;

</description>
      <category>privacy</category>
      <category>opensource</category>
      <category>linux</category>
      <category>sysadmin</category>
    </item>
  </channel>
</rss>
