CLI tool
tuanngocptn/nport avatar
tuanngocptn/nport

NPort advertises no limits while its own session banner counts down from four hours

NPort is a powerful, lightweight ngrok alternative that creates secure HTTP/HTTPS tunnels from your localhost to public URLs using Cloudflare's global edge network. No configuration, no accounts, just instant tunnels with custom subdomains!

774 stars134 forksTypeScriptMIT

At a glance

What is it?
A TypeScript ngrok alternative that tunnels localhost through Cloudflare's edge, where the default backend is shared by every user and the feature list and the rate limit notice disagree with each other.
Who is it for?
NPort is a reasonable choice for a short-lived demo or a webhook callback while you are iterating, and the install path is short enough that trying it costs little. Three things to know before you wire it into anything scheduled.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 95 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • tuanngocptn/nport774 ★ · +73
Star history
Repository2026-08-042026-11-14
tuanngocptn/nport701774

73 Stars in the last 102 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The feature list and the announcement at the top of the page contradict each other

Two blocks sit close together and cannot both be read as current. The announcement says the shared backend is receiving more tunnel requests than Cloudflare's API allows, that many users are being rate limited, and that this is not a problem on the reader's machine. The error it shows is:

code
✖ Failed to connect to server.
Backend Error: CF API Error: [10429] Rate limited. Please wait and consider throttling your request speed

Further down, the feature list claims no accounts, no limits and no paywalls, plus automatic HTTPS through Cloudflare and a global edge network. The tunnel time limit in the sample output contradicts the same claim from a third direction.

The announcement also names the release meant to settle this, v3.0.0, with friendly messages instead of the raw `10429`, automatic retry with backoff, smarter cleanup so abandoned tunnels stop consuming calls, higher capacity, visibility into current usage, and support for bringing your own Cloudflare account. None of that is in the version this repository is on.

Every tunnel start spends from one Cloudflare account's quota

The rate limit has a specific cause and a specific trigger. Cloudflare returns error `10429` when the account-wide API request quota for the shared `nport.link` backend is exhausted. Because every user of the default configuration goes through that one account, heavy usage from a few users rate-limits everyone else. There is no per-user accounting on the client side, so one busy repository can be the reason your one command fails.

The trigger is starting tunnels, not holding them open. The guidance is to wait a minute or two and run the command again, which fixes it most of the time, and to avoid starting many tunnels in a tight loop or in CI, since each start consumes API calls. The third option is to run your own backend with your own Cloudflare account.

That also explains why the retry item on the v3.0.0 list matters more than the friendlier wording: cleanup of abandoned tunnels is listed as a fix, which means a tunnel left running by a crashed process keeps drawing on the shared budget until it is reaped.

There is no flag for a Cloudflare account, only a backend URL

The options table is short enough to read in full. It carries six rows: a positional `<port>` that defaults to 8080, `--subdomain` with the short form `-s`, `--backend` with the short form `-b` described as temporary, `--set-backend` described as saving the URL permanently, `--language` with the short form `-l` taking en, vi or es or opening an interactive prompt, and `--version` with the short form `-v`.

None of them accepts a token, an account id, or a zone. So the bring-your-own Cloudflare account item on the v3.0.0 list has no client-side counterpart on this version, and the documented escape route is to run the backend yourself, in the `server/` directory, and point the client at it:

bash
# Use custom backend via CLI flag
nport 3000 --backend https://your-backend.com
nport 3000 -b https://your-backend.com

The default target is `https://api.nport.link`. The two backend flags differ only in lifetime, one for the current session and one written so later runs reuse it.

The subdomain flag is the other half of the URL story. Without `-s` you get a generated name such as `https://user-1234.nport.link`; with `nport 3000 -s myapp` you get `https://myapp.nport.link`, and the long form is `nport 3000 --subdomain myapp`.

Two lockfiles, one documented install path, and a bin that points at build output

The repository root holds `package-lock.json` and `pnpm-lock.yaml` side by side, while the requirements section asks for Node.js 20 or newer and npm 10 or newer, and the recommended install is npm:

bash
# Global installation
npm install -g nport

# Or use npx without installation
npx nport 3000 -s myapp

A git install is offered as the second route, `npm install -g git+https://github.com/tuanngocptn/nport.git`, and the announcement points at the same `server/` directory for anyone who wants to self-host. Two lockfiles in one tree means the build was captured by two package managers at different times, and only the npm one matches the documented commands.

The manifest is declared as an ES module with `main` pointing at `dist/index.js` and a single binary named `nport` pointing at the same file. `dist/` is not in the root listing, so the entry point is generated rather than committed. The scripts show how: `build` runs `node scripts/build.js`, `dev` runs the same script with `--watch`, `start` runs `node dist/index.js`, and a `postinstall` step runs `node scripts/postinstall.js`.

Version 2.1.6 is what the manifest declares and the newest tag. Tests run under vitest with `vitest run`, and both `lint` and `typecheck` are the same `tsc --noEmit` invocation.

Three runtime dependencies and no Cloudflare SDK

The dependency list is short enough to state exactly: axios at 1.13.2, chalk at 5.6.2 and ora at 9.0.0. That is the entire runtime set for a program that opens public HTTPS tunnels to a local port.

There is no Cloudflare API client, no tunnel binary and no transport library among them, even though the keyword list in the manifest advertises cloudflared alongside ngrok, localtunnel, proxy, port-forwarding and webhook-testing. The client is an HTTP caller with a spinner and coloured output; the tunnel work happens behind the backend it talks to, which is the same component whose shared quota produces error `10429`.

That division is also why the self-hosting instructions point at a directory rather than at a flag. Anyone who wants their own account has to run and operate the backend half, and the client half stays a three-package program.

The root layout also carries `CLIENT_SETUP.md`, a `server/` directory, `docs/`, `website/`, `scripts/`, `src/`, `tests/`, a vitest config, a CHANGELOG and a TODO, alongside `.claude/`, `.vscode/` and a CLAUDE.md.

The session banner counts down from four hours

The quick start prints what a successful tunnel looks like, and the banner includes a line that has nothing to do with features:

code
⏱️  Time:     4h remaining

A four hour countdown is the closest thing the page gives to a session limit, and it sits under a feature list that says no limits. Whether that is the enforced tunnel lifetime, the display refresh interval or a placeholder in an example captured from an early build is not stated anywhere, but the reader is left to assume the first reading, because the example is presented as real output.

The same block is cut off in the middle. It opens with a boxed NPORT banner, prints a spinner line, then the assigned URL `https://user-1234.nport.link`, then the countdown, then two connection steps, and the closing lines break off inside the text `⭐️ Drop a Sta`. So the one piece of output that shows the session's real shape is also the piece that stops mid-word.

The two checked steps are worth noting for what they imply about the connection: the first establishes the tunnel and the second enables compression.

MIT licensed, three tagged releases, and a homepage that changes scheme

Licensing is unambiguous: MIT in the repository record and MIT in the manifest's license field, with the author recorded as Nick Pham and one listed contributor, Eric Barch. Funding links point at GitHub Sponsors and a Buy Me a Coffee page.

Release cadence in the visible window is three tags: v2.1.4 on 2026-03-16, v2.1.5 on 2026-03-31 and v2.1.6 on 2026-08-03. The repository is not archived and its last recorded push is 2026-08-12, a few days after the newest tag, so the tree has moved past v2.1.6 without a further release. That is the state the v3.0.0 announcement describes as still being built for the rate limit problem.

One small inconsistency is worth recording for anyone scripting against it. The repository record lists the homepage as `http://nport.link`, while the manifest's homepage field says `https://nport.link`, and the README badge links to the bare domain. The default backend, by contrast, is given with its scheme as `https://api.nport.link`.

Editorial conclusion

NPort is a reasonable choice for a short-lived demo or a webhook callback while you are iterating, and the install path is short enough that trying it costs little. Three things to know before you wire it into anything scheduled. First, every tunnel start spends from one shared Cloudflare account's API quota, so a loop that opens and closes tunnels will rate-limit other users, and the documentation itself tells you to keep tunnels out of CI. Second, there is no client flag for your own Cloudflare credentials: the only supported way to escape the shared quota is to run the backend yourself from the `server/` directory and point the CLI at it with `--backend` or `--set-backend`. Third, the advertised session shape is not unlimited, since the sample banner shows a four hour countdown. If you need a stable URL for anything longer than an afternoon, self-hosting the backend is the part that matters, not the client.

Frequently asked questions

What does it mean when NPort reports Cloudflare error 10429?

The account-wide API request quota for the shared nport.link backend is exhausted, which happens because every default user goes through the same Cloudflare account. The page says to wait a minute or two and run the command again, to avoid starting tunnels in a tight loop or in CI since each start consumes API calls, and that the failure is not a problem on your machine.

How do I use NPort without the shared rate limit?

Run your own backend with your own Cloudflare account from the server/ directory, then point the client at it with nport 3000 --backend https://your-backend.com for one session, or use --set-backend to save the URL permanently. The default backend is https://api.nport.link.

What does NPort need to run?

Node.js 20.0.0 or newer and npm 10.0.0 or newer, both declared in the engines field of the manifest. The package is an ES module whose nport binary points at dist/index.js, and the build script is node scripts/build.js.

Does NPort give you a subdomain you choose?

Yes. Without a flag you get a generated name such as https://user-1234.nport.link, and nport 3000 -s myapp creates https://myapp.nport.link, with nport 3000 --subdomain myapp as the long form. The port argument defaults to 8080 if you leave it out.

What runtime libraries does NPort depend on?

Three: axios, chalk and ora. There is no Cloudflare SDK or tunnel binary among the dependencies, so the client talks to a backend over HTTP and the tunnel work happens on that side.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tuanngocptn-nport.svg)](https://hysenlabs.com/projects/tuanngocptn-nport)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/tuanngocptn-nport.svg)](https://hysenlabs.com/projects/tuanngocptn-nport)

Was this useful?