<?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: Mdtzlm</title>
    <description>The latest articles on DEV Community by Mdtzlm (@mdtzlm).</description>
    <link>https://dev.to/mdtzlm</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3870047%2F6e20efa2-1e61-403d-9d6c-2a7c8936dbec.png</url>
      <title>DEV Community: Mdtzlm</title>
      <link>https://dev.to/mdtzlm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mdtzlm"/>
    <language>en</language>
    <item>
      <title>I built a directory of EU software alternatives. Then HN pointed out I was running it on Cloudflare.</title>
      <dc:creator>Mdtzlm</dc:creator>
      <pubDate>Thu, 09 Apr 2026 14:42:35 +0000</pubDate>
      <link>https://dev.to/mdtzlm/i-built-a-directory-of-eu-software-alternatives-then-hn-pointed-out-i-was-running-it-on-cloudflare-1cem</link>
      <guid>https://dev.to/mdtzlm/i-built-a-directory-of-eu-software-alternatives-then-hn-pointed-out-i-was-running-it-on-cloudflare-1cem</guid>
      <description>&lt;p&gt;&lt;a href="https://only-eu.eu" rel="noopener noreferrer"&gt;only-eu.eu&lt;/a&gt; is a directory of verified European alternatives to common US software. Proton instead of Gmail, filen instead of Dropbox, that kind of thing. 332 pages, EN and DE, 88+ products.&lt;/p&gt;

&lt;p&gt;This is about how it's built. Some decisions I'd make again. One I had to fix while 6,100 people were on the site.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why Astro
&lt;/h3&gt;

&lt;p&gt;The site is content: product pages, category pages, a landing page. No user accounts, no dynamic feeds, nothing that needs a server at render time. Astro was the obvious fit. Static output, fast builds, and you only ship client-side JS where you explicitly add it.&lt;/p&gt;

&lt;p&gt;In practice the site has two interactive elements: a "switch tool" widget on the homepage (shows EU alternatives based on what US tool you use) and a suggestion modal for submitting new products. Both are Astro islands. Everything else is plain HTML from the build.&lt;/p&gt;

&lt;p&gt;Build time for 332 pages is around 40 seconds. That includes generating both language variants for every product and category page from a single TypeScript data source. Astro's file-based routing made the i18n structure straightforward: &lt;code&gt;/[lang]/[category]/[product]&lt;/code&gt; resolves cleanly with &lt;code&gt;getStaticPaths&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Hosting: from Cloudflare Pages to Bunny.net
&lt;/h3&gt;

&lt;p&gt;The site launched on Cloudflare Pages. It works fine: zero config, fast deploys, generous free tier. But after a Show HN post got traction (326 upvotes, ~6,100 visitors in a day), I decided to migrate.&lt;/p&gt;

&lt;p&gt;The reason was not performance. It was consistency. A directory arguing "use European software" probably should not run on US infrastructure. Cloudflare is registered in San Francisco.&lt;/p&gt;

&lt;p&gt;I moved to &lt;strong&gt;Bunny.net&lt;/strong&gt; for hosting, CDN, and DNS. Bunny is registered in Slovenia, runs its edge network across EU regions first, and the developer experience is comparable to Cloudflare. Maybe a bit more config upfront, but nothing unreasonable.&lt;/p&gt;

&lt;p&gt;The migration itself was mostly a DNS exercise. Bunny has a Storage Zone for static files and a Pull Zone for CDN delivery. You point your DNS at Bunny, configure the Pull Zone to serve from the Storage Zone, set up the custom hostname, and deploy via their API. I integrated the deploy into the existing build step: &lt;code&gt;bunny.net&lt;/code&gt; CLI uploads the &lt;code&gt;dist/&lt;/code&gt; folder after &lt;code&gt;astro build&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One thing to watch: Bunny's DNS API uses numeric type codes. Type 0 for A records, Type 2 for CNAME, Type 3 for TXT. The docs are a bit sparse on this. I created two TXT records by accident before I found the right values.&lt;/p&gt;




&lt;h3&gt;
  
  
  API and analytics: Hetzner VPS + self-hosted Plausible
&lt;/h3&gt;

&lt;p&gt;The site has a small backend: a suggestion API (collects product submissions from users), a contact form endpoint, and an automation layer. All of that runs on a single Hetzner VPS in Nuremberg (~4 EUR/month).&lt;/p&gt;

&lt;p&gt;Analytics is self-hosted Plausible on the same VPS. No cookie banner, no third-party JS, no fingerprinting. A clean analytics dashboard with no data leaving the EU and no GDPR consent dialog. For a site about EU software, that felt like the only reasonable option.&lt;/p&gt;




&lt;h3&gt;
  
  
  What broke during the HN launch
&lt;/h3&gt;

&lt;p&gt;When the Show HN post went live, the first substantive comment pointed out that Ente Photos, which I had listed as Norwegian, is actually incorporated in Delaware, USA. I removed it within the hour.&lt;/p&gt;

&lt;p&gt;That comment prompted a full pricing audit across all products. I found 19 incorrect prices. Corrected all of them the same day.&lt;/p&gt;

&lt;p&gt;And then there was the comment that stung a little more. Someone noted that a directory promoting European alternatives was running on Cloudflare, a US company headquartered in San Francisco. They were right. The HN community did not let that one slide quietly, and honestly I deserved it. That is part of why the Bunny.net migration happened: not just because of the principle, but because the irony had been pointed out publicly and I had no good counterargument.&lt;/p&gt;

&lt;p&gt;None of these were catastrophic. But they were visible. A community of thorough people will find the things you missed, including the things you were already a little uncomfortable about.&lt;/p&gt;




&lt;h3&gt;
  
  
  Current state
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;332 pages (EN + DE)&lt;/li&gt;
&lt;li&gt;88+ products, 20+ categories&lt;/li&gt;
&lt;li&gt;Hosting: Bunny.net (EU)&lt;/li&gt;
&lt;li&gt;DNS: Bunny DNS (EU)&lt;/li&gt;
&lt;li&gt;Analytics: self-hosted Plausible on Hetzner (Nuremberg)&lt;/li&gt;
&lt;li&gt;API: Hetzner VPS, Node&lt;/li&gt;
&lt;li&gt;Build: Astro, deployed via Bunny CLI&lt;/li&gt;
&lt;li&gt;No cookies, no third-party JS, no CDN outside EU&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building something similar, happy to discuss the specifics in the comments. &lt;/p&gt;

&lt;p&gt;Also, if you think a product is missing on the site, use the "suggest" button, I'm implementing products on a weekly base. &lt;/p&gt;

&lt;p&gt;Feel free to connect on X.&lt;/p&gt;

&lt;p&gt;Cheers,&lt;/p&gt;

&lt;p&gt;Manuel&lt;/p&gt;

&lt;p&gt;PS:&lt;br&gt;
I used AI to spellcheck and sharpen my tone, I hope that's OK here.&lt;/p&gt;

</description>
      <category>astro</category>
      <category>webdev</category>
      <category>privacy</category>
      <category>marketing</category>
    </item>
  </channel>
</rss>
