Enhance a proxied site

Proxy an external site through Gate One and inject a userscript into every HTML page.

This example puts Gate One in front of a real external site and injects a userscript into every HTML page. The browser installs no extension and the upstream site contains no Gate One code.

The example is the Wikipedia+ demo, moved from the deprecated gate-one repository. It proxies the language editions of Wikipedia and adds a dark/light toggle and a reading-time badge.

Files

The full example lives in the source repository:

The .user.js file is the canonical, userscript-manager-installable artifact. The .html file is its generated <script> wrapper, used by the injection bundle.

Route

{
  "host": "{lang}.wikipedia.demo.localhost",
  "path": "/*",
  "backend": "https://{lang}.wikipedia.org",
  "frontend": true,
  "upstream": {
    "host": true,
    "rewriteRedirects": true,
    "rewriteBody": { "enabled": true },
    "responseHeaders": {
      "remove": [
        "Content-Security-Policy",
        "Content-Security-Policy-Report-Only"
      ]
    }
  },
  "inject": "injects/bundle.json",
  "wildcard": {
    "lang": ["en", "fr", "de", "ja", "zh", "ru", "es", "it", "pt"]
  }
}

The full file lists 29 language editions. The wildcard expands one route into one public host per language and compiles the cross-edition rewrite map.

  • upstream.host: true sends the origin its own Host header.

  • rewriteRedirects and rewriteBody keep the browser behind Gate One.

  • responseHeaders.remove removes the origin CSP so the injected script can run. Only do this for a trusted origin and trusted injected code.

  • inject points at the bundle; it is relative to routes.json.

  • wildcard.lang is the allow-list of language labels. A label outside this list has no route.

The bundle is deliberately small:

{
  "injects": [{
    "name": "wikipedia-plus",
    "target": "head",
    "order": 30,
    "file": "./wikipedia-plus.html"
  }]
}

The long userscript is not embedded in this page; it lives in the example directory.

target: "head" only says where the <script> tag goes in the document — it is not a DOM selector. The Wikipedia+ script replaces the theme, builds its floating panel and positions the arrow relative to that panel at runtime. Placing content at a specific element is the script’s job; see Placing content at a specific element.

Run it

cd gate-one-src
./bin/gate-one -check -config examples/siteproxy/routes.json
./bin/gate-one -config examples/siteproxy/routes.json

Point the public hosts at the gateway, then open:

http://en.wikipedia.demo.localhost:3000/wiki/Cat

This example needs outbound internet access to *.wikipedia.org.

What to observe

  • the page is served from the real Wikipedia origin, through Gate One;

  • the Wikipedia+ panel appears even though the browser has no extension;

  • interlanguage links move between the proxified editions;

  • the route is public: there is no auth policy.

Warning
CSP removal is a real weakening. Only inject trusted code into a trusted origin; the userscript runs in the page context with the page’s full origin.
Note
  • The userscript must be free-licensed and vetted. The Wikipedia+ script is MIT licensed and carries the original copyright notice.

  • Keep the generated .html in sync with the .user.js; edit the userscript, then regenerate the wrapper.

  • A frontend: true route also carries the Gate One guard; custom bundle entries start at order 30 (the guard is 10, the PWA is 20).

See also