website server hoster
@EliteCoder917Jun 10, 20262 files
A proxy that makes your clients browser work from your servers connection.
server.py
— server sideserver.py
# run this part on the server side
#!/usr/bin/env python3
"""
web.py — a password-protected HTTP/HTTPS forward proxy.
Run this on your Mac. It turns your Mac into a web proxy: any device that
points its browser at this proxy will browse the internet *through your Mac*
(using your Mac's IP address).
To make it reachable from anywhere on the internet, expose it with ngrok:
ngrok tcp 8080
ngrok prints a public address like tcp://7.tcp.ngrok.io:18123 — give that
host and port to the other device (see client.py).
Security: the proxy requires a username + password (HTTP proxy auth). NEVER run
an open proxy on the public internet — it will be found and abused. Change the
credentials below (or set PROXY_USER / PROXY_PASS environment variables).
"""
import base64
import os
import select
import socket
import sys
import threading
# --- configuration -----------------------------------------------------------
HOST = "0.0.0.0" # listen on all interfaces (ngrok connects locally)
PORT = int(os.environ.get("PROXY_PORT", "8080"))
USER = os.environ.get("PROXY_USER", "username")
PASS = os.environ.get("PROXY_PASS", "change-me-please")
BUFSIZE = 65536
# -----------------------------------------------------------------------------
EXPECTED_AUTH = "Basic " + base64.b64encode(f"{USER}:{PASS}".encode()).decode()
def recv_headers(sock):
"""Read until the end of the HTTP header block. Returns raw bytes or None."""
data = b""
while b"\r\n\r\n" not in data:
chunk = sock.recv(BUFSIZE)
if not chunk:
return None
data += chunk
if len(data) > 1_000_000: # guard against runaway headers
return None
return data
def parse_request(raw):
"""Return (method, target, version, header_lines list, raw bytes)."""
head, _, _rest = raw.partition(b"\r\n\r\n")
lines = head.split(b"\r\n")
method, target, version = lines[0].decode("latin-1").split(" ", 2)
headers = lines[1:]
return method, target, version, headers, raw
def find_header(headers, name):
name = name.lower()
for line in headers:
k, _, v = line.decode("latin-1").partition(":")
if k.strip().lower() == name:
return v.strip()
return None
def authorized(headers):
return find_header(headers, "Proxy-Authorization") == EXPECTED_AUTH
def send_407(client):
body = b"Proxy authentication required."
client.sendall(
b"HTTP/1.1 407 Proxy Authentication Required\r\n"
b'Proxy-Authenticate: Basic realm="Mac Proxy"\r\n'
b"Content-Length: " + str(len(body)).encode() + b"\r\n"
b"Connection: close\r\n\r\n" + body
)
def pipe(a, b):
"""Relay data both directions between two sockets until one closes."""
socks = [a, b]
try:
while True:
readable, _, errored = select.select(socks, [], socks, 60)
if errored or not readable:
break
for s in readable:
data = s.recv(BUFSIZE)
if not data:
return
(b if s is a else a).sendall(data)
except (OSError, ValueError):
pass
def handle_connect(client, target):
"""HTTPS / tunneling: 'CONNECT host:port HTTP/1.1'."""
host, _, port = target.partition(":")
port = int(port or 443)
try:
upstream = socket.create_connection((host, port), timeout=15)
except OSError as e:
client.sendall(f"HTTP/1.1 502 Bad Gateway\r\n\r\n{e}".encode())
return
client.sendall(b"HTTP/1.1 200 Connection Established\r\n\r\n")
pipe(client, upstream)
upstream.close()
def handle_plain(client, method, target, version, headers, raw):
"""Plain HTTP: target is an absolute URL like http://host/path."""
if not target.startswith("http://"):
client.sendall(b"HTTP/1.1 400 Bad Request\r\n\r\nUnsupported target")
return
rest = target[len("http://"):]
hostport, _, path = rest.partition("/")
path = "/" + path
host, _, port = hostport.partition(":")
port = int(port or 80)
# Rebuild the request in origin form, stripping proxy-only headers.
out_headers = []
for line in headers:
k = line.split(b":", 1)[0].strip().lower()
if k in (b"proxy-authorization", b"proxy-connection"):
continue
out_headers.append(line)
_head, _, body = raw.partition(b"\r\n\r\n")
request = (
f"{method} {path} {version}\r\n".encode()
+ b"\r\n".join(out_headers)
+ b"\r\n\r\n"
+ body
)
try:
upstream = socket.create_connection((host, port), timeout=15)
except OSError as e:
client.sendall(f"HTTP/1.1 502 Bad Gateway\r\n\r\n{e}".encode())
return
upstream.sendall(request)
pipe(client, upstream)
upstream.close()
def handle_client(client, addr):
try:
raw = recv_headers(client)
if not raw:
return
method, target, version, headers, raw = parse_request(raw)
if not authorized(headers):
send_407(client)
return
if method.upper() == "CONNECT":
handle_connect(client, target)
else:
handle_plain(client, method, target, version, headers, raw)
except Exception as e: # keep one bad request from crashing the server
sys.stderr.write(f"[error] {addr}: {e}\n")
finally:
client.close()
def main():
if PASS == "change-me-please":
sys.stderr.write(
"\n!! WARNING: using the default password. Set PROXY_PASS before\n"
" exposing this to the internet: PROXY_PASS=secret python3 web.py\n\n"
)
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((HOST, PORT))
server.listen(128)
print(f"Proxy listening on {HOST}:{PORT}")
print(f"Auth: user='{USER}' pass='{PASS}'")
print(f"Expose it with: ngrok tcp {PORT}")
print("Press Ctrl+C to stop.\n")
try:
while True:
client, addr = server.accept()
threading.Thread(
target=handle_client, args=(client, addr), daemon=True
).start()
except KeyboardInterrupt:
print("\nShutting down.")
finally:
server.close()
if __name__ == "__main__":
main()
client.py
— client sideclient.py
# run this part on the client side
#!/usr/bin/env python3
"""
client.py — run this on the OTHER device.
It launches a fresh browser window whose traffic is routed through your Mac's
proxy (web.py, exposed via `ngrok tcp`). Every page that browser loads is
fetched by your Mac, using your Mac's internet connection / IP address.
Fill in the four values below with what your Mac printed:
- the ngrok host + port (from `ngrok tcp 8080`, e.g. 7.tcp.ngrok.io 18123)
- the proxy username + password (from web.py)
Then run: python3 client.py
"""
import os
import shutil
import subprocess
import sys
import tempfile
# --- fill these in -----------------------------------------------------------
PROXY_HOST = "7.tcp.ngrok.io" # <-- from your `ngrok tcp 8080` output
PROXY_PORT = 18123 # <-- from your `ngrok tcp 8080` output
PROXY_USER = "username" # <-- must match web.py
PROXY_PASS = "change-me-please" # <-- must match web.py
START_URL = "https://whatismyipaddress.com" # opens here so you can confirm
# -----------------------------------------------------------------------------
def find_chrome():
"""Locate a Chromium-based browser on whatever OS this client runs on
(macOS / Windows / Linux). This is the *client* device's browser."""
if sys.platform == "darwin": # macOS
candidates = [
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"/Applications/Chromium.app/Contents/MacOS/Chromium",
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
]
elif sys.platform == "win32": # Windows
progfiles = [
os.environ.get("PROGRAMFILES", r"C:\Program Files"),
os.environ.get("PROGRAMFILES(X86)", r"C:\Program Files (x86)"),
os.environ.get("LOCALAPPDATA", ""),
]
rels = [
r"Google\Chrome\Application\chrome.exe",
r"Microsoft\Edge\Application\msedge.exe",
r"BraveSoftware\Brave-Browser\Application\brave.exe",
r"Chromium\Application\chrome.exe",
]
candidates = [os.path.join(b, r) for b in progfiles if b for r in rels]
else: # Linux / other
candidates = []
for path in candidates:
if os.path.exists(path):
return path
# Fall back to anything on PATH (covers Linux and PATH-installed browsers).
for name in ("google-chrome", "google-chrome-stable", "chromium",
"chromium-browser", "microsoft-edge", "msedge",
"brave-browser", "brave", "chrome"):
found = shutil.which(name)
if found:
return found
return None
def main():
chrome = find_chrome()
if not chrome:
sys.exit(
"No Chromium-based browser found. Install Google Chrome, Chromium, "
"Edge, or Brave (Chrome handles proxy auth most smoothly)."
)
proxy_server = f"{PROXY_HOST}:{PROXY_PORT}"
# Use a throwaway profile so we don't touch the user's normal browser data,
# and so the proxy applies cleanly to this window only.
profile_dir = tempfile.mkdtemp(prefix="mac-proxy-")
args = [
chrome,
f"--proxy-server=http://{proxy_server}",
# never bypass the proxy — force *all* traffic through the Mac:
"--proxy-bypass-list=<-loopback>",
f"--user-data-dir={profile_dir}",
"--no-first-run",
"--no-default-browser-check",
"--new-window",
START_URL,
]
print(f"Routing browser through Mac proxy at {proxy_server}")
print("When the browser prompts for a proxy username/password, enter:")
print(f" username: {PROXY_USER}")
print(f" password: {PROXY_PASS}")
print("\nLaunching browser...")
subprocess.Popen(args)
if __name__ == "__main__":
main()