PublicLocal

PublicLocal vs ngrok: a free, open-source alternative

ngrok made "expose localhost" a one-liner, and it is a solid product. PublicLocal does the same job with two differences that matter to a lot of developers: it is fully open source, and you can run the server yourself. Updated 30 October 2026

Short version

Choose PublicLocal if you want a free public link without creating an account, an MIT-licensed tool you can read and change, or your own tunnel server on your own domain with no per-seat pricing.

Choose ngrok if you need its managed extras: traffic inspection in a dashboard, OAuth and IP policies in front of tunnels, edge load balancing, SLAs, or a global network of entry points.

Side by side

PublicLocalngrok
LicenceMIT, client and serverProprietary (agent source is viewable, server is not)
Free useNo account; 24-hour links, 7 days signed inAccount required; free tier with limits and an interstitial page
Random HTTPS subdomainsYesYes
Fixed subdomain / custom domainFree on your own serverPaid plans
Self-host the serverYes, one binary, any VPSNo
TCP tunnels (SSH, databases)On your own serverYes (paid for fixed addresses)
Automatic certificatesLet's Encrypt, or one wildcard via Cloudflare DNSManaged
WebSockets, streamingYesYes
Traffic inspectorTerminal feed plus a local inspector with webhook replayWeb dashboard with replay
Auth in front of tunnelsPassword-protected links, freeOAuth, basic auth, IP rules (paid)
QR code for phones--qrNo
Expired-link pages with statsYesNo
Share a folder or file directlypubliclocal share ./buildNo
Self-destructing links--max-visits, --expiresNo
MCP for AI assistantsBuilt inNo
Where traffic goespubliclocal.app (London), or your serverngrok's global edge
CostFree; self-hosting costs you a VPS (≈$5/month)Free tier; paid plans per user

Switching from ngrok

The commands map one to one. Install PublicLocal, then:

# ngrok                      # PublicLocal
ngrok http 3000              publiclocal http 3000
ngrok http 3000 --domain x   publiclocal http --subdomain x 3000   # own server
ngrok tcp 22                 publiclocal tcp 22                    # own server
ngrok config add-authtoken   publiclocal login                     # optional, for 7-day links

Things to know when you switch:

Self-hosting in two commands

This is the part ngrok cannot offer. With a domain and a small VPS:

# DNS: tunnel.example.com and *.tunnel.example.com -> your server
publiclocal server --domain tunnel.example.com --tokens "$(openssl rand -hex 24)"

# on your laptop
PUBLICLOCAL_SERVER=tunnel.example.com PUBLICLOCAL_TOKEN=... publiclocal http --subdomain myapp 3000
Forwarding https://myapp.tunnel.example.com -> localhost:3000

Certificates, reconnects and WebSockets are handled for you. The docs cover the flags; the public-instance guide covers running a server for other people safely.

Other alternatives, honestly

Cloudflare Tunnel (cloudflared) is free and robust, but your domain has to be on Cloudflare and traffic runs through their network; the server side is not open source. frp is open source and very capable (UDP, P2P, dashboards), with more configuration to write and no automatic HTTPS. bore is tiny and open source, TCP only, no HTTPS or subdomains. localtunnel is open source but its free server is often overloaded. PublicLocal sits in the middle: ngrok-style HTTPS links and subdomains, open source, one binary, and self-hostable.

Frequently asked

Is there a free alternative to ngrok?

Yes. PublicLocal is a free, open-source alternative. Run publiclocal http 3000 to get a public HTTPS link with no account; links last 24 hours, or 7 days with GitHub sign-in. You can also self-host the server on your own domain with no limits.

Can I self-host an ngrok alternative?

Yes. PublicLocal's server is open source. Point a domain and its wildcard DNS at a small VPS, run publiclocal server --domain yourdomain.com, and clients get addresses like https://myapp.yourdomain.com with automatic Let's Encrypt certificates, plus TCP tunnels.

How do I switch from ngrok to PublicLocal?

Install PublicLocal and replace ngrok http 3000 with publiclocal http 3000. For a fixed subdomain, self-host and use --subdomain myapp. For ngrok tcp 22, self-host and use publiclocal tcp 22.

Install PublicLocalRead the docs