Skip to main content

port-proxy

Expose local web applications publicly through the Distiller platform's built-in reverse proxy. Fix path issues, resolve MIME type errors, and make your applications accessible from anywhere.

Overview

The port-proxy skill enables you to expose local web applications running on your Distiller device to the internet through a secure reverse proxy. It automatically handles SSL/TLS, domain routing, and path rewriting, making it easy to share your projects and access them remotely.

Features

  • Public Access - Expose local apps to the internet
  • Automatic SSL/TLS - HTTPS enabled by default
  • Path Rewriting - Fix absolute path issues
  • MIME Type Handling - Resolve CSS/JS loading issues
  • WebSocket Support - Real-time applications work
  • Custom Domains - Use your own subdomain
  • Authentication - Optional basic auth protection

Prerequisites

  • Distiller device with internet connection
  • Local web application running on any port
  • Valid Distiller account (for public proxies)
  • Firewall configured if needed

Usage

Basic Commands

# Expose local app on port 3000
/port-proxy enable --port 3000

# Expose with custom subdomain
/port-proxy enable --port 5000 --subdomain myapp

# Expose with authentication
/port-proxy enable --port 8080 --auth user:password

# List active proxies
/port-proxy list

# Disable proxy
/port-proxy disable --port 3000

# Show proxy URL
/port-proxy url --port 3000

Advanced Options

# Enable with path prefix
/port-proxy enable --port 3000 --path /myapp

# Enable WebSocket support
/port-proxy enable --port 3000 --websocket

# Custom timeout
/port-proxy enable --port 3000 --timeout 300

# Enable CORS
/port-proxy enable --port 3000 --cors

# Custom headers
/port-proxy enable --port 3000 --header "X-Custom: value"

Common Use Cases

Expose Development Server

# React/Vue/Angular dev server
npm start # Runs on port 3000
/port-proxy enable --port 3000

# Access at: https://your-device.distiller.app

Expose Flask/FastAPI App

# Start Flask app
python app.py # Runs on port 5000

# Enable proxy
/port-proxy enable --port 5000 --subdomain myapi

# Access at: https://myapi.distiller.app

Expose Node.js App

# Start Express server
node server.js # Runs on port 8080

# Enable proxy with auth
/port-proxy enable --port 8080 --auth admin:secret123

# Access at: https://your-device.distiller.app
# Requires username: admin, password: secret123

Python API

Basic Proxy Management

from distiller_sdk import PortProxy

# Create proxy manager
proxy = PortProxy()

# Enable proxy
url = proxy.enable(port=3000)
print(f"Application available at: {url}")

# Disable proxy
proxy.disable(port=3000)

# List all proxies
proxies = proxy.list()
for p in proxies:
print(f"Port {p.port}: {p.url}")

Advanced Configuration

from distiller_sdk import PortProxy, ProxyConfig

# Configure proxy
config = ProxyConfig(
port=5000,
subdomain="myapp",
path_prefix="/api",
enable_websocket=True,
enable_cors=True,
timeout=300,
auth=("username", "password")
)

proxy = PortProxy()
url = proxy.enable_with_config(config)
print(f"Proxy enabled: {url}")

Automatic Proxy Management

from distiller_sdk import PortProxy
import subprocess
import time

proxy = PortProxy()

# Start application
app_process = subprocess.Popen(["python", "app.py"])

# Wait for app to start
time.sleep(3)

# Enable proxy
url = proxy.enable(port=5000)
print(f"Application running at: {url}")

try:
# Keep running
app_process.wait()
except KeyboardInterrupt:
# Cleanup
proxy.disable(port=5000)
app_process.terminate()

Context Manager

from distiller_sdk import PortProxy

# Automatically enable and disable proxy
with PortProxy() as proxy:
url = proxy.enable(port=3000)
print(f"App available at: {url}")

# Run application
run_app()

# Proxy automatically disabled when context exits

Fixing Path Issues

Problem: CSS/JS Not Loading

When running behind a reverse proxy, absolute paths may not work correctly.

Symptom:

GET /style.css → 404 Not Found
GET /script.js → 404 Not Found

Solution 1: Use Relative Paths

// ❌ Absolute path (breaks behind proxy)
<link href="/style.css" rel="stylesheet">
<script src="/script.js"></script>

// ✅ Relative path (works behind proxy)
<link href="style.css" rel="stylesheet">
<script src="script.js"></script>

Solution 2: Use Base Tag

<html>
<head>
<base href="/">
<link href="style.css" rel="stylesheet">
</head>
</html>

Solution 3: Configure Path Prefix

# Tell proxy to rewrite paths
/port-proxy enable --port 3000 --path /myapp --rewrite-paths

Problem: API Endpoints 404

Symptom:

GET /api/users → 404 Not Found

Solution: Path Prefix Configuration

# Flask example
from flask import Flask

app = Flask(__name__)

# Configure app for proxy path
app.config['APPLICATION_ROOT'] = '/myapp'

@app.route('/api/users')
def get_users():
return {'users': []}

# Enable proxy with matching path
proxy.enable(port=5000, path_prefix='/myapp')

Problem: WebSocket Connection Failed

Symptom:

WebSocket connection failed

Solution: Enable WebSocket Support

/port-proxy enable --port 3000 --websocket

# Or in Python
proxy.enable(port=3000, enable_websocket=True)

MIME Type Issues

Problem: Wrong MIME Type

Symptom:

Refused to apply style from 'style.css' because MIME type ('text/plain') is not 'text/css'

Solution 1: File Extensions

Ensure files have correct extensions:

  • .css for stylesheets
  • .js for JavaScript
  • .json for JSON

Solution 2: Server Configuration

# Flask example
from flask import Flask, send_from_directory

app = Flask(__name__)

@app.route('/static/<path:path>')
def serve_static(path):
return send_from_directory('static', path,
mimetype='text/css' if path.endswith('.css') else None)

Solution 3: Proxy Headers

/port-proxy enable --port 3000 --header "Content-Type: text/css"

Security

Authentication

# Basic auth
/port-proxy enable --port 3000 --auth username:password

# In Python
proxy.enable(port=3000, auth=("username", "password"))

IP Whitelist

# Only allow specific IPs
/port-proxy enable --port 3000 --allow-ip 192.168.1.0/24

# In Python
config = ProxyConfig(
port=3000,
allowed_ips=["192.168.1.0/24", "10.0.0.1"]
)
proxy.enable_with_config(config)

Rate Limiting

# Limit requests per minute
/port-proxy enable --port 3000 --rate-limit 100

# In Python
proxy.enable(port=3000, rate_limit=100)

Technical Details

Proxy Architecture

Internet → Distiller Proxy (nginx) → Your Local App
HTTPS Path Rewriting HTTP
Port 443 SSL/TLS Termination Port 3000

Supported Protocols

  • HTTP/1.1
  • HTTP/2
  • WebSocket (ws://, wss://)
  • Server-Sent Events (SSE)

Headers Added

The proxy adds headers to help your app:

  • X-Forwarded-For - Original client IP
  • X-Forwarded-Proto - Original protocol (https)
  • X-Forwarded-Host - Original host
  • X-Real-IP - Client IP address

Limitations

  • Port Range: 1024-65535 (no privileged ports)
  • Request Size: 100MB max
  • Timeout: 300 seconds default
  • Bandwidth: Fair use policy applies
  • Concurrent Connections: 100 per proxy

Configuration Examples

React Development Server

# Start React app
npm start # Port 3000

# Enable proxy with WebSocket (for hot reload)
/port-proxy enable --port 3000 --websocket

# Access at generated URL

FastAPI Backend

from fastapi import FastAPI
from distiller_sdk import PortProxy
import uvicorn

app = FastAPI()
proxy = PortProxy()

@app.get("/api/hello")
def hello():
return {"message": "Hello World"}

if __name__ == "__main__":
# Enable proxy
url = proxy.enable(port=8000, path_prefix="/api")
print(f"API available at: {url}")

# Start server
uvicorn.run(app, host="0.0.0.0", port=8000)

Flask with Authentication

from flask import Flask
from distiller_sdk import PortProxy

app = Flask(__name__)
proxy = PortProxy()

@app.route("/")
def index():
return "Hello World"

if __name__ == "__main__":
# Enable proxy with auth
url = proxy.enable(
port=5000,
auth=("admin", "password123")
)
print(f"App available at: {url}")

app.run(host="0.0.0.0", port=5000)

Troubleshooting

Proxy Won't Enable

# Check if port is already in use
netstat -tulpn | grep :3000

# Check if another proxy exists
/port-proxy list

# Verify application is running
curl http://localhost:3000

502 Bad Gateway

Causes:

  • Application not running
  • Application crashed
  • Wrong port specified
  • Firewall blocking connection

Solutions:

# Check if app is running
ps aux | grep python

# Check app logs
journalctl -u your-app

# Restart app
systemctl restart your-app

# Verify proxy port
/port-proxy list

504 Gateway Timeout

Causes:

  • Application is slow
  • Long-running request
  • Database query taking too long

Solutions:

# Increase timeout
/port-proxy enable --port 3000 --timeout 600

# Or in Python
proxy.enable(port=3000, timeout=600)

CSS/JS Not Loading

See "Fixing Path Issues" section above.

WebSocket Not Working

# Enable WebSocket support
/port-proxy enable --port 3000 --websocket

Best Practices

  1. Use authentication - Protect sensitive applications
  2. Monitor traffic - Check proxy logs regularly
  3. Set timeouts - Prevent hung connections
  4. Use HTTPS - Always (automatically enabled)
  5. Clean up - Disable unused proxies
  6. Rate limiting - Prevent abuse
  7. Test locally first - Verify app works before proxying

Advanced Examples

Multi-Port Application

from distiller_sdk import PortProxy

proxy = PortProxy()

# Frontend
frontend_url = proxy.enable(port=3000, subdomain="app")

# Backend API
api_url = proxy.enable(port=5000, subdomain="api")

# WebSocket server
ws_url = proxy.enable(port=8080, subdomain="ws", enable_websocket=True)

print(f"Frontend: {frontend_url}")
print(f"API: {api_url}")
print(f"WebSocket: {ws_url}")

Auto-Restart with Proxy

from distiller_sdk import PortProxy
import subprocess
import time

def run_app_with_proxy():
proxy = PortProxy()

while True:
try:
# Start app
print("Starting application...")
app = subprocess.Popen(["python", "app.py"])

# Wait for startup
time.sleep(3)

# Enable proxy
url = proxy.enable(port=5000)
print(f"App running at: {url}")

# Wait for app to exit
app.wait()

except KeyboardInterrupt:
print("Shutting down...")
proxy.disable(port=5000)
app.terminate()
break

except Exception as e:
print(f"Error: {e}")
time.sleep(5) # Wait before restart

run_app_with_proxy()

Load Balanced Proxies

from distiller_sdk import PortProxy

proxy = PortProxy()

# Start multiple instances
ports = [5000, 5001, 5002]

urls = []
for port in ports:
url = proxy.enable(port=port)
urls.append(url)
print(f"Instance on port {port}: {url}")

# Configure load balancer to distribute across instances

See Also