ProxDocs

Building a web proxy

This is documentation for building an interception-based web proxy with Scramjet. Plus a generator that hands you a working project configured the way you want it.

It fills the gap between short setup READMEs and reading every upstream package.

Two ways to use this:

You want a working proxy now. Go to Quickstart, or open the builder at /build after starting this repository. The downloaded project README gives the commands for your selected package manager.

You want to understand the stack. Start with How a proxy works and read the Concepts section in order. It builds up from the two jobs a proxy performs to why the current architecture looks the way it does.


The one thing to understand first

A proxy has two independent jobs, and nearly every confusing question comes from conflating them:

  1. Fetching bytes from a server the browser will not let you reach directly.
  2. Rewriting those bytes so every URL, script, and cookie inside them points back through the proxy.

Wisp, Bare, epoxy, and libcurl solve problem 1.

Scramjet solves problem 2. It is the engine.

They are chosen independently. "Should I use Scramjet or wisp?" is not a question. You use Scramjet over wisp.


What to read

Concepts

PageWhat it answers
How a proxy worksThe four layers, and one request traced end to end
Proxy enginesWhat the rewriter does, and why this site documents Scramjet
Wisp vs BareThe two tunnel protocols, and why wisp won
Transportsepoxy, libcurl, bare. What they are and how to choose
bare-mux and proxy-transportsWhat bare-mux is, and what replaced it
Cross-origin isolationWhy Scramjet needs COOP/COEP and what breaks without them

Guides

PageWhat you build
QuickstartA working proxy in about two minutes
Multiple tabsReal tabs that keep their pages alive
SettingsValidated, persisted settings that cannot brick your app
URL parsing and historyAn address bar that behaves like a browser's
Custom protocolsInternal pages on your own scheme
Cookies and sessionsWhere logins live, and the three ways they break
Search enginesWhich ones survive a proxy, and which only work in dev
Wiring ScramjetServing the engine, its service worker, and Wisp
Serverless deploymentAn all-in-one deployment over Bare, and what it costs
Framework integrationsReact, Astro, Fastify, Vite, Next.js, SvelteKit, Bun
DeploymentHosting, HTTPS, and platform limits
Running a proxyBandwidth, blocking, abuse, and logging, after launch
Practices worth knowingShared storage, performance, accessibility

Reference

PageWhat it answers
Config and flagsEvery Scramjet option, what it does, what breaks
Plugins and hooksThe extension surface, and how to write against it
Site compatibilityWhy a given site fails, and whether you can fix it

Version matrix · Breaking changes · Troubleshooting · Official docs and licensing · Glossary


The builder

The builder at /build composes a project from parts. Every part is a real file in builder/parts/, readable on its own. The generator only strips the blocks you did not ask for and fills in a few names.

It asks about the stack:

QuestionOptions
LanguageTypeScript or JavaScript
Package managernpm, pnpm, yarn, bun
RuntimeNode or Bun
Server frameworkExpress or Fastify
FrontendVanilla, React, or Astro + Preact
Build stepVite, or none at all
StylingPlain CSS, SCSS, or Tailwind
Transportslibcurl, epoxy, bare, or any mix

It also asks about the features:

  • Browser controls: back, forward, and reload wired to the frame's history
  • Multiple tabs: one proxy session per tab, kept alive in the background
  • Settings: validated and persisted, shown in a popup unless custom protocols are enabled
  • Transport switching: any transport you shipped, at runtime, plus a custom Wisp server
  • History: a visit log, separate from per-tab back and forward
  • Bookmarks and history menus: popup overlays or navigable custom protocol pages
  • Cloaking and custom protocol pages
  • Quiet service worker: silence log, info and debug inside the worker

Choices that cannot work together are greyed out with the reason, rather than letting you pick them and quietly changing them afterwards. Picking an all-in-one serverless host selects the Bare transport, because those hosts cannot hold Wisp's WebSocket open; a static frontend may instead point at Wisp hosted elsewhere. See Serverless deployment.

Or from the terminal:

node builder/cli.js --out ./my-proxy --preset standard

node builder/cli.js --out ./my-proxy \
    --language ts --runtime bun --server express \
    --bundler vite --styling tailwind \
    --features browserControls,tabs,settings,history

Generated projects are structured so that engine.ts is the only file that talks to the proxy engine. Everything else, tabs, settings, history, is written against a small interface, so swapping transports or upgrading the engine does not touch your feature code.

The generated UI is a compact dark interface with a monospace typeface and plain controls. It works on narrow screens and is intended to be easy to edit.


Running this documentation locally

npm install
npm start

The documentation opens at / on the configured port. The guides render from the same Markdown files that GitHub displays; the interactive builder is local-site functionality.


Limits

  • URL codecs are obfuscation, not encryption. The key is in the client bundle.
  • about:blank cloaking hides a URL from someone looking at your screen. It adds no network privacy. What an observer sees depends on whether the proxy uses Wisp or Bare; a managed-browser extension can still inspect the page.
  • Serverless hosting forces the Bare transport, which means your server terminates target TLS and WebSocket sites stop working. It is free to start and fine at small scale, but every proxied byte is billed egress, so it stops adding up as traffic grows. A static frontend pointed at Wisp on a cheap VPS avoids all of it.
  • The published Scramjet docs currently describe the 1.x API while the repository has moved on. Breaking changes tracks the difference.
  • This repository and generated projects use AGPL-3.0-only. See licensing for upstream links and the license notice.

If something here is wrong or out of date, open an issue or a PR.

Questions are best asked in the Night Network Discord, https://discord.gg/algebra, which is also where a lot of this ecosystem gets built.

Profile Views