Client

HTTP Tunnel

Learn how to start an HTTP tunnel with the Portr CLI to expose a local web server or API to the public internet in a single command.

Use the following command to tunnel an HTTP connection.

portr http 9000

Or start it with a custom subdomain:

portr http 9000 --subdomain amal-test

This also starts the portr inspector on http://localhost:7777 by default, where you can inspect and replay HTTP requests. Change dashboard_port in the client config to move it to another local port, or set disable_dashboard: true to skip starting it entirely.

Rewriting the Host header

By default, Portr forwards the public host (amal-test.portr.dev) to your local server. Frameworks with host allowlists — Rails host authorization, Django ALLOWED_HOSTS, Vite server.allowedHosts — reject those requests.

portr http 9000 --host-header rewrite

rewrite replaces the Host header with the local address (localhost:9000). Any other value is sent literally, which is useful for vhost-based local setups:

portr http 9000 --host-header myapp.local

Or per tunnel in the config file:

tunnels:
  - name: rails
    subdomain: rails
    port: 3000
    host_header: rewrite

rewrite changes the hostname your app believes it is served from, so absolute URLs and redirects it generates will point at the local address. If that matters, leave host_header unset and add the public host to your framework's allowlist instead.

host_header is only valid on type: http tunnels. The inspector always records the original public host, not the rewritten one.

Password-protecting a tunnel

A tunnel URL is public as soon as it starts. basic_auth puts HTTP basic auth in front of it, so visitors get their browser's credential prompt and only authenticated requests reach your local server.

portr http 9000 --basic-auth admin:s3cret

Flags can appear anywhere on the command line — before or after the port, in any order.

The value is user:password, split on the first colon — your password may contain colons, the username may not. Because a credential on the command line is visible in the process table and lands in your shell history, you can pass it through the environment instead:

PORTR_BASIC_AUTH=admin:s3cret portr http 9000

Or per tunnel in the config file:

tunnels:
  - name: staging
    subdomain: staging
    port: 9000
    basic_auth: admin:s3cret

basic_auth works on http, stub and static tunnels. It is rejected on tcp tunnels, which carry no HTTP requests to challenge, and on team templates, which are shared verbatim in plain text and cannot keep a credential secret.

Rejected requests are recorded in the inspector as 401, with the attempted credential redacted, so you can see what is hitting the tunnel.

Basic auth is base64-encoded, not encrypted. Over the default https:// tunnel URL it is protected by TLS, but if you run with use_localhost: true the tunnel URL is plain http:// and the credentials travel in the clear.

A few behaviours worth knowing:

  • Your app still sees the header. Portr validates Authorization and forwards it unchanged, so a local app checking the same credential keeps working. An app expecting a different Authorization value cannot work behind basic_auth — a browser only sends one.
  • WebSocket handshakes are gated too. Browsers replay cached credentials on the upgrade, but non-browser clients must send the header themselves (wscat -H "Authorization: Basic ..."). A failed upgrade shows up as 401 with no credential prompt.
  • CORS preflights are gated. Browsers do not send Authorization on an OPTIONS preflight, so cross-origin JavaScript cannot reach a basic_auth tunnel.
  • There is no logout. Browsers cache basic credentials per origin for the session, so changing basic_auth does not evict a credential a browser already has.
  • Replaying a request returns 401. The inspector redacts Authorization when it stores a request, so a replay re-sends the redacted placeholder. Set the header explicitly in the replay dialog, or with portr replay --header "Authorization: Basic ...".

How it works

When you run the HTTP tunnel command:

  1. Portr connects to your configured server
  2. Creates a secure tunnel from your local port to a public URL
  3. Starts the request inspector interface locally
  4. Routes all incoming requests through the tunnel to your local service

Inspector Features

The Portr inspector provides powerful debugging capabilities:

  • Request inspection: View all incoming HTTP requests in real-time
  • Request replay: Replay a stored request as-is or edit it before resending
  • Headers analysis: Examine request and response headers
  • Payload viewing: Inspect request and response bodies
  • WebSocket inspection: Monitor upgraded WebSocket sessions and captured frames

Common Use Cases

  • Local web development: Share your local development server with others
  • Webhook testing: Receive webhooks from external services during development
  • API debugging: Test API integrations with external services
  • Demo presentations: Show your work to clients or team members