<?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: Darshan Gada 👨‍💻</title>
    <description>The latest articles on DEV Community by Darshan Gada 👨‍💻 (@dr5hn).</description>
    <link>https://dev.to/dr5hn</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%2F358926%2F28aaa57c-5d11-44e8-b250-c41b93efe8d2.jpeg</url>
      <title>DEV Community: Darshan Gada 👨‍💻</title>
      <link>https://dev.to/dr5hn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dr5hn"/>
    <language>en</language>
    <item>
      <title>How I built static hosting that Claude can publish to (via MCP)</title>
      <dc:creator>Darshan Gada 👨‍💻</dc:creator>
      <pubDate>Sat, 27 Jun 2026 12:06:24 +0000</pubDate>
      <link>https://dev.to/dr5hn/how-i-built-static-hosting-that-claude-can-publish-to-via-mcp-14ee</link>
      <guid>https://dev.to/dr5hn/how-i-built-static-hosting-that-claude-can-publish-to-via-mcp-14ee</guid>
      <description>&lt;p&gt;I watched a friend generate a genuinely nice portfolio in Claude in about ten minutes. Then the momentum vanished: "wait, how do I actually host this?" We spent longer arguing about Vercel vs Netlify and DNS than it took to build the site. Minutes to create, an afternoon to deploy — that asymmetry is the whole reason this exists.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://www.makemysitelive.com" rel="noopener noreferrer"&gt;MakeMySiteLive&lt;/a&gt;: you upload a ZIP (or paste a single HTML file), and you get a live HTTPS URL. No repo, no build step, no server. Here's how it's put together and the parts that were more annoying than I expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shape of it
&lt;/h2&gt;

&lt;p&gt;Three pieces with a hard trust boundary between them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Web (Next.js)&lt;/strong&gt; — dashboard + marketing. It's a BFF: no database access, no business logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Control plane (Fastify + Postgres/Prisma)&lt;/strong&gt; — all business logic, the only thing that touches the DB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Site-server&lt;/strong&gt; — serves the actual published sites. Holds &lt;strong&gt;no local state&lt;/strong&gt;, so it scales horizontally.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last property was a deliberate constraint, and it shaped everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stateless serving
&lt;/h2&gt;

&lt;p&gt;The site-server can run on any number of nodes, and any node can serve any site. Files live in Cloudflare R2; password-gate sessions live in Redis; nothing is on local disk. Resolving a request is just: map the &lt;code&gt;Host&lt;/code&gt; header to a site (cached in Redis on a short TTL), then stream the file from R2.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;              &lt;span class="c1"&gt;// Redis cache, 300s TTL&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;folderPath&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// R2&lt;/span&gt;
&lt;span class="c1"&gt;// SPA fallback to index.html, branding badge injected for free-tier sites&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The payoff: deploys are immutable versioned writes, and a rollback is just flipping which version is "active" in one transaction — no files move.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom domains + automatic TLS
&lt;/h2&gt;

&lt;p&gt;This was the real time sink. Customers point a CNAME at us and HTTPS "just works," including cert issuance and renewal. That's &lt;a href="https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/" rel="noopener noreferrer"&gt;Cloudflare for SaaS custom hostnames&lt;/a&gt; doing the heavy lifting — you register the hostname via their API, then poll for SSL status. Making that flow reliable took longer than the entire upload pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Single-file "microsites"
&lt;/h2&gt;

&lt;p&gt;Plenty of people don't have a ZIP — they have one HTML file. So microsites: paste/upload a single &lt;code&gt;.html&lt;/code&gt;, get a live page. These store the HTML &lt;strong&gt;inline&lt;/strong&gt; on the version row and serve it directly, no R2 round-trip.&lt;/p&gt;

&lt;p&gt;The interesting decision: I originally gave microsites the same version history + rollback as full sites. Shipped it, then tore it out. For a one-off landing page, "v1 / v2 / roll back" is just noise — so now a republish simply overwrites the single version. Less surface, less confusion. A good reminder that "consistent with the rest of the system" isn't always the right call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Letting an AI agent deploy
&lt;/h2&gt;

&lt;p&gt;Since AI usually &lt;em&gt;generated&lt;/em&gt; the page, making someone copy it into a dashboard felt backwards. So there's a hosted MCP (Model Context Protocol) server — an agent like Claude connects once (OAuth, scoped to your account) and gets tools to create and deploy sites from the chat.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;reg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;create_microsite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Create and publish a microsite from one standalone HTML string.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;subdomain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createAndDeployMicrosite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Publish this as a site" → live URL, no dashboard. If you want the setup details, I wrote it up here: &lt;a href="https://www.makemysitelive.com/guides/deploy-website-with-ai-mcp" rel="noopener noreferrer"&gt;connecting the MCP server to Claude&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hosting arbitrary HTML is a phishing magnet
&lt;/h2&gt;

&lt;p&gt;This is the part you can't hand-wave. Free subdomains + arbitrary user HTML is exactly what abuse loves. So every upload runs through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Unzip   → require index.html at root, reject "../" path traversal, strip macOS cruft
2. Scan    → ClamAV over TCP + blocked extensions + phishing/eval heuristics
3. Publish → write a new immutable version, flip "active" in one transaction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's not perfect, but "instant and frictionless" can't mean "open relay for phishing kits," so this layer has to be real from day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd tell past-me
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Decide the &lt;strong&gt;statelessness&lt;/strong&gt; constraint up front. Retrofitting "no local state" is miserable; designing for it is free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't mirror your own abstractions reflexively&lt;/strong&gt; — microsites didn't need full versioning just because full sites had it.&lt;/li&gt;
&lt;li&gt;For a solo dev selling worldwide, offload tax/VAT/GST to a merchant of record early. I used one and it saved me a category of work I had zero interest in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to poke at it, the first site is free, no card: &lt;strong&gt;&lt;a href="https://www.makemysitelive.com" rel="noopener noreferrer"&gt;makemysitelive.com&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Question I'm genuinely chewing on: for static hosting like this, is per-site/usage pricing better than a flat monthly subscription? Subscription is cleaner MRR, but per-site feels more honest for someone who just wants one page online. Curious how others have landed on this.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
