Akhil Raj

Akhil Raj / "Stop Exposing Supabase URLs: Fix DNS & ISP Issues the Right Way"

Software Engineer

All posts

"Stop Exposing Supabase URLs: Fix DNS & ISP Issues the Right Way"

Why owning your API domain eliminates timeout errors and improves reliability

You can also read this on Medium.

"Stop Exposing Supabase URLs: Fix DNS & ISP Issues the Right Way"

If your users are suddenly unable to log in to your app, you're probably panicking a little.

Auth requests are timing out. API calls never complete. Users see ERR_CONNECTION_TIMED_OUT or TypeError: fetch failed.

Recently, Supabase acknowledged a connectivity issue affecting some users due to ISP-level routing/DNS problems even though their infrastructure itself is healthy. (You can see their update here: status.supabase.com)

That means your backend may be completely fine but certain networks or regions simply can't reliably reach *.supabase.co.

And no, telling users to "just use a VPN" is not a real solution. It's not scalable. It's not professional. And it's definitely not good UX.

So the real fix is to stop exposing a vendor hostname directly to your users.

What makes this issue so frustrating is that:

  • Everything works in development
  • Everything works for most users, just not all
  • Everything works over VPN
  • There are no clear error logs

It feels random. It feels like your code is broken.
But it's actually a network routing and DNS issue between user ISPs and Supabase. The fix isn't in your code; it's in your architecture.

The Correct Fix: Put Supabase Behind Your Own API Domain

Instead of this architecture:

Browser → https://your-project.supabase.co

Use this:

Browser → https://api.yourdomain.com
Cloudflare Worker → https://your-project.supabase.co

Now your users never touch Supabase's domain. They connect to your domain, which Cloudflare, with its global reliable network, resolves and proxies to Supabase. Cloudflare's network is far more reliably reachable across ISPs worldwide. No more random failures. No more "works on my network" bugs.

In fact, this is how production-grade systems are typically designed. You own your API surface. You can swap vendors later without touching frontend code. You get Cloudflare's edge performance for free.

Step-By-Step Guide: Cloudflare Worker Reverse Proxy Setup

0. Prerequisites

  • A Cloudflare account with your domain added.
  • Your Supabase project URL: https://your-project.supabase.co
  • Your app currently creates Supabase client with something like:
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key

You won't change any code except this env value for production.

1. Create a new Worker to proxy all Supabase traffic

  1. Go to dash.cloudflare.com → left sidebar "Workers & Pages".
  2. Click "Create application" → "Create Worker".
  3. Name it, e.g. supabase-api-proxy.
  4. In the editor, delete the default code and paste:
export default {
  async fetch(request, env) {
    const url = new URL(request.url);

    // Your real Supabase project URL
    const SUPABASE_URL = "https://your-project.supabase.co";

    // Keep same path + query
    const targetURL = SUPABASE_URL + url.pathname + url.search;

    const modifiedRequest = new Request(targetURL, {
      method: request.method,
      headers: request.headers,
      body:
        request.method === "GET" || request.method === "HEAD"
          ? null
          : request.body,
      redirect: "follow",
    });

    // Just proxy Supabase's response back
    return fetch(modifiedRequest);
  },
};

Click "Save and Deploy" (top right).

You now have a Worker that, for any path it receives, forwards the same path to Supabase.

2. Add DNS records for api.yourdomain.com

These are added inside Cloudflare DNS for your domain, not in code.

  1. In Cloudflare dashboard, click your domain.
  2. In left sidebar, click "DNS" → "Records".
  3. Click "Add record".

Add A record:

  • Type: A
  • Name: api
  • (Cloudflare will display api.yourdomain.com)
  • IPv4 address: 192.0.2.1 (dummy address)
  • Proxy status: set to Proxied (orange cloud ON)
  • TTL: Auto
  • Click Save.

Add AAAA record:

  • Type: AAAA
  • Name: api
  • IPv6 address: 100:: (dummy address)
  • Proxy status: Proxied (orange cloud ON)
  • TTL: Auto
  • Click Save.

Now Cloudflare can terminate traffic for api.yourdomain.com and run a Worker on it. These records are fully reversible: to undo, you just delete them later.

3. Attach the Worker to api.yourdomain.com/*

  1. Go back to "Workers & Pages", click your new Worker supabase-api-proxy.
  2. Go to the "Settings" tab.
  3. Scroll to "Triggers" → "Routes".
  4. Click "Add Route".
  5. Fill:
    • Route: api.yourdomain.com/*
    • Zone: choose yourdomain.com
    • Worker: supabase-api-proxy
  6. Save

4. Update your environment variables

You want:

  • Local dev: talk directly to Supabase (easier debugging).
  • Production: go through api.yourdomain.com (bypasses ISP routing issues globally).

Dev (.env.local or local env)

NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key

Production (Vercel / hosting dashboard env vars)

NEXT_PUBLIC_SUPABASE_URL=https://api.yourdomain.com
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key

You do not need to touch the Supabase client code if it already uses these env vars, for example:

import { createClient } from "@supabase/supabase-js";
export const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
  • In prod, that becomes https://api.yourdomain.com.
  • SDK will internally call https://api.yourdomain.com/auth/..., /rest/v1/…, etc., and your Worker forwards to Supabase.

5. Verify everything

Wait 5–30 minutes for DNS/route to propagate.

In your browser, go to: https://api.yourdomain.com/rest/v1/

You should see a Supabase‑style JSON error (e.g. "Not found" or PostgREST error). That means the Worker is correctly hitting Supabase.

  1. Deploy your app with the production env set to https://api.yourdomain.com
  2. Test from different networks (WiFi, mobile data, or any network where issues were previously observed)

If the app works from those problem networks, the Cloudflare proxy is doing its job.

What This Solves

  • Supabase timeout issues
  • Supabase auth not working
  • Supabase works on VPN but not mobile data
  • ERR_CONNECTION_TIMED_OUT Supabase
  • TypeError: fetch failed with no backend errors
  • DNS resolution issues for Supabase
  • ISP routing issues

Why This Is Better Architecture Anyway

Even if ISP routing was never a problem for you, this is best practice. You own your API surface. Your frontend talks to api.yourdomain.com and not a vendor hostname. That way, you can switch providers later without changing your frontend. For example, if you move from Supabase to another service, your frontend remains unchanged.

Key Takeaway

This kind of issue isn't unique to Supabase, and it can happen with any third-party API exposed directly to users. If your app works everywhere except certain networks, fixes itself the moment users turn on a VPN, and shows auth timeouts with zero backend logs, nothing in your code needs fixing. You were never the problem.

The professional answer is not "tell your users to use a VPN." It's owning your API domain and routing through a resilient edge layer so your users never depend on a vendor's DNS to reach your app.

If you're building SaaS on raw vendor URLs in production, this is the moment to change that. It's a 20-minute fix that makes your infrastructure quietly bulletproof and the day it saves you from hours of debugging or lost users, you'll be glad it was already there.