<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[anandsuthar]]></title><description><![CDATA[anandsuthar]]></description><link>https://blog.anandsuthar.dev</link><generator>RSS for Node</generator><lastBuildDate>Sun, 10 May 2026 01:12:32 GMT</lastBuildDate><atom:link href="https://blog.anandsuthar.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Why Reverse Proxy Failed with Vercel + Cloudflare Workers - and How Nginx Fixes It]]></title><description><![CDATA[The Goal
I wanted this setup:
https://anandsuthar.dev        → Main website (Next.js)
https://anandsuthar.dev/blog   → Hashnode blog

Instead of:
blog.anandsuthar.dev

The goal was a clean URL, better branding, and shared SEO authority.
What I Tried ...]]></description><link>https://blog.anandsuthar.dev/why-reverse-proxy-failed-with-vercel-cloudflare-workers-and-how-nginx-fixes-it</link><guid isPermaLink="true">https://blog.anandsuthar.dev/why-reverse-proxy-failed-with-vercel-cloudflare-workers-and-how-nginx-fixes-it</guid><dc:creator><![CDATA[anand suthar]]></dc:creator><pubDate>Sun, 11 Jan 2026 18:30:00 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-the-goal">The Goal</h2>
<p>I wanted this setup:</p>
<pre><code class="lang-plaintext">https://anandsuthar.dev        → Main website (Next.js)
https://anandsuthar.dev/blog   → Hashnode blog
</code></pre>
<p>Instead of:</p>
<pre><code class="lang-plaintext">blog.anandsuthar.dev
</code></pre>
<p>The goal was a <strong>clean URL</strong>, better branding, and shared SEO authority.</p>
<h2 id="heading-what-i-tried-and-why-it-failed">What I Tried (and Why It Failed)</h2>
<h3 id="heading-1-nextjs-rewrites-vercel">1. Next.js Rewrites (Vercel)</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> rewrites() {
  <span class="hljs-keyword">return</span> [
    {
      <span class="hljs-attr">source</span>: <span class="hljs-string">'/blog/:path*'</span>,
      <span class="hljs-attr">destination</span>: <span class="hljs-string">'https://blog.anandsuthar.dev/:path*'</span>,
    },
  ];
}
</code></pre>
<p>❌ <strong>Did not work</strong></p>
<p>Why:</p>
<ul>
<li><p>Next.js rewrites are <strong>not a true reverse proxy</strong></p>
</li>
<li><p>Browser still makes cross-origin requests</p>
</li>
<li><p>Hashnode/Vercel security kicks in</p>
</li>
</ul>
<h3 id="heading-2-cloudflare-workers-as-reverse-proxy">2. Cloudflare Workers as Reverse Proxy</h3>
<p>Worker logic:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-keyword">async</span> fetch(request) {
    <span class="hljs-keyword">return</span> fetch(<span class="hljs-string">"https://blog.anandsuthar.dev"</span>);
  }
};
</code></pre>
<p>result:</p>
<pre><code class="lang-swift"><span class="hljs-number">429</span> <span class="hljs-type">Too</span> <span class="hljs-type">Many</span> <span class="hljs-type">Requests</span>
/.well-known/vercel/security/request-challenge
</code></pre>
<p>❌ <strong>Blocked</strong></p>
<h3 id="heading-3-why-worker-hit-worked-important-insight">3. Why “WORKER HIT” Worked (Important Insight)</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-keyword">async</span> fetch() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(<span class="hljs-string">"WORKER HIT"</span>);
  },
};
</code></pre>
<p>✅ This worked because:</p>
<pre><code class="lang-nginx"><span class="hljs-attribute">Browser</span> → Cloudflare Worker → Response
</code></pre>
<p><strong>Vercel was never involved</strong></p>
<p>The moment the Worker tried to <strong>fetch Vercel/Hashnode</strong>, security kicked in.</p>
<h2 id="heading-the-real-reason-it-fails">The Real Reason It Fails</h2>
<h3 id="heading-vercel-security-model">Vercel Security Model</h3>
<p>Vercel:</p>
<ul>
<li><p>Detects <strong>edge proxies</strong></p>
</li>
<li><p>Detects <strong>non-browser requests</strong></p>
</li>
<li><p>Injects <strong>JavaScript challenges</strong></p>
</li>
<li><p>Requires <strong>real browser execution</strong></p>
</li>
</ul>
<p>Cloudflare Workers:</p>
<ul>
<li><p>Are server-side</p>
</li>
<li><p>Cannot execute JS challenges</p>
</li>
<li><p>Cannot solve bot protection</p>
</li>
<li><p>Are detected instantly</p>
</li>
</ul>
<p><strong>You do not have full control on Vercel. This is intentional.</strong></p>
<h2 id="heading-the-only-place-reverse-proxy-truly-works">The Only Place Reverse Proxy Truly Works</h2>
<h3 id="heading-self-hosted-linux-nginx">Self-Hosted Linux + Nginx</h3>
<p>Why?</p>
<ul>
<li><p>Nginx operates at the <strong>network level</strong></p>
</li>
<li><p>No JS challenges</p>
</li>
<li><p>No bot detection</p>
</li>
<li><p>Full header, cookie, and TLS control</p>
</li>
<li><p>Looks like a <strong>real origin server</strong></p>
</li>
</ul>
<h3 id="heading-final-working-architecture-recommended">Final Working Architecture (Recommended)</h3>
<pre><code class="lang-java">Internet
  ↓
<span class="hljs-function">Cloudflare <span class="hljs-title">DNS</span> <span class="hljs-params">(optional)</span>
  ↓
DigitalOcean <span class="hljs-title">Droplet</span> <span class="hljs-params">(Ubuntu)</span>
  ↓
Nginx
  ├── /        → Next.js app
  └── /blog    → Hashnode</span>
</code></pre>
<h2 id="heading-step-by-step-working-solution-digitalocean-nginx">Step-by-Step Working Solution (DigitalOcean + Nginx)</h2>
<h3 id="heading-1-create-a-droplet">1. Create a Droplet</h3>
<ul>
<li><p>Ubuntu 22.04</p>
</li>
<li><p>Open ports: 80, 443</p>
</li>
</ul>
<h3 id="heading-2-install-nginx">2. Install Nginx</h3>
<pre><code class="lang-bash">sudo apt update
sudo apt install nginx -y
</code></pre>
<h3 id="heading-3-install-ssl-lets-encrypt">3. Install SSL (Let’s Encrypt)</h3>
<pre><code class="lang-bash">sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d anandsuthar.dev -d www.anandsuthar.dev
</code></pre>
<h3 id="heading-4-nginx-reverse-proxy-configuration">4. Nginx Reverse Proxy Configuration</h3>
<p>Edit:</p>
<pre><code class="lang-bash">sudo nano /etc/nginx/sites-available/anandsuthar.dev
</code></pre>
<pre><code class="lang-nginx"><span class="hljs-section">server</span> {
    <span class="hljs-attribute">listen</span> <span class="hljs-number">443</span> ssl;
    <span class="hljs-attribute">server_name</span> anandsuthar.dev www.anandsuthar.dev;

    <span class="hljs-attribute">ssl_certificate</span> /etc/letsencrypt/live/anandsuthar.dev/fullchain.pem;
    <span class="hljs-attribute">ssl_certificate_key</span> /etc/letsencrypt/live/anandsuthar.dev/privkey.pem;

    <span class="hljs-comment"># MAIN WEBSITE (Next.js)</span>
    <span class="hljs-attribute">location</span> / {
        <span class="hljs-attribute">proxy_pass</span> http://localhost:3000;
        <span class="hljs-attribute">proxy_http_version</span> <span class="hljs-number">1</span>.<span class="hljs-number">1</span>;

        <span class="hljs-attribute">proxy_set_header</span> Host <span class="hljs-variable">$host</span>;
        <span class="hljs-attribute">proxy_set_header</span> X-Real-IP <span class="hljs-variable">$remote_addr</span>;
        <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-For <span class="hljs-variable">$proxy_add_x_forwarded_for</span>;
        <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-Proto <span class="hljs-variable">$scheme</span>;

        <span class="hljs-attribute">proxy_set_header</span> Upgrade <span class="hljs-variable">$http_upgrade</span>;
        <span class="hljs-attribute">proxy_set_header</span> Connection <span class="hljs-string">"upgrade"</span>;
    }

    <span class="hljs-comment"># BLOG → HASHNODE (THIS IS THE MAGIC)</span>
    <span class="hljs-attribute">location</span> /blog/ {
        <span class="hljs-attribute">proxy_pass</span> https://blog.anandsuthar.dev/;

        <span class="hljs-attribute">proxy_set_header</span> Host blog.anandsuthar.dev;
        <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-For <span class="hljs-variable">$remote_addr</span>;
        <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-Proto https;

        <span class="hljs-attribute">proxy_ssl_server_name</span> <span class="hljs-literal">on</span>;

        <span class="hljs-attribute">proxy_redirect</span> https://blog.anandsuthar.dev/ /blog/;
    }
}
</code></pre>
<p>Enable site:</p>
<pre><code class="lang-bash">sudo ln -s /etc/nginx/sites-available/anandsuthar.dev /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
</code></pre>
<h3 id="heading-result">Result</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td>Works</td></tr>
</thead>
<tbody>
<tr>
<td><a target="_blank" href="http://anandsuthar.dev"><code>anandsuthar.dev</code></a></td><td>✅ Next.js</td></tr>
<tr>
<td><a target="_blank" href="http://anandsuthar.dev/blog"><code>anandsuthar.dev/blog</code></a></td><td>✅ Hashnode</td></tr>
<tr>
<td>JS / CSS / Images</td><td>✅</td></tr>
<tr>
<td>SEO</td><td>✅</td></tr>
<tr>
<td>Cookies</td><td>✅</td></tr>
<tr>
<td>No 429 / No challenge</td><td>✅</td></tr>
</tbody>
</table>
</div><h2 id="heading-why-this-works-final-explanation">Why This Works (Final Explanation)</h2>
<ul>
<li><p>Nginx runs <strong>before the browser</strong></p>
</li>
<li><p>Hashnode sees a <strong>real origin</strong></p>
</li>
<li><p>No bot detection</p>
</li>
<li><p>No edge fingerprint</p>
</li>
<li><p>Full HTTP control</p>
</li>
</ul>
<p>This is <strong>impossible</strong> on:</p>
<ul>
<li><p>Vercel</p>
</li>
<li><p>Cloudflare Workers</p>
</li>
<li><p>Netlify</p>
</li>
<li><p>Any managed edge platform</p>
</li>
</ul>
<hr />
<h2 id="heading-final-takeaway">Final Takeaway</h2>
<blockquote>
<p><strong>If you need reverse proxy, you need server control.</strong></p>
</blockquote>
<ul>
<li><p>Vercel = convenience, not control</p>
</li>
<li><p>Workers = compute, not browsers</p>
</li>
<li><p>Nginx = absolute control</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Setting up a subdirectory for Hashnode]]></title><description><![CDATA[This is a testing blog for setting up a subdirectory without going headless]]></description><link>https://blog.anandsuthar.dev/setting-up-a-subdirectory-for-hashnode</link><guid isPermaLink="true">https://blog.anandsuthar.dev/setting-up-a-subdirectory-for-hashnode</guid><dc:creator><![CDATA[anand suthar]]></dc:creator><pubDate>Wed, 07 Jan 2026 13:54:04 GMT</pubDate><content:encoded><![CDATA[<p>This is a testing blog for setting up a subdirectory without going headless</p>
]]></content:encoded></item></channel></rss>