pgrok is a free, open source identity & access management (iam) project written in Go and released under MIT. It has 3,645 GitHub stars, 134 forks and 18 open issues, and was last pushed 9 hours ago. On this registry it ranks #27 of 71 tracked projects in Identity & Access Management (IAM), with 5 head-to-head comparisons available.

What is pgrok?

pgrok is a self-hosted, multi-tenant networking platform, written in Go and released under the MIT licence, that exposes HTTP services and raw TCP connections through SSH reverse tunnels on your own domain, with users signing in through your team's OIDC-compatible SSO provider to obtain their tunnel credentials and stable subdomains.

What it is

pgrok is a two-part system: a server, pgrokd, that runs on infrastructure you control, and a client CLI, pgrok, that users install on their own machines. The server accepts SSH reverse tunnels on port 2222 and serves an HTTP dashboard; the client opens the tunnel and forwards traffic to a local address such as http://localhost:3000. The repository is written in Go, carries the MIT licence, and has 3,646 stars, 134 forks and 18 open issues. It is filed under Security & Privacy / Identity & Access Management because user access is bound to your identity provider rather than to a shared tunnel secret.

The concrete problem it solves is getting a locally running service in front of colleagues, clients or testers without asking non-engineers to understand server operations. The README is explicit that stable subdomains and SSO are two things that are too expensive to obtain together, and that community managers, sales staff and PMs should not have to debug tunnels to show their work. pgrok lives in the tunnelling corner of the Go ecosystem, tagged as an ngrok-alternative, and replaces the hosted tunnel service in that picture with software you run on your own domain: each user signs in through the team's SSO and receives a personal token plus a predictable subdomain, and "copy, paste, and run" is presented as the intended user experience.

Key capabilities

  • Exposes both HTTP services and raw TCP connections through SSH reverse tunnels, driven either by the pgrok CLI or by a standard SSH client.
  • Multi-tenant SSO login: users authenticate against an OIDC provider such as Google, JumpCloud, Okta, GitLab or Keycloak, and the dashboard hands back a token and a stable URL like unknwon.example.com.
  • Path-based routing to different local services via dynamic_forwards in pgrok.yml.
  • The server ships in three deployment shapes: a single binary, a standalone Docker container, and Docker Compose.
  • Guided client initialisation with pgrok init --remote-addr example.com:2222 --forward-addr http://localhost:3000 --token {YOUR_TOKEN}, which writes pgrok.yml into the standard XDG configuration directory on macOS, Linux or Windows.
  • Token rotation from the dashboard, where a regenerated token immediately stops working for new connections; the replacement goes into pgrok.yml or is passed with --token.
  • A documented Caddy 2 front: example.com proxied to localhost:3320 and *.example.com to localhost:3000, with the OIDC redirect URI set to http://example.com/-/oidc/callback.

Who uses it and how

  • Organisations that already run an OIDC-capable identity provider, since the login flow, the callback URI and the credential issuance all hang off that provider.
  • Teams with non-developer members — the README names community managers, sales and PMs — who need to publish a local service but should only ever paste a prepared command.
  • Self-hosters with a VPS or dedicated server that has a public IP address, control over DNS A and wildcard A records, and the ability to open inbound port 2222 to 0.0.0.0/0.
  • Groups that want predictable, person-specific subdomains rather than a random hostname per session, so links can be shared and reused.

Getting started

Deploy pgrokd on a server with a public IP using the single binary, the Docker image, or the Docker Compose setup, after pointing both example.com and *.example.com at the host and creating an OIDC client. On the client side, install with brew install pgrok or download the archive from the Releases page, then run pgrok init with your server address and token.

How it compares

The repository's own topics place it as an ngrok-alternative, and the README points readers at the Awesome Tunneling list rather than claiming novelty in tunnelling itself. Its distinction there is that the tunnel endpoint, the domain and the SSO integration are all yours, so stable subdomains and single sign-on arrive together instead of as separately priced hosted features.

When to use it — and when not to

Choose pgrok if you already operate an OIDC provider, can run a PostgreSQL v12-or-higher database, and are willing to own the DNS, the reverse proxy and the tunnel port. Skip it if the team has no identity provider to connect or if nobody wants to operate a server, because the documented path requires all of those pieces before the first tunnel works. The README keeps its walkthroughs on plain HTTP for brevity and defers HTTPS to a separate Caddy and Cloudflare guide, so TLS is an extra step rather than a default.

project readme (upstream, from github) — read inline

pgrok banner

Programmable Networking

Sourcegraph

What?

pgrok is a self-hosted, multi-tenant networking platform for exposing HTTP services and raw TCP connections through SSH reverse tunnels.

Run it on your own infrastructure with your own domain and OIDC-compatible SSO provider. Users sign in through your team's SSO to obtain their tunnel credentials and stable HTTP subdomains.

Use the pgrok CLI to create tunnels, choose predictable subdomains, and route HTTP requests to different local services by path—or connect with a standard SSH client.

Why?

Stable subdomains and SSO are two things too expensive.

Why not just pick one from the Awesome Tunneling? Think broader. Not everyone is a dev who knows about server operations. For people working as community managers, sales, and PMs, booting up something locally could already be a stretch and requiring them to understand how to set up and fix server problems is a waste of team's productivity.

Copy, paste, and run is the best UX for everyone.

How?

Before you get started, make sure you have the following:

  1. A domain name (e.g., example.com, this will be used as the example throughout this section).
  2. A server (dedicated server, VPS) with a public IP address (e.g., 111.33.5.14).
  3. An SSO provider (e.g., Google, JumpCloud, Okta, GitLab, Keycloak) that allows you to create OIDC clients.
  4. A PostgreSQL server, v12 or higher (Render, Vercel, Cloud SQL, self-host).

[!NOTE]

  1. All values used in this document are just examples, substitute based on your setup.
  2. All examples in this document use HTTP for brevity, you may refer to our example walkthrough of setting HTTPS with Caddy and Cloudflare.

Set up the server (pgrokd)

  1. Add the following DNS records for your domain name:
    1. A record for example.com to 111.33.5.14 (with DNS only if using Cloudflare)
    2. A record for *.example.com to 111.33.5.14 (with DNS only if using Cloudflare)
  2. Set up the server with the single binary, Docker or Docker Compose.
  3. Alter your network security policy (if applicable) to allow inbound requests to port 2222 from 0.0.0.0/0 (anywhere).
  4. Download and install Caddy 2 on your server, and use the following Caddyfile config:
    http://example.com {
        reverse_proxy * localhost:3320
    }
    
    http://*.example.com {
        reverse_proxy * localhost:3000
    }
    
  5. Create a new OIDC client in your SSO with the Redirect URI to be http://example.com/-/oidc/callback.

Set up the client (pgrok)

  1. Go to http://example.com, authenticate with your SSO to obtain the token and URL (e.g., http://unknwon.example.com). The "Get started" section of the dashboard has the following commands ready to copy with your token and server address filled in.
    • If your token leaks, click Regenerate next to it on the dashboard. The old token stops working for new connections immediately, so update every client with the new token: edit token in pgrok.yml, or pass --token to clients started with that flag. Re-running pgrok init ... --token also works, but rewrites the whole pgrok.yml, including any dynamic_forwards. Tunnels that are already connected keep running until they disconnect.
  2. Download the latest version of the pgrok:
    • For Homebrew:
      brew install pgrok
      
    • For others, download the archive from the Releases page.
  3. Initialize a pgrok.yml file with the following command (assuming you want to forward requests to http://localhost:3000):
    pgrok init --remote-addr example.com:2222 --forward-addr http://localhost:3000 --token {YOUR_TOKEN}
    
    • By default, the config file is created under the standard user configuration directory (XDG_CONFIG_HOME):
      • macOS: ~/Library/Application Support/pgrok/pgrok.yml
      • Linux: ~/.config/pgrok/pgrok.yml
      • Windows: %LOCALAPPDATA%\pgrok\pgrok.yml
    • Use --config flag to specify a different path for the config file.
  4. Launch the client by executing the pgrok or pgrok http command.
    • By default, pgrok expects the pgrok.yml is available under the standard user configuration directory, or under the home directory (~/.pgrok/pgrok.yml). Use --config flag to specify a different path for the config file.
    • Use the --debug flag to turn on debug logging.
    • Upon successful startup, you should see a log looks like:
      🎉 You're ready to go live at http://unknwon.example.com! remote=example.com:2222
      
  5. Now visit the URL.

As a special case, the first argument of the pgrok http can be used to specify forward address, e.g.,

pgrok http 8080
Raw TCP tunnels

[!IMPORTANT] You need to alter the server network security policy (if applicable) to allow additional inbound requests to port range 10000-15000 from 0.0.0.0/0 (anywhere).

Use the tcp subcommand to tunnel raw TCP traffic:

pgrok tcp 5432

Upon successful startup, you should see a log looks like:

🎉 You're ready to go live at tcp://example.com:10086! remote=example.com:2222

The assigned TCP port on the server side is semi-stable, such that the same port number is used when still available.

Override config options

Following config options can be overridden through CLI flags for both http and tcp subcommands:

  • --remote-addr, -r -> remote_addr
  • --forward-addr, -f -> forward_addr
  • --token, -t -> token
QR code

To open the tunnel on your phone right away, pgrok prints a QR code of the URL once the tunnel is up, for both http and tcp subcommands. It is printed again only when a reconnect gets a different URL, and only when stdout is a terminal.

HTTP dynamic forwards

Typical HTTP reverse tunnel solutions only support forwarding requests to a single address, pgrok can be configured to have dynamic forward rules when tunneling HTTP requests.

For example, if your local frontend is running at http://localhost:3000 but some gRPC endpoints need to talk to the backend directly at http://localhost:8080:

dynamic_forwards: |
  /api http://localhost:8080
  /hook http://localhost:8080

Then all requests prefixed with the path /api and /hook will be forwarded to http://localhost:8080 and all the rest are forwarded to the forward_addr (http://localhost:3000).

When prefixes overlap (e.g., /api and /api/v2), the longest matching prefix wins.

HTTP request headers

By default, requests are forwarded with the public Host header (e.g., unknwon.example.com), which local dev servers that check it (e.g., Vite's server.allowedHosts, Rails' config.hosts, Django's ALLOWED_HOSTS, webpack-dev-server) reject. Use --host-header rewrite to send the host of the forward address instead (e.g., localhost:5173), so no app config changes are needed:

pgrok http --host-header rewrite 5173
  • With dynamic forwards, each request gets the host of the address it is forwarded to.
  • Any other value is used literally, e.g., --host-header app.test.
  • The public host is kept in the X-Forwarded-Host header so the app can still build absolute URLs.

Use --request-header "Name: value" to add or overwrite a request header and --remove-request-header Name to remove one; both can be repeated. The equivalent options in pgrok.yml:

host_header: rewrite
request_headers:
  - "X-Tunnel: pgrok"
remove_request_headers:
  - Cookie

The --host-header flag overrides host_header, and headers from the CLI flags are applied after those in the config file. All removals are applied before any header is set, so a header that is both removed and set is sent with the set value, regardless of where each comes from. When set, X-Forwarded-For gets the local address appended and hop-by-hop headers (e.g., Connection, Upgrade) are dropped by the proxy.

Custom subdomain prefix

By default, each user gets a single stable subdomain (e.g., unknwon.example.com), and when it is already taken pgrok falls back to a host prefixed with a server-generated UUID (e.g., 7fa4f0d0...-unknwon.example.com). Use the --subdomain, -s flag of the http subcommand to choose that prefix yourself, so you get a deterministic URL and can run multiple tunnels under predictable hosts:

pgrok http --subdomain staging 3000

This goes live at http://staging-unknwon.example.com, forwarding to http://localhost:3000.

  • The value may contain lowercase letters, digits, and hyphens, with no leading or trailing hyphen. It shares the leftmost DNS label with your subdomain (-), so the combined length must stay within 63 characters. Invalid values are rejected by the server.
  • The resulting URL is deterministic: if the prefixed host is already in use, the client fails with an error instead of falling back to a randomized one.
  • This flag only applies to HTTP tunnels. It has no effect on pgrok tcp.

Vanilla SSH

Because the standard SSH protocol is used for tunneling, you may well just use the vanilla SSH client.

  1. Go to http://example.com, authenticate with your SSO to obtain the token and URL (e.g., http://unknwon.example.com).
  2. Launch the client by executing the ssh -N -R 0:localhost:3000 example.com -p 2222 command:
    1. Enter the token as your password.
    2. Use the -v flag to turn on debug logging.
    3. Upon successful startup, you should see a log looks like:
      Allocated port 22487 for remote forward to localhost:3000
      
  3. Now visit the URL.

Explain it to me

pgrok network diagram

Contributing

Please read through our contributing guide and set up your development environment.

Sponsors

Credits

The project wouldn't be possible without reading function61/holepunch-server, function61/holepunch-client, and TCP/IP Port Forwarding.

License

This project is under the MIT License. See the LICENSE file for the full license text.

Frequently asked questions

Is pgrok free to use?

pgrok is open source under the MIT licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does pgrok do?

Self-hosted, multi-tenant networking platform for exposing HTTP services and raw TCP connections

What is pgrok written in?

pgrok is primarily written in Go. Its source is publicly available at https://github.com/pgrok/pgrok, and it has 3,645 GitHub stars.