Latest commit

History

37 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

publicRelay — Expose Local Services to the Internet via WebSocket Tunneling

Lightweight, self‑hosted HTTP reverse tunnel to expose localhost to the public internet using a Node.js relay and a Python client.


About

publicRelay (formerly HTTP Tunnel / Http Proxy) is an open‑source tunneling system that lets you publish a local web service without port‑forwarding or ISP NAT configuration. A public Node.js relay server accepts HTTP traffic and forwards it over a persistent WebSocket connection to a Python client running beside your local app. Responses are streamed back through the tunnel to the original requester.

This project is built for developers who want a simple, inspectable alternative to commercial tunnels ideal for local development, demos, webhook testing, or temporary sharing.

⚠️ This project is experimental and actively evolving. If you hit issues or have improvements, please open an issue or PR.


Features

  • Zero port forwarding - Works behind NAT / CGNAT.
  • Bi‑directional streaming - Full request/response relay over WebSocket.
  • Binary-safe - Handles JSON, text, and media via base64 for non‑text payloads.
  • Header preservation - Forwards request headers end‑to‑end.
  • Real client IP - Injects X-Forwarded-For with the original remote address.
  • Self‑hosted - Run on your own VPS (AWS/Linode/DO/etc.).
  • Hackable - Simple codebase, easy to extend.

Architecture

[ Internet Client ]
│
▼
[ Node.js Relay (Public IP) ]
│ WebSocket (JSON / Base64)
▼
[ Python Client (Private) ] ──► [ Local App (127.0.0.1:PORT) ]

How It Works

  1. Public Relay (Node.js) listens for HTTP requests and an incoming WebSocket connection.
  2. When a request arrives, the relay serializes the request (method, path, headers, body).
  3. The serialized request is sent over WebSocket to the Python client.
  4. The client replays the request locally using requests.
  5. The response is sent back over WebSocket.
  6. The relay converts it into a real HTTP response for the original requester.

The original visitor never talks directly to your private network.


Getting Started

Requirements

  • Public VPS with a reachable port
  • Node.js ≥ 16
  • Python ≥ 3.8
  • ws, requests, websocket-client

Installation

1. Clone

git clone https://github.com/bashified/publicRelay
cd publicRelay

2. Server Setup (Public Machine)

cd server
npm install

Edit server/proxyconfig.json to point to the open port

{
"port": 8080
}

Run the relay:

node proxy.js

3. Client Setup (Local Machine)

cd client
pip install -r requirements.txt

Edit client/clientconfig.json:

{
"proxy-ip": "YOUR_VPS_IP",
"proxy-port": 8080,
"localApplicationIP": "127.0.0.1",
"localApplicationPort": 5000
}

Run the client:

python client.py

or in background:

nohup python client.py > client.log &

Make sure your local app is listening on localhost:5000 or the address that u configured on the proxy.


Testing

In command prompt

curl http://YOUR_VPS_IP:8080/

If correctly connected:

Tunnel is alive

Try forwarding requests to your local server:

http://YOUR_VPS_IP:8080/api

Reading the Forwarded IP

The server sends the initiator ip under the "X-Forwarded-For" header and this can be like this :

# pythonrequest.headers.get("X-Forwarded-For")

This should be used instead of req.ip to avoid getting "localhost"


Security Notes

  • No authentication is currently implemented.

  • Anyone hitting your relay can reach your local app.

  • Recommended protections:

    • IP filtering
    • Auth tokens
    • Rate limiting
    • Getting an SSL cert to allow traffic and responses in HTTP/S

Do NOT use this for banking, auth flows, or sensitive production workloads.


Known Limitations

  • Single active client connection
  • Not suitable for WebRTC or long‑lived streams
  • Adds latency due to request relay

Roadmap

[ * ] Forward initiator IP [ * ] Binary payload support [ * ] Header passthrough [ ? ] Implementing a configurable firewall [ ? ] Blacklist feature for potential DDoS detection [ ? ] Multi‑tunnel support [ ? ] Authentication layer [ ? ] Access logging dashboard [ ? ] Traffic statistics


Contributing

Pull requests welcome.

If you add a feature, document it.


If you break it — fix it. If you improve it — PR it. If you love it — star it.

About

http tunnel written in node js and python using ws, http and flask to expose the localhost to the public network

Resources

Stars

3 stars

Watchers

1 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

37 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

publicRelay — Expose Local Services to the Internet via WebSocket Tunneling

Lightweight, self‑hosted HTTP reverse tunnel to expose localhost to the public internet using a Node.js relay and a Python client.


About

publicRelay (formerly HTTP Tunnel / Http Proxy) is an open‑source tunneling system that lets you publish a local web service without port‑forwarding or ISP NAT configuration. A public Node.js relay server accepts HTTP traffic and forwards it over a persistent WebSocket connection to a Python client running beside your local app. Responses are streamed back through the tunnel to the original requester.

This project is built for developers who want a simple, inspectable alternative to commercial tunnels ideal for local development, demos, webhook testing, or temporary sharing.

⚠️ This project is experimental and actively evolving. If you hit issues or have improvements, please open an issue or PR.


Features

  • Zero port forwarding - Works behind NAT / CGNAT.
  • Bi‑directional streaming - Full request/response relay over WebSocket.
  • Binary-safe - Handles JSON, text, and media via base64 for non‑text payloads.
  • Header preservation - Forwards request headers end‑to‑end.
  • Real client IP - Injects X-Forwarded-For with the original remote address.
  • Self‑hosted - Run on your own VPS (AWS/Linode/DO/etc.).
  • Hackable - Simple codebase, easy to extend.

Architecture

[ Internet Client ]
│
▼
[ Node.js Relay (Public IP) ]
│ WebSocket (JSON / Base64)
▼
[ Python Client (Private) ] ──► [ Local App (127.0.0.1:PORT) ]

How It Works

  1. Public Relay (Node.js) listens for HTTP requests and an incoming WebSocket connection.
  2. When a request arrives, the relay serializes the request (method, path, headers, body).
  3. The serialized request is sent over WebSocket to the Python client.
  4. The client replays the request locally using requests.
  5. The response is sent back over WebSocket.
  6. The relay converts it into a real HTTP response for the original requester.

The original visitor never talks directly to your private network.


Getting Started

Requirements

  • Public VPS with a reachable port
  • Node.js ≥ 16
  • Python ≥ 3.8
  • ws, requests, websocket-client

Installation

1. Clone

git clone https://github.com/bashified/publicRelay
cd publicRelay

2. Server Setup (Public Machine)

cd server
npm install

Edit server/proxyconfig.json to point to the open port

{
"port": 8080
}

Run the relay:

node proxy.js

3. Client Setup (Local Machine)

cd client
pip install -r requirements.txt

Edit client/clientconfig.json:

{
"proxy-ip": "YOUR_VPS_IP",
"proxy-port": 8080,
"localApplicationIP": "127.0.0.1",
"localApplicationPort": 5000
}

Run the client:

python client.py

or in background:

nohup python client.py > client.log &

Make sure your local app is listening on localhost:5000 or the address that u configured on the proxy.


Testing

In command prompt

curl http://YOUR_VPS_IP:8080/

If correctly connected:

Tunnel is alive

Try forwarding requests to your local server:

http://YOUR_VPS_IP:8080/api

Reading the Forwarded IP

The server sends the initiator ip under the "X-Forwarded-For" header and this can be like this :

# pythonrequest.headers.get("X-Forwarded-For")

This should be used instead of req.ip to avoid getting "localhost"


Security Notes

  • No authentication is currently implemented.

  • Anyone hitting your relay can reach your local app.

  • Recommended protections:

    • IP filtering
    • Auth tokens
    • Rate limiting
    • Getting an SSL cert to allow traffic and responses in HTTP/S

Do NOT use this for banking, auth flows, or sensitive production workloads.


Known Limitations

  • Single active client connection
  • Not suitable for WebRTC or long‑lived streams
  • Adds latency due to request relay

Roadmap

[ * ] Forward initiator IP [ * ] Binary payload support [ * ] Header passthrough [ ? ] Implementing a configurable firewall [ ? ] Blacklist feature for potential DDoS detection [ ? ] Multi‑tunnel support [ ? ] Authentication layer [ ? ] Access logging dashboard [ ? ] Traffic statistics


Contributing

Pull requests welcome.

If you add a feature, document it.


If you break it — fix it. If you improve it — PR it. If you love it — star it.

About

http tunnel written in node js and python using ws, http and flask to expose the localhost to the public network

Resources

Stars

3 stars

Watchers

1 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

37 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

publicRelay — Expose Local Services to the Internet via WebSocket Tunneling

Lightweight, self‑hosted HTTP reverse tunnel to expose localhost to the public internet using a Node.js relay and a Python client.


About

publicRelay (formerly HTTP Tunnel / Http Proxy) is an open‑source tunneling system that lets you publish a local web service without port‑forwarding or ISP NAT configuration. A public Node.js relay server accepts HTTP traffic and forwards it over a persistent WebSocket connection to a Python client running beside your local app. Responses are streamed back through the tunnel to the original requester.

This project is built for developers who want a simple, inspectable alternative to commercial tunnels ideal for local development, demos, webhook testing, or temporary sharing.

⚠️ This project is experimental and actively evolving. If you hit issues or have improvements, please open an issue or PR.


Features

  • Zero port forwarding - Works behind NAT / CGNAT.
  • Bi‑directional streaming - Full request/response relay over WebSocket.
  • Binary-safe - Handles JSON, text, and media via base64 for non‑text payloads.
  • Header preservation - Forwards request headers end‑to‑end.
  • Real client IP - Injects X-Forwarded-For with the original remote address.
  • Self‑hosted - Run on your own VPS (AWS/Linode/DO/etc.).
  • Hackable - Simple codebase, easy to extend.

Architecture

[ Internet Client ]
│
▼
[ Node.js Relay (Public IP) ]
│ WebSocket (JSON / Base64)
▼
[ Python Client (Private) ] ──► [ Local App (127.0.0.1:PORT) ]

How It Works

  1. Public Relay (Node.js) listens for HTTP requests and an incoming WebSocket connection.
  2. When a request arrives, the relay serializes the request (method, path, headers, body).
  3. The serialized request is sent over WebSocket to the Python client.
  4. The client replays the request locally using requests.
  5. The response is sent back over WebSocket.
  6. The relay converts it into a real HTTP response for the original requester.

The original visitor never talks directly to your private network.


Getting Started

Requirements

  • Public VPS with a reachable port
  • Node.js ≥ 16
  • Python ≥ 3.8
  • ws, requests, websocket-client

Installation

1. Clone

git clone https://github.com/bashified/publicRelay
cd publicRelay

2. Server Setup (Public Machine)

cd server
npm install

Edit server/proxyconfig.json to point to the open port

{
"port": 8080
}

Run the relay:

node proxy.js

3. Client Setup (Local Machine)

cd client
pip install -r requirements.txt

Edit client/clientconfig.json:

{
"proxy-ip": "YOUR_VPS_IP",
"proxy-port": 8080,
"localApplicationIP": "127.0.0.1",
"localApplicationPort": 5000
}

Run the client:

python client.py

or in background:

nohup python client.py > client.log &

Make sure your local app is listening on localhost:5000 or the address that u configured on the proxy.


Testing

In command prompt

curl http://YOUR_VPS_IP:8080/

If correctly connected:

Tunnel is alive

Try forwarding requests to your local server:

http://YOUR_VPS_IP:8080/api

Reading the Forwarded IP

The server sends the initiator ip under the "X-Forwarded-For" header and this can be like this :

# pythonrequest.headers.get("X-Forwarded-For")

This should be used instead of req.ip to avoid getting "localhost"


Security Notes

  • No authentication is currently implemented.

  • Anyone hitting your relay can reach your local app.

  • Recommended protections:

    • IP filtering
    • Auth tokens
    • Rate limiting
    • Getting an SSL cert to allow traffic and responses in HTTP/S

Do NOT use this for banking, auth flows, or sensitive production workloads.


Known Limitations

  • Single active client connection
  • Not suitable for WebRTC or long‑lived streams
  • Adds latency due to request relay

Roadmap

[ * ] Forward initiator IP [ * ] Binary payload support [ * ] Header passthrough [ ? ] Implementing a configurable firewall [ ? ] Blacklist feature for potential DDoS detection [ ? ] Multi‑tunnel support [ ? ] Authentication layer [ ? ] Access logging dashboard [ ? ] Traffic statistics


Contributing

Pull requests welcome.

If you add a feature, document it.


If you break it — fix it. If you improve it — PR it. If you love it — star it.

About

http tunnel written in node js and python using ws, http and flask to expose the localhost to the public network

Resources

Stars

3 stars

Watchers

1 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

37 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

publicRelay — Expose Local Services to the Internet via WebSocket Tunneling

Lightweight, self‑hosted HTTP reverse tunnel to expose localhost to the public internet using a Node.js relay and a Python client.


About

publicRelay (formerly HTTP Tunnel / Http Proxy) is an open‑source tunneling system that lets you publish a local web service without port‑forwarding or ISP NAT configuration. A public Node.js relay server accepts HTTP traffic and forwards it over a persistent WebSocket connection to a Python client running beside your local app. Responses are streamed back through the tunnel to the original requester.

This project is built for developers who want a simple, inspectable alternative to commercial tunnels ideal for local development, demos, webhook testing, or temporary sharing.

⚠️ This project is experimental and actively evolving. If you hit issues or have improvements, please open an issue or PR.


Features

  • Zero port forwarding - Works behind NAT / CGNAT.
  • Bi‑directional streaming - Full request/response relay over WebSocket.
  • Binary-safe - Handles JSON, text, and media via base64 for non‑text payloads.
  • Header preservation - Forwards request headers end‑to‑end.
  • Real client IP - Injects X-Forwarded-For with the original remote address.
  • Self‑hosted - Run on your own VPS (AWS/Linode/DO/etc.).
  • Hackable - Simple codebase, easy to extend.

Architecture

[ Internet Client ]
│
▼
[ Node.js Relay (Public IP) ]
│ WebSocket (JSON / Base64)
▼
[ Python Client (Private) ] ──► [ Local App (127.0.0.1:PORT) ]

How It Works

  1. Public Relay (Node.js) listens for HTTP requests and an incoming WebSocket connection.
  2. When a request arrives, the relay serializes the request (method, path, headers, body).
  3. The serialized request is sent over WebSocket to the Python client.
  4. The client replays the request locally using requests.
  5. The response is sent back over WebSocket.
  6. The relay converts it into a real HTTP response for the original requester.

The original visitor never talks directly to your private network.


Getting Started

Requirements

  • Public VPS with a reachable port
  • Node.js ≥ 16
  • Python ≥ 3.8
  • ws, requests, websocket-client

Installation

1. Clone

git clone https://github.com/bashified/publicRelay
cd publicRelay

2. Server Setup (Public Machine)

cd server
npm install

Edit server/proxyconfig.json to point to the open port

{
"port": 8080
}

Run the relay:

node proxy.js

3. Client Setup (Local Machine)

cd client
pip install -r requirements.txt

Edit client/clientconfig.json:

{
"proxy-ip": "YOUR_VPS_IP",
"proxy-port": 8080,
"localApplicationIP": "127.0.0.1",
"localApplicationPort": 5000
}

Run the client:

python client.py

or in background:

nohup python client.py > client.log &

Make sure your local app is listening on localhost:5000 or the address that u configured on the proxy.


Testing

In command prompt

curl http://YOUR_VPS_IP:8080/

If correctly connected:

Tunnel is alive

Try forwarding requests to your local server:

http://YOUR_VPS_IP:8080/api

Reading the Forwarded IP

The server sends the initiator ip under the "X-Forwarded-For" header and this can be like this :

# pythonrequest.headers.get("X-Forwarded-For")

This should be used instead of req.ip to avoid getting "localhost"


Security Notes

  • No authentication is currently implemented.

  • Anyone hitting your relay can reach your local app.

  • Recommended protections:

    • IP filtering
    • Auth tokens
    • Rate limiting
    • Getting an SSL cert to allow traffic and responses in HTTP/S

Do NOT use this for banking, auth flows, or sensitive production workloads.


Known Limitations

  • Single active client connection
  • Not suitable for WebRTC or long‑lived streams
  • Adds latency due to request relay

Roadmap

[ * ] Forward initiator IP [ * ] Binary payload support [ * ] Header passthrough [ ? ] Implementing a configurable firewall [ ? ] Blacklist feature for potential DDoS detection [ ? ] Multi‑tunnel support [ ? ] Authentication layer [ ? ] Access logging dashboard [ ? ] Traffic statistics


Contributing

Pull requests welcome.

If you add a feature, document it.


If you break it — fix it. If you improve it — PR it. If you love it — star it.

About

http tunnel written in node js and python using ws, http and flask to expose the localhost to the public network

Resources

Stars

3 stars

Watchers

1 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

37 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

publicRelay — Expose Local Services to the Internet via WebSocket Tunneling

Lightweight, self‑hosted HTTP reverse tunnel to expose localhost to the public internet using a Node.js relay and a Python client.


About

publicRelay (formerly HTTP Tunnel / Http Proxy) is an open‑source tunneling system that lets you publish a local web service without port‑forwarding or ISP NAT configuration. A public Node.js relay server accepts HTTP traffic and forwards it over a persistent WebSocket connection to a Python client running beside your local app. Responses are streamed back through the tunnel to the original requester.

This project is built for developers who want a simple, inspectable alternative to commercial tunnels ideal for local development, demos, webhook testing, or temporary sharing.

⚠️ This project is experimental and actively evolving. If you hit issues or have improvements, please open an issue or PR.


Features

  • Zero port forwarding - Works behind NAT / CGNAT.
  • Bi‑directional streaming - Full request/response relay over WebSocket.
  • Binary-safe - Handles JSON, text, and media via base64 for non‑text payloads.
  • Header preservation - Forwards request headers end‑to‑end.
  • Real client IP - Injects X-Forwarded-For with the original remote address.
  • Self‑hosted - Run on your own VPS (AWS/Linode/DO/etc.).
  • Hackable - Simple codebase, easy to extend.

Architecture

[ Internet Client ]
│
▼
[ Node.js Relay (Public IP) ]
│ WebSocket (JSON / Base64)
▼
[ Python Client (Private) ] ──► [ Local App (127.0.0.1:PORT) ]

How It Works

  1. Public Relay (Node.js) listens for HTTP requests and an incoming WebSocket connection.
  2. When a request arrives, the relay serializes the request (method, path, headers, body).
  3. The serialized request is sent over WebSocket to the Python client.
  4. The client replays the request locally using requests.
  5. The response is sent back over WebSocket.
  6. The relay converts it into a real HTTP response for the original requester.

The original visitor never talks directly to your private network.


Getting Started

Requirements

  • Public VPS with a reachable port
  • Node.js ≥ 16
  • Python ≥ 3.8
  • ws, requests, websocket-client

Installation

1. Clone

git clone https://github.com/bashified/publicRelay
cd publicRelay

2. Server Setup (Public Machine)

cd server
npm install

Edit server/proxyconfig.json to point to the open port

{
"port": 8080
}

Run the relay:

node proxy.js

3. Client Setup (Local Machine)

cd client
pip install -r requirements.txt

Edit client/clientconfig.json:

{
"proxy-ip": "YOUR_VPS_IP",
"proxy-port": 8080,
"localApplicationIP": "127.0.0.1",
"localApplicationPort": 5000
}

Run the client:

python client.py

or in background:

nohup python client.py > client.log &

Make sure your local app is listening on localhost:5000 or the address that u configured on the proxy.


Testing

In command prompt

curl http://YOUR_VPS_IP:8080/

If correctly connected:

Tunnel is alive

Try forwarding requests to your local server:

http://YOUR_VPS_IP:8080/api

Reading the Forwarded IP

The server sends the initiator ip under the "X-Forwarded-For" header and this can be like this :

# pythonrequest.headers.get("X-Forwarded-For")

This should be used instead of req.ip to avoid getting "localhost"


Security Notes

  • No authentication is currently implemented.

  • Anyone hitting your relay can reach your local app.

  • Recommended protections:

    • IP filtering
    • Auth tokens
    • Rate limiting
    • Getting an SSL cert to allow traffic and responses in HTTP/S

Do NOT use this for banking, auth flows, or sensitive production workloads.


Known Limitations

  • Single active client connection
  • Not suitable for WebRTC or long‑lived streams
  • Adds latency due to request relay

Roadmap

[ * ] Forward initiator IP [ * ] Binary payload support [ * ] Header passthrough [ ? ] Implementing a configurable firewall [ ? ] Blacklist feature for potential DDoS detection [ ? ] Multi‑tunnel support [ ? ] Authentication layer [ ? ] Access logging dashboard [ ? ] Traffic statistics


Contributing

Pull requests welcome.

If you add a feature, document it.


If you break it — fix it. If you improve it — PR it. If you love it — star it.

About

http tunnel written in node js and python using ws, http and flask to expose the localhost to the public network

Resources

Stars

3 stars

Watchers

1 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

37 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

publicRelay — Expose Local Services to the Internet via WebSocket Tunneling

Lightweight, self‑hosted HTTP reverse tunnel to expose localhost to the public internet using a Node.js relay and a Python client.


About

publicRelay (formerly HTTP Tunnel / Http Proxy) is an open‑source tunneling system that lets you publish a local web service without port‑forwarding or ISP NAT configuration. A public Node.js relay server accepts HTTP traffic and forwards it over a persistent WebSocket connection to a Python client running beside your local app. Responses are streamed back through the tunnel to the original requester.

This project is built for developers who want a simple, inspectable alternative to commercial tunnels ideal for local development, demos, webhook testing, or temporary sharing.

⚠️ This project is experimental and actively evolving. If you hit issues or have improvements, please open an issue or PR.


Features

  • Zero port forwarding - Works behind NAT / CGNAT.
  • Bi‑directional streaming - Full request/response relay over WebSocket.
  • Binary-safe - Handles JSON, text, and media via base64 for non‑text payloads.
  • Header preservation - Forwards request headers end‑to‑end.
  • Real client IP - Injects X-Forwarded-For with the original remote address.
  • Self‑hosted - Run on your own VPS (AWS/Linode/DO/etc.).
  • Hackable - Simple codebase, easy to extend.

Architecture

[ Internet Client ]
│
▼
[ Node.js Relay (Public IP) ]
│ WebSocket (JSON / Base64)
▼
[ Python Client (Private) ] ──► [ Local App (127.0.0.1:PORT) ]

How It Works

  1. Public Relay (Node.js) listens for HTTP requests and an incoming WebSocket connection.
  2. When a request arrives, the relay serializes the request (method, path, headers, body).
  3. The serialized request is sent over WebSocket to the Python client.
  4. The client replays the request locally using requests.
  5. The response is sent back over WebSocket.
  6. The relay converts it into a real HTTP response for the original requester.

The original visitor never talks directly to your private network.


Getting Started

Requirements

  • Public VPS with a reachable port
  • Node.js ≥ 16
  • Python ≥ 3.8
  • ws, requests, websocket-client

Installation

1. Clone

git clone https://github.com/bashified/publicRelay
cd publicRelay

2. Server Setup (Public Machine)

cd server
npm install

Edit server/proxyconfig.json to point to the open port

{
"port": 8080
}

Run the relay:

node proxy.js

3. Client Setup (Local Machine)

cd client
pip install -r requirements.txt

Edit client/clientconfig.json:

{
"proxy-ip": "YOUR_VPS_IP",
"proxy-port": 8080,
"localApplicationIP": "127.0.0.1",
"localApplicationPort": 5000
}

Run the client:

python client.py

or in background:

nohup python client.py > client.log &

Make sure your local app is listening on localhost:5000 or the address that u configured on the proxy.


Testing

In command prompt

curl http://YOUR_VPS_IP:8080/

If correctly connected:

Tunnel is alive

Try forwarding requests to your local server:

http://YOUR_VPS_IP:8080/api

Reading the Forwarded IP

The server sends the initiator ip under the "X-Forwarded-For" header and this can be like this :

# pythonrequest.headers.get("X-Forwarded-For")

This should be used instead of req.ip to avoid getting "localhost"


Security Notes

  • No authentication is currently implemented.

  • Anyone hitting your relay can reach your local app.

  • Recommended protections:

    • IP filtering
    • Auth tokens
    • Rate limiting
    • Getting an SSL cert to allow traffic and responses in HTTP/S

Do NOT use this for banking, auth flows, or sensitive production workloads.


Known Limitations

  • Single active client connection
  • Not suitable for WebRTC or long‑lived streams
  • Adds latency due to request relay

Roadmap

[ * ] Forward initiator IP [ * ] Binary payload support [ * ] Header passthrough [ ? ] Implementing a configurable firewall [ ? ] Blacklist feature for potential DDoS detection [ ? ] Multi‑tunnel support [ ? ] Authentication layer [ ? ] Access logging dashboard [ ? ] Traffic statistics


Contributing

Pull requests welcome.

If you add a feature, document it.


If you break it — fix it. If you improve it — PR it. If you love it — star it.

About

http tunnel written in node js and python using ws, http and flask to expose the localhost to the public network

Resources

Stars

3 stars

Watchers

1 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

37 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

publicRelay — Expose Local Services to the Internet via WebSocket Tunneling

Lightweight, self‑hosted HTTP reverse tunnel to expose localhost to the public internet using a Node.js relay and a Python client.


About

publicRelay (formerly HTTP Tunnel / Http Proxy) is an open‑source tunneling system that lets you publish a local web service without port‑forwarding or ISP NAT configuration. A public Node.js relay server accepts HTTP traffic and forwards it over a persistent WebSocket connection to a Python client running beside your local app. Responses are streamed back through the tunnel to the original requester.

This project is built for developers who want a simple, inspectable alternative to commercial tunnels ideal for local development, demos, webhook testing, or temporary sharing.

⚠️ This project is experimental and actively evolving. If you hit issues or have improvements, please open an issue or PR.


Features

  • Zero port forwarding - Works behind NAT / CGNAT.
  • Bi‑directional streaming - Full request/response relay over WebSocket.
  • Binary-safe - Handles JSON, text, and media via base64 for non‑text payloads.
  • Header preservation - Forwards request headers end‑to‑end.
  • Real client IP - Injects X-Forwarded-For with the original remote address.
  • Self‑hosted - Run on your own VPS (AWS/Linode/DO/etc.).
  • Hackable - Simple codebase, easy to extend.

Architecture

[ Internet Client ]
│
▼
[ Node.js Relay (Public IP) ]
│ WebSocket (JSON / Base64)
▼
[ Python Client (Private) ] ──► [ Local App (127.0.0.1:PORT) ]

How It Works

  1. Public Relay (Node.js) listens for HTTP requests and an incoming WebSocket connection.
  2. When a request arrives, the relay serializes the request (method, path, headers, body).
  3. The serialized request is sent over WebSocket to the Python client.
  4. The client replays the request locally using requests.
  5. The response is sent back over WebSocket.
  6. The relay converts it into a real HTTP response for the original requester.

The original visitor never talks directly to your private network.


Getting Started

Requirements

  • Public VPS with a reachable port
  • Node.js ≥ 16
  • Python ≥ 3.8
  • ws, requests, websocket-client

Installation

1. Clone

git clone https://github.com/bashified/publicRelay
cd publicRelay

2. Server Setup (Public Machine)

cd server
npm install

Edit server/proxyconfig.json to point to the open port

{
"port": 8080
}

Run the relay:

node proxy.js

3. Client Setup (Local Machine)

cd client
pip install -r requirements.txt

Edit client/clientconfig.json:

{
"proxy-ip": "YOUR_VPS_IP",
"proxy-port": 8080,
"localApplicationIP": "127.0.0.1",
"localApplicationPort": 5000
}

Run the client:

python client.py

or in background:

nohup python client.py > client.log &

Make sure your local app is listening on localhost:5000 or the address that u configured on the proxy.


Testing

In command prompt

curl http://YOUR_VPS_IP:8080/

If correctly connected:

Tunnel is alive

Try forwarding requests to your local server:

http://YOUR_VPS_IP:8080/api

Reading the Forwarded IP

The server sends the initiator ip under the "X-Forwarded-For" header and this can be like this :

# pythonrequest.headers.get("X-Forwarded-For")

This should be used instead of req.ip to avoid getting "localhost"


Security Notes

  • No authentication is currently implemented.

  • Anyone hitting your relay can reach your local app.

  • Recommended protections:

    • IP filtering
    • Auth tokens
    • Rate limiting
    • Getting an SSL cert to allow traffic and responses in HTTP/S

Do NOT use this for banking, auth flows, or sensitive production workloads.


Known Limitations

  • Single active client connection
  • Not suitable for WebRTC or long‑lived streams
  • Adds latency due to request relay

Roadmap

[ * ] Forward initiator IP [ * ] Binary payload support [ * ] Header passthrough [ ? ] Implementing a configurable firewall [ ? ] Blacklist feature for potential DDoS detection [ ? ] Multi‑tunnel support [ ? ] Authentication layer [ ? ] Access logging dashboard [ ? ] Traffic statistics


Contributing

Pull requests welcome.

If you add a feature, document it.


If you break it — fix it. If you improve it — PR it. If you love it — star it.

About

http tunnel written in node js and python using ws, http and flask to expose the localhost to the public network

Resources

Stars

3 stars

Watchers

1 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

37 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

publicRelay — Expose Local Services to the Internet via WebSocket Tunneling

Lightweight, self‑hosted HTTP reverse tunnel to expose localhost to the public internet using a Node.js relay and a Python client.


About

publicRelay (formerly HTTP Tunnel / Http Proxy) is an open‑source tunneling system that lets you publish a local web service without port‑forwarding or ISP NAT configuration. A public Node.js relay server accepts HTTP traffic and forwards it over a persistent WebSocket connection to a Python client running beside your local app. Responses are streamed back through the tunnel to the original requester.

This project is built for developers who want a simple, inspectable alternative to commercial tunnels ideal for local development, demos, webhook testing, or temporary sharing.

⚠️ This project is experimental and actively evolving. If you hit issues or have improvements, please open an issue or PR.


Features

  • Zero port forwarding - Works behind NAT / CGNAT.
  • Bi‑directional streaming - Full request/response relay over WebSocket.
  • Binary-safe - Handles JSON, text, and media via base64 for non‑text payloads.
  • Header preservation - Forwards request headers end‑to‑end.
  • Real client IP - Injects X-Forwarded-For with the original remote address.
  • Self‑hosted - Run on your own VPS (AWS/Linode/DO/etc.).
  • Hackable - Simple codebase, easy to extend.

Architecture

[ Internet Client ]
│
▼
[ Node.js Relay (Public IP) ]
│ WebSocket (JSON / Base64)
▼
[ Python Client (Private) ] ──► [ Local App (127.0.0.1:PORT) ]

How It Works

  1. Public Relay (Node.js) listens for HTTP requests and an incoming WebSocket connection.
  2. When a request arrives, the relay serializes the request (method, path, headers, body).
  3. The serialized request is sent over WebSocket to the Python client.
  4. The client replays the request locally using requests.
  5. The response is sent back over WebSocket.
  6. The relay converts it into a real HTTP response for the original requester.

The original visitor never talks directly to your private network.


Getting Started

Requirements

  • Public VPS with a reachable port
  • Node.js ≥ 16
  • Python ≥ 3.8
  • ws, requests, websocket-client

Installation

1. Clone

git clone https://github.com/bashified/publicRelay
cd publicRelay

2. Server Setup (Public Machine)

cd server
npm install

Edit server/proxyconfig.json to point to the open port

{
"port": 8080
}

Run the relay:

node proxy.js

3. Client Setup (Local Machine)

cd client
pip install -r requirements.txt

Edit client/clientconfig.json:

{
"proxy-ip": "YOUR_VPS_IP",
"proxy-port": 8080,
"localApplicationIP": "127.0.0.1",
"localApplicationPort": 5000
}

Run the client:

python client.py

or in background:

nohup python client.py > client.log &

Make sure your local app is listening on localhost:5000 or the address that u configured on the proxy.


Testing

In command prompt

curl http://YOUR_VPS_IP:8080/

If correctly connected:

Tunnel is alive

Try forwarding requests to your local server:

http://YOUR_VPS_IP:8080/api

Reading the Forwarded IP

The server sends the initiator ip under the "X-Forwarded-For" header and this can be like this :

# pythonrequest.headers.get("X-Forwarded-For")

This should be used instead of req.ip to avoid getting "localhost"


Security Notes

  • No authentication is currently implemented.

  • Anyone hitting your relay can reach your local app.

  • Recommended protections:

    • IP filtering
    • Auth tokens
    • Rate limiting
    • Getting an SSL cert to allow traffic and responses in HTTP/S

Do NOT use this for banking, auth flows, or sensitive production workloads.


Known Limitations

  • Single active client connection
  • Not suitable for WebRTC or long‑lived streams
  • Adds latency due to request relay

Roadmap

[ * ] Forward initiator IP [ * ] Binary payload support [ * ] Header passthrough [ ? ] Implementing a configurable firewall [ ? ] Blacklist feature for potential DDoS detection [ ? ] Multi‑tunnel support [ ? ] Authentication layer [ ? ] Access logging dashboard [ ? ] Traffic statistics


Contributing

Pull requests welcome.

If you add a feature, document it.


If you break it — fix it. If you improve it — PR it. If you love it — star it.

About

http tunnel written in node js and python using ws, http and flask to expose the localhost to the public network

Resources

Stars

3 stars

Watchers

1 watching

Forks

Contributors

Languages