Skip to content

HTTP/HTTPS Tunnels

Give a local web app a public HTTPS address with a browser-trusted certificate, a link that survives restarts, and rules for who is allowed to open it.

Summary

One command gives a web app on your machine a public HTTPS address such as https://example.eu.localport.dev, reachable from anywhere. The certificate is publicly trusted, the address stays the same across restarts, and you decide who is allowed to open it.

What is an HTTP tunnel?#

An HTTP tunnel is a public HTTPS address for a web server on your machine. The Localport agent holds one outbound connection to Localport, and requests sent to your address reach your app through it.

The agent connects outward from your machine. Nothing on your network accepts an inbound connection, so there is no port forwarding, no firewall rule and no static IP address. It works behind carrier-grade NAT, on networks you do not administer, and on mobile connections.

Any web framework works unchanged. Next.js, Django, Rails, Laravel, Spring Boot, a Go binary, python3 -m http.server 3000. Your app continues to serve plain HTTP on localhost. The public address is HTTPS, and the certificate is obtained and renewed for you.

You need a Localport account, the Localport agent, and a web app listening on a local port.

Create a tunnel#

1. Open dashboard.localport.io and go to Tunnels.

2. Click New.

3. Enter a name, choose a region, and click Create Tunnel.

Every field here can be changed later.

  • Name identifies the tunnel in the dashboard. It does not appear in the public address.
  • Region is EU, US or Asia Pacific, and it forms part of the address. Choose the region closest to the people who will open the link.
  • Custom Domain serves the tunnel on a domain you own. Optional, and can be attached later.
  • Delivery is Standard or Fanout. Standard sends every request to one device. Fanout sends a copy of each request to every connected device, so a team can share one webhook URL.
  • Force HTTPS redirects plain http:// requests to the secure address. On by default.
Create your tunnel in two steps, then copy the command the dashboard builds for you.

Get your connect command#

Creating the tunnel opens the Connect step, which assembles the command for your service. The Connect button on the tunnel reopens it.

  • Preset fills in the protocol and port for you. Select your framework, or select Custom and enter them yourself.
  • Protocol is http for web apps and APIs. For databases, SSH and game servers, use a TCP tunnel.
  • Local Address is where the agent delivers traffic. It defaults to localhost and accepts another machine on your network.
  • Name identifies this connection in the agent output. Leave it blank to skip.
  • Run without the live UI replaces the live panel with plain log lines. Use it on a server, in CI, and inside Docker or systemd.
  • Log HTTP requests prints one line per request. Available once the live UI is off.
  • Token is the tunnel's credential, already in the command. Treat it like a password.

For a web app on port 3000:

localport http 3000 --token tok_k8f2 --region eu

http is the protocol, 3000 is the local port, --token authenticates the tunnel, and --region matches the region you selected. Every flag is documented in the CLI reference.

Keep the token off shared command lines

On a machine other people use, a token passed as an argument appears in the process list. Set LOCALPORT_TOKEN instead, or point LOCALPORT_TOKEN_FILE at a file only your user can read. See Environment Variables.

Run the tunnel#

Run the command in a terminal.

Run the command and your public HTTPS address appears under Forwarding.

Forwarding is the public address. Local is where traffic is delivered on your machine. Bandwidth and Connections update as traffic arrives, and each open connection is listed with its source address, duration and bytes transferred.

The address answers while the command runs. Press Ctrl+C to stop it, and run the command again to restore the same address.

See every request as it arrives

Turn on Log HTTP requests, or add --log-requests alongside --noui, and the agent prints one line per request with the method, the path, the status and the time your app took to answer.
2026-01-14T09:12:44Z http.req [default] GET /webhooks/stripe 200 12ms

Your permanent HTTPS address#

Your address is a subdomain of the region you selected.

https://example.eu.localport.dev

The URL is yours until you change it. Stopping the agent does not release it, and neither a reboot nor a change of network affects it. Register it once in a webhook setting or an OAuth callback and it continues to resolve.

The http:// form reaches the same tunnel. With Force HTTPS on, it answers a 308 to the secure address.

Use a custom domain instead

Attach a domain you own and the tunnel answers at preview.acme.com. Visitors see your own brand in the address bar, and Localport obtains and renews the certificate for that name. Detailed guide: Custom Domains.

Headers and request handling#

Requests reach your app as the visitor sent them. The original host is preserved, and three forwarding headers are added.

HeaderWhat your app sees
HostUnchanged, so name-based virtual hosts continue to resolve.
X-Forwarded-ForThe visitor's IP address.
X-Forwarded-Protohttps or http, whichever the visitor used.
X-Forwarded-HostThe same host, for frameworks that read the forwarded pair.

Request and response bodies are forwarded unchanged. Nothing is compressed, rewritten or cached in transit.

  • WebSocket upgrades pass through, so live reload, chat and any long-lived socket behave as they do locally.
  • Responses are flushed as they are written, so server-sent events and streamed responses reach the visitor as your app produces them.
  • No limit is placed on the duration of a request or a response. Large uploads, slow downloads and long-lived streams run to completion.
  • Between requests, an idle keep-alive connection is closed after 60 seconds, the same window a typical load balancer uses.
  • Browsers reach the tunnel over HTTP/2, and your app is reached over HTTP/1.1. For a protocol that requires HTTP/2 end to end, gRPC in particular, use a TCP or TLS tunnel.

Access controls#

Anyone with the address, until you restrict it. Every control below is set per tunnel, applied to every request, and takes effect on a tunnel that is already running.

Choose who can reach your tunnel, from the tunnel's own settings.
ControlWhat it does
Force HTTPSAnswers a plain http:// request with a 308 to the secure address. On by default, and applied before the password prompt.
Basic AuthenticationRequires a username and password. The browser prompts, and every request is checked. Basic Auth
Header AuthenticationRequires a header you name, carrying a value you set. Suits scripts, CI jobs and API clients. Header Authentication
Signature VerificationChecks the signature GitHub, Stripe, Shopify or Slack attaches to a webhook, against your signing secret. Webhook Signature Verification
Inbound IP WhitelistAdmits only the addresses and CIDR ranges you list. Every other connection is closed without a response. IP Allowlists
Network IPsLimits the addresses your own tunnel may connect from, so a leaked token cannot serve your app from elsewhere.

The first four sit under HTTP Protection in the tunnel's settings, and the last two under Network & Security.

The controls combine. A request is checked against the IP allowlist, then the password, then your header rules, then the webhook signature. The first refusal ends the request.

Control access by identity

A fleet is a group of your machines that is private by default. Every caller proves who it is before the connection is accepted, and reaches only the devices you grant it. Detailed guide: Remote Access.

Choose your subdomain#

Every tunnel is created with a generated name. To set your own, enter it in the Subdomain field of the tunnel's settings. The dashboard checks availability as you type.

Check whether the subdomain you want is available before you save it.

A subdomain is 12 characters or more, and a label is unique across every region. To serve the tunnel on a domain you own, see Custom Domains.

Forward to another machine#

The agent delivers to localhost by default. To reach an app on another host, a container or a NAS, pass the address to --local with an http:// scheme.

localport --token tok_k8f2 --local http://192.168.1.50:8080 --region eu

The Local Address field in the connect sheet writes the same flag. Include the port. The agent dials the address exactly as written, and http://192.168.1.50 fails with missing port in address.

Reach a local model server#

Ollama serves an HTTP API on 11434. On the machine holding the GPU:

localport http 11434 --token tok_k8f2 --region eu

Any OpenAI-compatible client then reaches the model over HTTPS, with no port in the address:

export OPENAI_BASE_URL=https://example.eu.localport.dev/v1

The model, the weights and the GPU stay on your machine.

A model server has no authentication of its own

Ollama and comparable servers answer every request they receive, so the tunnel address is the only barrier in front of your GPU. Add Header Authentication with a header of your own, or an inbound IP allowlist, before leaving it running. Basic Authentication reads the Authorization header, which OpenAI-compatible clients already use to carry their own key.

Editor and agent configurations are covered in the local LLM guide.

Common uses#

  • Receive live webhooks from Stripe, GitHub, Slack or Twilio on your machine, with a stack trace instead of a delivery log. See the webhook guide.
  • Share work in progress with a client or a colleague while you keep editing.
  • Open it on a phone over mobile data to check layout, touch targets and load time on a real device and a real network.
  • Register it as an OAuth redirect URI and develop against Google, GitHub or Apple over a genuine HTTPS callback.
  • Give a partner team an endpoint to integrate against before the service behind it is finished.
  • Use a model running on your own GPU from a laptop or a phone, through any OpenAI-compatible client. See the local LLM guide.
  • Point a headless browser, a link checker or Lighthouse at a build that exists only on your machine.

Frequently asked questions#

What is the difference between an HTTP tunnel and an HTTPS tunnel?

There is one tunnel and it serves both. Localport terminates HTTPS with a publicly trusted certificate and carries the request to your local app, which keeps serving plain HTTP. Share the https:// address. The http:// form reaches the same tunnel, and Force HTTPS redirects it to the secure one.

Do I need my own SSL certificate?

No. The certificate is obtained and renewed for you, and it is publicly trusted, so browsers show no warning and strict callers such as webhook senders and mobile apps accept it. Your app keeps serving plain HTTP on localhost with nothing to install or configure.

Does my public address change when I restart?

No. The same URL comes back every time, through restarts, reboots and network changes, and it is yours until you change it. Point a webhook setting or an OAuth callback at it once and leave it.

Does an HTTP tunnel work behind NAT, CGNAT or a corporate firewall?

Yes. The tunnel is an outbound connection from your machine, the same kind a browser makes, so there is no port to forward and no inbound rule to add. It works on home routers, on carrier-grade NAT, on office networks you do not administer, and on a phone hotspot.

Why do I see "Tunnel not found" or a 502?

Tunnel not found with a 404 means no agent is connected, so check the command is still running. A 502 means the agent is connected but your local app did not answer, so check the app is up on the port you forwarded.

How do I see the visitor's real IP address?

Read X-Forwarded-For. Your app also receives the original Host unchanged and X-Forwarded-Proto telling it whether the visitor arrived over HTTPS. Most frameworks need that pair to build correct absolute URLs, and many need a trusted-proxy setting turned on before they read either.

Do WebSockets and server-sent events work?

Yes, both. Upgrades pass through and responses are flushed as they are written, so live reload, chat and streaming responses behave as they do locally. No limit is placed on how long a request or a response may take.

Does gRPC work over an HTTP tunnel?

No. gRPC requires HTTP/2 all the way to the server, and an HTTP tunnel reaches your app over HTTP/1.1. Use a TCP tunnel for a plaintext gRPC server, or a TLS tunnel when the server holds its own certificate.

How do I password protect my tunnel?

Turn on Basic Authentication in the tunnel's settings and set a username and password. Visitors get a browser prompt before your app is reached, on every request. To limit by network address instead, use the IP allowlist, and for machine callers, Header Authentication checks a header you named.

What happens when I rotate the token?

A new token is issued and the old one stops being accepted for new connections. Connections already running are not interrupted, so rotating does not take your tunnel down, and the agent presents the new token the next time it connects. Your address and every other setting stay as they were.

Can I expose a database, SSH or a game server this way?

No. None of those are web protocols. Use a TCP tunnel. It gives the service a host and port instead of a URL.

  • Webhook Development. Step by step for Stripe, GitHub, Slack and Twilio.
  • Custom Domains. Serve the tunnel on a domain you own.
  • Fanout Tunnels. One address, delivered to every connected device.
  • TCP Tunnels. Databases, game servers, SSH and anything else that is not HTTP.
  • Local LLM. Reach Ollama and other model servers from anywhere.
  • CLI. Every command and flag.