Skip to content

artebels/local-domain-proxy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 

Repository files navigation

local-domain-proxy

English

Local reverse proxy for mapping external websites to a local domain or IP while rewriting requests and responses back and forth.

Features:

  • accepts requests on a local IP/port or local domain;
  • maps them to an external hostname and port;
  • rewrites domains and ports back to local values in response headers;
  • rewrites external domains inside HTML, JS, CSS, JSON, SVG, XML, and other textual responses;
  • supports subdomains with rules like api.example.com -> api.local.test;
  • works without editing /etc/hosts by using wildcard DNS names like 192.168.1.91.sslip.io;
  • softens CORS for local debugging by handling OPTIONS preflight, reflecting the local Origin, and rewriting Origin/Referer back to the upstream domain;
  • preserves text encodings including utf-8, latin1, and windows-1251;
  • supports local HTTPS with its own CA and per-host certificates;
  • proxies WebSocket upgrade requests using the same host-mapping rules.

Run

cd /path/to/local-domain-proxy
TARGET_ORIGIN=https://example.com LISTEN_PORT=8080 npm start

CLI version:

cd /path/to/local-domain-proxy
node src/index.js --target https://example.com --port 8080

Minimal CLI version with defaults:

cd /path/to/local-domain-proxy
node src/index.js --target https://example.com

HTTPS mode:

cd /path/to/local-domain-proxy
TARGET_ORIGIN=https://example.com HTTPS_ENABLED=1 HTTPS_PORT=8443 PUBLIC_PORT=8443 npm start

CLI version:

cd /path/to/local-domain-proxy
node src/index.js --target https://example.com --https --https-port 8443 --public-port 8443

Minimal HTTPS CLI version with defaults:

cd /path/to/local-domain-proxy
node src/index.js --target https://example.com --https

Use Burp for outgoing traffic:

cd /path/to/local-domain-proxy
node src/index.js --target https://example.com --https --burp-proxy 127.0.0.1:8080

The short --burp-proxy flag automatically expands to:

  • --upstream-proxy http://127.0.0.1:8080
  • --insecure-upstream-tls

If you want to use a generic upstream HTTP proxy without automatically disabling TLS verification, use --upstream-proxy.

If you want Burp to see the local request before host rewriting, add:

cd /path/to/local-domain-proxy
node src/index.js --target https://example.com --https --burp-proxy 127.0.0.1:8080 --burp-before-rewrite

In this mode, the proxy first sends the local URL through Burp, then routes the request back into the reverse proxy for rewriting and upstream delivery. Burp will therefore show the local target instead of the original domain.

The second pass after Burp is marked as an internal re-entry and is not sent through Burp again, so you do not get duplicate "before" and "after" entries in Burp history.

This is useful when you want Burp to see the local Host, local URL, and local HTTPS session before the reverse proxy rewrites the request to the external origin.

If LOCAL_DOMAIN is not set, the proxy automatically uses:

  • 192.168.1.91.sslip.io if PUBLIC_HOST looks like an IPv4 address;
  • otherwise PUBLIC_HOST itself.

If PUBLIC_HOST is not set, the proxy auto-detects the first suitable external IPv4 and prefers private LAN addresses such as 192.168.x.x or 10.x.x.x.

Configuration

Environment variables:

  • TARGET_ORIGIN - upstream origin, for example https://example.com or https://example.com:8443
  • LOCAL_DOMAIN - local rewrite domain, for example local.test; if unset it is built automatically from PUBLIC_HOST
  • TARGET_CONNECT_HOST - optional real TCP host to connect to if the logical upstream domain should not or cannot be resolved directly
  • TARGET_CONNECT_PORT - optional real TCP port for upstream TCP connections
  • UPSTREAM_PROXY - HTTP proxy for outgoing traffic, for example http://127.0.0.1:8080; useful for Burp Suite
  • UPSTREAM_PROXY_STAGE - upstream proxy mode: upstream or pre-rewrite; in pre-rewrite mode Burp sees the local URL first, then the request returns to the reverse proxy and only after that goes to the external origin
  • ADDITIONAL_TARGET_DOMAINS - additional root domains, comma-separated, for example static.example.net,auth.example.org
  • LISTEN_HOST - interface to listen on, default 0.0.0.0
  • LISTEN_PORT - local HTTP listener port, default 8080
  • HTTPS_ENABLED - enables the local HTTPS listener and certificate generation when set to 1 or true
  • HTTPS_PORT - HTTPS listener port, default 8443
  • PUBLIC_HOST - host used in rewritten responses; defaults to the first detected external IPv4
  • PUBLIC_PORT - port used in rewritten responses; defaults to LISTEN_PORT
  • PUBLIC_PROTOCOL - protocol used when rewriting links; defaults to https: when HTTPS_ENABLED, otherwise http:
  • WILDCARD_DNS_SUFFIX - wildcard DNS suffix, default sslip.io
  • TLS_DIR - directory for the local CA and issued certificates, default .local-tls in the project root
  • UPSTREAM_TLS_DISABLE_SNI - if set to 1, disables SNI for upstream TLS connections; useful for hosts that fail with tlsv1 unrecognized name
  • UPSTREAM_TLS_INSECURE - if set to 1, disables upstream TLS certificate verification; useful when intercepting HTTPS through Burp
  • UPSTREAM_TLS_SERVERNAME - manually overrides the upstream TLS servername
  • DEBUG_PROXY - if set to 1, prints detailed routing, upstream host selection, and TLS/HTTP errors
  • USE_BROWSER_HEADERS - if set to 1 or left unset, injects browser-like upstream headers when the client did not provide them
  • BROWSER_USER_AGENT, BROWSER_ACCEPT, BROWSER_ACCEPT_LANGUAGE, BROWSER_SEC_FETCH_SITE, BROWSER_SEC_FETCH_MODE, BROWSER_SEC_FETCH_DEST, BROWSER_UPGRADE_INSECURE_REQUESTS, BROWSER_SEC_CH_UA, BROWSER_SEC_CH_UA_MOBILE, BROWSER_SEC_CH_UA_PLATFORM - override the default browser-like headers

Mapping

  • A request to http://127.0.0.1:8080/path goes to the main upstream from TARGET_ORIGIN.
  • A request to http://192.168.1.91.sslip.io:8080/path also goes to the main upstream.
  • A request to http://api.192.168.1.91.sslip.io:8080/path goes to api.example.com.
  • If additional domains are enabled, separate local suffixes are created for them:
  • www.static.example.net -> www.static-example-net.192.168.1.91.sslip.io
  • login.auth.example.org -> login.auth-example-org.192.168.1.91.sslip.io
  • In Location, Set-Cookie, Access-Control-Allow-Origin, and other textual headers, domains are rewritten back to the local form.
  • Textual response bodies also have absolute URLs, authorities, and hostnames rewritten.

DNS

By default this is not a local DNS server. The proxy simply uses a public wildcard DNS service such as sslip.io, where:

  • 192.168.1.91.sslip.io -> 192.168.1.91
  • api.192.168.1.91.sslip.io -> 192.168.1.91

Because of that, the browser can resolve both the main local domain and its subdomains without a custom DNS server or /etc/hosts entries.

HTTPS

When HTTPS_ENABLED=1, the proxy:

  • generates a local CA;
  • generates a certificate for each incoming Host;
  • uses SNI so that api.<local-domain> and www.<local-domain> receive separate certificates;
  • automatically re-issues older local certificates if they were created without the browser-required TLS extensions.

Files are stored in .local-tls.

To remove browser certificate warnings, import the CA from:

/path/to/local-domain-proxy/.local-tls/local-proxy-ca.cert.pem

Example for macOS:

sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /path/to/local-domain-proxy/.local-tls/local-proxy-ca.cert.pem

Example for Windows (cmd as Administrator):

certutil -addstore -f Root "C:\path\to\local-proxy-ca.cert.pem"

Example for Windows PowerShell as Administrator:

Import-Certificate -FilePath "C:\path\to\local-proxy-ca.cert.pem" -CertStoreLocation Cert:\LocalMachine\Root

Hosts

If you do not want to use sslip.io, you can still add entries to /etc/hosts, for example:

127.0.0.1 local.test api.local.test static.local.test

Then run the proxy with LOCAL_DOMAIN=local.test.

Limitations

  • Body rewriting is only applied to textual content types.
  • Binary responses such as images, fonts, or archives are proxied unchanged.
  • For WebSocket, the proxy rewrites Host, Origin, Referer, and upgrade headers, but does not modify the frames inside the connection.

Русский

Локальная reverse proxy, которая позволяет открывать внешний сайт как локальный домен или IP и на лету переписывать запросы и ответы в обе стороны.

Возможности:

  • принимает запросы на локальный IP/порт или локальный домен;
  • автоматически подставляет внешний hostname и port для upstream-запроса;
  • переписывает домен и порт обратно на локальные в заголовках ответа;
  • заменяет внешний домен в HTML, JS, CSS, JSON, SVG, XML и других текстовых ответах;
  • поддерживает сабдомены по правилу api.example.com -> api.local.test;
  • умеет работать без правки /etc/hosts, используя wildcard DNS вида 192.168.1.91.sslip.io;
  • смягчает CORS для локальной отладки: обрабатывает preflight OPTIONS, отражает локальный Origin в Access-Control-Allow-Origin и переписывает Origin/Referer обратно во внешний домен для upstream;
  • сохраняет текстовые кодировки ответа, включая utf-8, latin1 и windows-1251;
  • умеет поднимать локальный HTTPS с собственным CA и сертификатами по Host;
  • проксирует WebSocket upgrade-запросы по тем же правилам маппинга доменов.

Запуск

cd /path/to/local-domain-proxy
TARGET_ORIGIN=https://example.com LISTEN_PORT=8080 npm start

CLI-вариант:

cd /path/to/local-domain-proxy
node src/index.js --target https://example.com --port 8080

Минимальный CLI-вариант с дефолтами:

cd /path/to/local-domain-proxy
node src/index.js --target https://example.com

HTTPS-режим:

cd /path/to/local-domain-proxy
TARGET_ORIGIN=https://example.com HTTPS_ENABLED=1 HTTPS_PORT=8443 PUBLIC_PORT=8443 npm start

CLI-вариант:

cd /path/to/local-domain-proxy
node src/index.js --target https://example.com --https --https-port 8443 --public-port 8443

Минимальный HTTPS CLI-вариант с дефолтами:

cd /path/to/local-domain-proxy
node src/index.js --target https://example.com --https

Через Burp для исходящего трафика:

cd /path/to/local-domain-proxy
node src/index.js --target https://example.com --https --burp-proxy 127.0.0.1:8080

Короткий флаг --burp-proxy автоматически разворачивается в:

  • --upstream-proxy http://127.0.0.1:8080
  • --insecure-upstream-tls

Если нужен не Burp, а любой другой upstream HTTP proxy без автоотключения TLS-проверки, используй --upstream-proxy.

Если хочешь, чтобы Burp видела локальный запрос до подмены на оригинальный домен, добавь:

cd /path/to/local-domain-proxy
node src/index.js --target https://example.com --https --burp-proxy 127.0.0.1:8080 --burp-before-rewrite

В этом режиме прокси сначала отправляет через Burp именно локальный URL, а уже потом возвращает запрос обратно в reverse proxy на переписывание и выход наружу. Поэтому в Burp target будет локальным, а не оригинальным.

Повторный проход после возврата из Burp помечается как внутренний re-entry и уже не отправляется в Burp повторно, чтобы в истории не было дублей "до" и "после" переписывания.

Это удобно, если ты хочешь в Burp видеть локальный Host, локальный URL и локальную HTTPS-сессию до того, как reverse proxy подменит всё на внешний origin.

Если LOCAL_DOMAIN не задан, прокси автоматически возьмет:

  • 192.168.1.91.sslip.io, если PUBLIC_HOST выглядит как IPv4;
  • иначе сам PUBLIC_HOST.

Если PUBLIC_HOST не задан, прокси сама выберет первый подходящий внешний IPv4, предпочитая приватный LAN-адрес вроде 192.168.x.x или 10.x.x.x.

Конфигурация

Переменные окружения:

  • TARGET_ORIGIN - внешний origin, например https://example.com или https://example.com:8443
  • LOCAL_DOMAIN - локальный домен для переписывания, например local.test; если не задан, будет автоматически собран из PUBLIC_HOST
  • TARGET_CONNECT_HOST - необязательный реальный адрес для TCP-подключения к upstream, если логический внешний домен резолвить не нужно или нельзя
  • TARGET_CONNECT_PORT - необязательный порт для TCP-подключения к upstream
  • UPSTREAM_PROXY - HTTP proxy для исходящего трафика, например http://127.0.0.1:8080; удобно для Burp Suite
  • UPSTREAM_PROXY_STAGE - режим upstream proxy: upstream или pre-rewrite; во втором режиме Burp видит сначала локальный URL, после чего запрос возвращается в reverse proxy и уже затем уходит на внешний origin
  • ADDITIONAL_TARGET_DOMAINS - дополнительные корневые домены через запятую, которые тоже нужно переписывать и проксировать, например static.example.net,auth.example.org
  • LISTEN_HOST - интерфейс, на котором слушает прокси, по умолчанию 0.0.0.0
  • LISTEN_PORT - локальный порт листнера, по умолчанию 8080
  • HTTPS_ENABLED - включает локальный HTTPS listener и генерацию сертификатов, если равно 1 или true
  • HTTPS_PORT - порт HTTPS listener, по умолчанию 8443
  • PUBLIC_HOST - хост, который будет подставляться в ответах вместо внешнего домена; по умолчанию берется первый внешний IPv4
  • PUBLIC_PORT - порт, который будет подставляться в ответах; по умолчанию совпадает с LISTEN_PORT
  • PUBLIC_PROTOCOL - протокол для переписывания ссылок в ответах; по умолчанию https: при HTTPS_ENABLED, иначе http:
  • WILDCARD_DNS_SUFFIX - суффикс wildcard DNS, по умолчанию sslip.io
  • TLS_DIR - каталог для локального CA и выданных сертификатов, по умолчанию .local-tls в корне проекта
  • UPSTREAM_TLS_DISABLE_SNI - если равно 1, прокси отключает SNI при TLS-подключении к upstream; полезно для хостов, которые отвечают tlsv1 unrecognized name
  • UPSTREAM_TLS_INSECURE - если равно 1, отключает проверку TLS-сертификата upstream; полезно при перехвате HTTPS через Burp
  • UPSTREAM_TLS_SERVERNAME - вручную задает servername для upstream TLS вместо вычисленного hostname
  • DEBUG_PROXY - если равно 1, прокси печатает подробный маршрут запроса, выбранный upstream host и ошибки TLS/HTTP
  • USE_BROWSER_HEADERS - если равно 1 или не задано, прокси подставляет браузероподобные заголовки для upstream, если клиент их не прислал
  • BROWSER_USER_AGENT, BROWSER_ACCEPT, BROWSER_ACCEPT_LANGUAGE, BROWSER_SEC_FETCH_SITE, BROWSER_SEC_FETCH_MODE, BROWSER_SEC_FETCH_DEST, BROWSER_UPGRADE_INSECURE_REQUESTS, BROWSER_SEC_CH_UA, BROWSER_SEC_CH_UA_MOBILE, BROWSER_SEC_CH_UA_PLATFORM - позволяют переопределить браузерные заголовки по умолчанию

Как работает маппинг

  • Запрос на http://127.0.0.1:8080/path уйдет на основной upstream из TARGET_ORIGIN.
  • Запрос на http://192.168.1.91.sslip.io:8080/path тоже уйдет на основной upstream.
  • Запрос на http://api.192.168.1.91.sslip.io:8080/path уйдет на api.example.com.
  • Если включены дополнительные домены, то для них создаются свои локальные суффиксы:
  • www.static.example.net -> www.static-example-net.192.168.1.91.sslip.io
  • login.auth.example.org -> login.auth-example-org.192.168.1.91.sslip.io
  • В Location, Set-Cookie, Access-Control-Allow-Origin и других текстовых заголовках домен будет переписан обратно на локальный.
  • В текстовых телах ответа также будут заменены абсолютные URL, хосты с портом и сами hostname.

DNS

По умолчанию это не локальный DNS-сервер. Прокси просто использует публичный wildcard DNS, например sslip.io, где:

  • 192.168.1.91.sslip.io -> 192.168.1.91
  • api.192.168.1.91.sslip.io -> 192.168.1.91

Поэтому браузер может открыть и основной локальный домен, и его сабдомены без отдельного DNS-сервера и без /etc/hosts.

HTTPS

При HTTPS_ENABLED=1 прокси:

  • генерирует локальный CA;
  • генерирует сертификат для каждого входящего Host;
  • использует SNI, чтобы на api.<local-domain> и www.<local-domain> отдавать отдельные сертификаты;
  • если старые локальные сертификаты были выпущены без нужных TLS-расширений браузера, прокси автоматически перевыпустит их при следующем запуске.

Файлы хранятся в каталоге .local-tls.

Чтобы браузер перестал ругаться на сертификаты, импортируй CA из:

/path/to/local-domain-proxy/.local-tls/local-proxy-ca.cert.pem

Пример для macOS:

sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /path/to/local-domain-proxy/.local-tls/local-proxy-ca.cert.pem

Пример для Windows (cmd от имени администратора):

certutil -addstore -f Root "C:\path\to\local-proxy-ca.cert.pem"

Пример для Windows PowerShell от имени администратора:

Import-Certificate -FilePath "C:\path\to\local-proxy-ca.cert.pem" -CertStoreLocation Cert:\LocalMachine\Root

Hosts

Если не хочется использовать sslip.io, можно как и раньше прописать имена в /etc/hosts, например:

127.0.0.1 local.test api.local.test static.local.test

Тогда запускай с LOCAL_DOMAIN=local.test.

Ограничения

  • Переписывание тела делается только для текстовых content-type.
  • Бинарные ответы (images, fonts, archives) проксируются без изменений.
  • Для WebSocket прокси переписывает Host, Origin, Referer и upgrade-заголовки, но не изменяет сами фреймы внутри соединения.

About

Local reverse proxy for mapping external websites to a local domain with response rewriting, HTTPS, subdomain support, WebSocket proxying, and optional Burp integration.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages