Step 6 of 6

Deploy the Worker

With routing, rewrites, headers, and redirects in place, deploying is mostly configuration: a wrangler.toml, a custom domain, and a robots.txt strategy.

Scaffold the Worker

Use the wrangler-init script you set up — it loads Node 24 via nvm and runs wrangler init:

wrangler-init my-reverse-proxy

# Pick: "Hello World" Worker → JavaScript → no git → no deploy yet.

wrangler.toml

name = "reverse-proxy"
main = "src/index.js"
compatibility_date = "2025-05-01"

# Bind the Worker to your canonical host. The zone must be on Cloudflare.
[[routes]]
pattern = "www.example.com/*"
zone_name = "example.com"

# Optional: a workers.dev URL for staging.
workers_dev = true

The full Worker, in one file

// src/index.js
const CANONICAL = 'www.example.com';
const PRIMARY   = 'brand.webflow.io';
const SECONDARY = 'legacy.example.com';

const RULES = [
  { prefix: '/blog', to: SECONDARY },
  { prefix: '/shop', to: SECONDARY },
  { prefix: '/',     to: PRIMARY   },
];

export default {
  async fetch(request) {
    const url = new URL(request.url);

    // 1. Enforce canonical scheme + host
    if (url.protocol === 'http:') {
      url.protocol = 'https:';
      return Response.redirect(url.toString(), 301);
    }
    if (url.hostname !== CANONICAL) {
      url.hostname = CANONICAL;
      return Response.redirect(url.toString(), 301);
    }

    // 2. Pick origin by path
    const rule = RULES.find(r =>
      url.pathname === r.prefix ||
      url.pathname.startsWith(r.prefix === '/' ? '/' : r.prefix + '/')
    );
    if (!rule) return new Response('Not Found', { status: 404 });

    // 3. Fetch upstream
    const upstreamUrl = `https://${rule.to}${url.pathname}${url.search}`;
    const upstream = await fetch(upstreamUrl, request);

    // 4. Rewrite canonical/og:url/hreflang back to the canonical host
    return new HTMLRewriter()
      .on('link[rel="canonical"], link[rel="alternate"]', {
        element(el) {
          const href = el.getAttribute('href');
          if (href) el.setAttribute('href', href.replace(rule.to, CANONICAL));
        },
      })
      .on('meta[property^="og:"]', {
        element(el) {
          const v = el.getAttribute('content');
          if (v && v.includes(rule.to)) el.setAttribute('content', v.replace(rule.to, CANONICAL));
        },
      })
      .transform(upstream);
  },
};

Custom domain

  1. In the Cloudflare dashboard, open the Worker → TriggersCustom Domains.
  2. Add www.example.com. Cloudflare creates the DNS record automatically.
  3. Remove any existing A/CNAME records for www.example.com that point at an origin — the Worker now owns that hostname.

robots.txt

Decide where robots.txt and sitemap.xml come from. Usually the primary origin's. Add an explicit rule so neither path is rewritten through the secondary:

// before the path rules
if (url.pathname === '/robots.txt' || url.pathname === '/sitemap.xml') {
  return fetch(`https://${PRIMARY}${url.pathname}`);
}

Ship it

npx wrangler deploy

# tail logs from production:
npx wrangler tail
That's the whole proxy. Iterate by adding rules, watching wrangler tail, and checking that view-source: on your canonical host never shows an origin URL.

Where to go next