An authenticated, self-hosted browser proxy that loads real interactive web pages through another computer or VPS. It rewrites HTML, JavaScript, requests, cookies, storage, navigation, forms, and WebSockets using Rammerhead and TestCafe Hammerhead.
It is not a screenshot or video stream, does not open a hidden browser on the server, and does not require Docker.
Important
Use this only on systems, accounts, and networks you own or are authorized to access. This is not an anonymity service: websites normally see the public or VPN egress IP of the machine running the proxy.
- A simple login page protected by a private access token.
- A URL/search box followed by real, interactive proxied pages in the same tab.
- Persistent cookies, local storage, cache, navigation, fetch/XHR, forms, and WebSocket support where the destination site permits them.
- Trusted HTTPS on a local network through a generated local root certificate.
- Trusted public HTTPS on a VPS through a standard Caddy or Nginx reverse proxy.
- Private-address destination blocking by default, login rate limiting, secure authentication cookies, and redacted diagnostic logs.
- Windows and Linux support with ordinary Python and Node.js processes.
| Goal | Command | Public entry point | Certificate |
|---|---|---|---|
| Use another device on the same LAN | python proxy_server.py |
Laptop LAN IP on ports 8080/8443 |
Install the generated local CA once |
| Use a public VPS/domain | python proxy_server.py --vps ... |
Your domain on HTTPS port 443 |
Caddy/Nginx obtains a public certificate |
- Python 3.10 or newer
- Node.js 20 or newer, including
npm - A browser on the client device
- For VPS mode: a DNS hostname pointing to the VPS and Caddy or Nginx
git clone https://github.com/Mhrnqaruni/lan-web-proxy.git
cd lan-web-proxy
python -m pip install -r requirements.txt
npm ci --omit=dev --ignore-scriptspython .\proxy_server.pyThe first run prepares the browser-rewriting assets. The terminal then prints:
- the access token;
- the setup address, such as
http://192.168.1.20:8080/; - the secure proxy address, such as
https://192.168.1.20:8443/; - the public certificate path and SHA-256 fingerprint.
- Open the printed
http://LAPTOP-IP:8080/address on the other device. - Download the public root certificate.
- Import it under Trusted Authorities / Certificate Authorities, enable website trust if asked, and compare its fingerprint with the laptop terminal.
- Fully close and reopen the browser.
- Open the printed
https://LAPTOP-IP:8443/address. - Enter the token from the laptop terminal, then enter a URL or search phrase.
The browser cannot silently trust a new certificate. Never copy or install the
private key named lan-proxy-root-ca-key.pem on another device.
If Windows Firewall does not prompt, run PowerShell as Administrator once:
New-NetFirewallRule -DisplayName "LAN Web Proxy" -Direction Inbound -Protocol TCP -LocalPort 8080,8443,8444 -Action Allow -Profile Private -RemoteAddress LocalSubnetSee the detailed LAN guide for Linux and browser-specific certificate instructions.
The safe VPS layout is:
Browser ──HTTPS──> Caddy :443 ──HTTP on loopback──> Proxy :8080 ──HTTPS──> Website
Only Caddy is public. The Python-launched backend stays on 127.0.0.1.
Create an A/AAAA DNS record such as proxy.example.com pointing to your
VPS. Allow inbound TCP ports 80 and 443. Install Python 3.10+, Node.js 20+,
Git, and Caddy.
git clone https://github.com/Mhrnqaruni/lan-web-proxy.git
cd lan-web-proxy
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
npm ci --omit=dev --ignore-scriptsGenerate a private token and save it somewhere secure:
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
export LAN_PROXY_ACCESS_TOKEN='paste-the-generated-token-here'Replace the hostname below with your real DNS name:
python3 proxy_server.py --vps --public-hostname proxy.example.comVPS mode requires a token of at least 16 characters and hides it from service
logs. It listens on 127.0.0.1:8080 by default.
Create /etc/caddy/Caddyfile:
proxy.example.com {
reverse_proxy 127.0.0.1:8080
}Validate and reload Caddy:
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddyOpen https://proxy.example.com/ and enter the token. Caddy obtains and renews
the publicly trusted certificate automatically when DNS is correct and ports
80/443 are reachable. No local CA installation is used in VPS mode.
For automatic startup, service hardening, updates, and Nginx configuration, use the complete VPS deployment guide.
--vps Run behind an HTTPS reverse proxy
--public-hostname HOST Required public DNS hostname in VPS mode
--public-port PORT External HTTPS port (default: 443)
--host ADDRESS Bind address (LAN: 0.0.0.0, VPS: 127.0.0.1)
--port PORT LAN setup page or VPS backend (default: 8080)
--tls-port PORT LAN HTTPS proxy (default: 8443)
--cross-port PORT Internal cross-domain listener (default: main + 1)
--access-token TOKEN Login token; VPS can use LAN_PROXY_ACCESS_TOKEN instead
Examples:
# LAN with a stable token and custom ports
python .\proxy_server.py --access-token "a-long-private-token" --port 8090 --tls-port 9443 --cross-port 9444# VPS with a nonstandard public HTTPS port
LAN_PROXY_ACCESS_TOKEN='a-very-long-private-token' python3 proxy_server.py \
--vps --public-hostname proxy.example.com --public-port 8443Runtime state is stored under .proxy_data/ and excluded from Git. It contains
site cookies/storage, session identifiers, generated certificates, private
keys, and redacted JSONL diagnostics. Treat the whole directory as sensitive.
Each run prints its diagnostic-log path. Logs include request paths and status codes for selected compatibility failures, TLS errors, browser console errors, and capability information. They exclude cookies, request bodies, passwords, and URL query values. Review a log before sharing it.
To reset all browsing sessions, stop the proxy and move .proxy_data/ to a
private backup. In LAN mode this also creates a new root CA, which must then be
installed again on client devices.
This project handles many modern sites, including the compression and secure- context behavior needed by large JavaScript applications. However, no URL- rewriting proxy can perfectly reproduce every origin-bound browser feature. Passkeys/WebAuthn, DRM media, some OAuth or anti-bot flows, nested service workers, WebRTC, and sites that explicitly reject rewritten origins may fail.
Do not report a site merely blocking a proxy as a security vulnerability. For reproducible application failures, include the browser/version, destination hostname, exact error, and a redacted diagnostic log in a bug report.
python -m pip install -r requirements.txt
npm ci --ignore-scripts
npm run prepare-engine
python -m unittest discover -s tests -v
python -m py_compile proxy_server.py
npm run checkThe dependency install uses a lockfile. prepare_engine.js applies the small,
deterministic Rammerhead compatibility patches and rebuilds its client assets
from the exact installed Hammerhead version. vendor/ip is a deliberately
minimal toBuffer() compatibility shim for Rammerhead's unused clustering
dependency; it replaces an upstream package with no patched release for
GHSA-2p57-rm9w-gvfp.
Read SECURITY.md before exposing the application publicly. Keep the backend loopback-only in VPS mode, use a unique random token, run under an unprivileged account, update dependencies regularly, and never commit runtime data or secrets.
This repository is available under the MIT License. It builds on the MIT-licensed Rammerhead and TestCafe Hammerhead projects; their respective copyrights remain with their authors.