Skip to content

Add tunnel URL rewrite mu-plugin for ngrok support#2960

Draft
gcsecsey wants to merge 2 commits intotrunkfrom
gcsecsey/ngrok-local-studio
Draft

Add tunnel URL rewrite mu-plugin for ngrok support#2960
gcsecsey wants to merge 2 commits intotrunkfrom
gcsecsey/ngrok-local-studio

Conversation

@gcsecsey
Copy link
Copy Markdown
Contributor

@gcsecsey gcsecsey commented Apr 1, 2026

Related issues

Proposed Changes

When users tunnel a Studio site via ngrok (or cloudflared, localtunnel, etc.), WordPress redirects all requests back to the configured local site URL. This happens because WordPress's siteurl/home options are stored as the local domain, and WordPress core's redirect_canonical() forces all requests to match. Users currently have to manually update WordPress settings — tedious and easy to forget to revert.

This PR adds a new 0-tunnel-url-rewrite.php mu-plugin that dynamically rewrites WordPress URLs when it detects a forwarded request (via the X-Forwarded-Host header), requiring zero configuration from the user.

The mu-plugin:

  1. Detects tunnel requests via X-Forwarded-Host header (set by ngrok, cloudflared, and Studio's own proxy xfwd: true)
  2. Dynamically rewrites siteurl and home using option_home and option_siteurl filters — no database changes
  3. Rewrites asset URLs (content_url, plugins_url, script_loader_src, style_loader_src, rest_url, upload_dir) so all resources load through the tunnel
  4. Selectively suppresses canonical redirect — only when WordPress would redirect away from the tunnel host, preserving legitimate redirects (trailing slashes, pagination, etc.)
  5. Adds the tunnel host to allowed redirect hosts so wp_safe_redirect calls work correctly

The mu-plugin is always-on but only activates when X-Forwarded-Host is present. Normal local browsing is completely unaffected. This is a Proof of Concept — the approach is intentionally minimal (PHP mu-plugin only, no TypeScript/UI/IPC changes).

Testing Instructions

  1. Build CLI: npm run cli:build
  2. Start a site with a custom domain (e.g., mywpsite.local) in Studio
  3. Note the site's localhost port from Studio
  4. Run: ngrok http http://localhost:<port> --host-header=mywpsite.local
  5. Visit the ngrok URL — the site should load with all links pointing to the ngrok URL
  6. Navigate around the site and visit wp-admin — no redirects back to the local domain
  7. Access the site directly via mywpsite.local — should work as before (mu-plugin inactive)
  8. Run tests: npm test -- tools/common/lib/tests/mu-plugins.test.ts

Pre-merge Checklist

  • Changes are limited to the Proof of Concept scope
  • Unit test added for the new mu-plugin
  • No changes to TypeScript server code, IPC, or UI
  • Existing mu-plugin behavior unaffected

Use home_url/site_url filters instead of option_siteurl/option_home,
since the option filters are bypassed when WordPress Playground defines
these as PHP constants.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant