expose-localhost

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Expose Localhost

暴露本地服务

Expose a local service to the public internet using ngrok. Optionally add OAuth, OWASP protection, or rate limiting via Traffic Policy.
使用ngrok将本地服务暴露至公网。可通过Traffic Policy(流量策略)选择性添加OAuth认证、OWASP防护或速率限制。

Prerequisites

前置条件

  • ngrok CLI installed (
    ngrok
    command available)
  • Auth token configured (
    ngrok config add-authtoken <TOKEN>
    )
  • 已安装ngrok CLI(可执行
    ngrok
    命令)
  • 已配置认证令牌(执行
    ngrok config add-authtoken <TOKEN>

Workflow

工作流程

Step 1: Pre-flight & Configuration

步骤1:预检与配置

Silently verify ngrok is ready:
bash
ngrok config check
If auth token missing, tell user to run:
ngrok config add-authtoken <TOKEN>
(get token at https://dashboard.ngrok.com/get-started/your-authtoken)
Then ask all questions upfront before doing anything:
Before I expose your service, I need a few details:

1. **Port**: I see your app runs on port 3000. Is that correct?
2. **Domain**: Use your dev domain, or do you have a custom domain?
3. **Access control**: Open access, or require login (Google/GitHub/etc.)?
4. **Save config?**: One-time setup, or save for reuse?
Do NOT mention cloud endpoints, reserved domains, or internal endpoints — those are advanced concepts the user shouldn't need to think about.
Detecting the port: Check
package.json
scripts for
--port
,
.env
for
PORT=
,
docker-compose.yml
for port mappings.
Domains: Most ngrok accounts have a free static dev domain (e.g.,
something.ngrok-free.dev
). Running
ngrok http PORT
uses it automatically. Users can also provide a custom domain configured in the ngrok dashboard. Some accounts (especially new ones) may not have a dev domain yet — if ngrok fails with
ERR_NGROK_15013
, tell the user: "You don't have a dev domain yet. Claim your free one at https://dashboard.ngrok.com/domains — then we can try again."
If user requests OAuth, also ask: "Should only specific people be able to access it? I can restrict by email address or email domain."
After gathering answers, confirm and get a Y/n before proceeding.
静默验证ngrok是否就绪:
bash
ngrok config check
如果缺少认证令牌,请告知用户执行:
ngrok config add-authtoken <TOKEN>
(令牌获取地址:https://dashboard.ngrok.com/get-started/your-authtoken)
然后在执行任何操作前先收集所有必要信息
在为您暴露服务前,我需要了解几个细节:

1. **端口**:我检测到您的应用运行在3000端口,是否正确?
2. **域名**:使用您的开发域名,还是您有自定义域名?
3. **访问控制**:开放访问,还是需要登录验证(Google/GitHub等)?
4. **保存配置?**:仅单次使用,还是保存配置以便复用?
请勿提及云端点、预留域名或内部端点——这些是高级概念,无需用户考虑。
端口检测:检查
package.json
脚本中的
--port
参数、
.env
文件中的
PORT=
配置、
docker-compose.yml
中的端口映射。
域名说明:大多数ngrok账号拥有免费静态开发域名(例如:
something.ngrok-free.dev
)。执行
ngrok http PORT
会自动使用该域名。用户也可提供在ngrok控制台配置的自定义域名。部分账号(尤其是新注册的)可能尚未拥有开发域名——如果ngrok返回错误
ERR_NGROK_15013
,请告知用户:"您尚未拥有开发域名,请前往https://dashboard.ngrok.com/domains领取免费域名,之后我们可再次尝试。"
若用户请求OAuth认证,还需询问:"是否仅允许特定人员访问?我可以通过邮箱地址或邮箱域名进行限制。"
收集完所有信息后,请确认并获取用户的Y/n确认后再继续。

Step 2: Start the Tunnel

步骤2:启动隧道

No security (simplest)

无安全防护(最简模式)

bash
ngrok http {PORT} &
sleep 3
curl -s http://localhost:4040/api/tunnels | grep -o '"public_url":"[^"]*"' | head -1
With a specific domain, add
--url https://{DOMAIN}
.
bash
ngrok http {PORT} &
sleep 3
curl -s http://localhost:4040/api/tunnels | grep -o '"public_url":"[^"]*"' | head -1
若使用特定域名,添加
--url https://{DOMAIN}
参数。

With security (Traffic Policy)

带安全防护(Traffic Policy)

Create the traffic policy file first, then start ngrok with it.
OAuth-only (default when user requests auth):
yaml
on_http_request:
  - actions:
      - type: oauth
        config:
          provider: google
Replace
google
with the chosen provider (google, github, microsoft, gitlab, linkedin, twitch).
If the user requests OAuth, default to OAuth-only. Do NOT add OWASP or rate limiting unless explicitly asked — OAuth already blocks unauthenticated access.
OAuth with email restriction — use a separate rule with a CEL expression to deny non-matching emails. Do NOT add an
allow
field to the OAuth action.
Single email:
yaml
on_http_request:
  - actions:
      - type: oauth
        config:
          provider: google
  - expressions:
      - "actions.ngrok.oauth.identity.email != 'user@example.com'"
    actions:
      - type: deny
        config:
          status_code: 403
Email domain:
yaml
on_http_request:
  - actions:
      - type: oauth
        config:
          provider: google
  - expressions:
      - "!actions.ngrok.oauth.identity.email.endsWith('@your-company.com')"
    actions:
      - type: deny
        config:
          status_code: 403
Multiple emails — use
!(... in ['a@x.com', 'b@x.com'])
in the expression.
Open-access hardening (no auth, but wants protection):
yaml
on_http_request:
  - actions:
      - type: rate-limit
        config:
          name: default-rate-limit
          algorithm: sliding_window
          capacity: 200
          rate: "60s"
          bucket_key:
            - conn.client_ip
      - type: owasp-crs-request
        config:
          on_error: halt

on_http_response:
  - actions:
      - type: owasp-crs-response
        config:
          on_error: halt
After writing the policy file, start ngrok:
bash
ngrok http {PORT} --traffic-policy-file .ngrok/traffic-policy.yml &
sleep 3
curl -s http://localhost:4040/api/tunnels | grep -o '"public_url":"[^"]*"' | head -1
Add
--url https://{DOMAIN}
if using a specific domain.
先创建流量策略文件,再启动ngrok。
仅OAuth认证(用户请求认证时的默认配置):
yaml
on_http_request:
  - actions:
      - type: oauth
        config:
          provider: google
google
替换为用户选择的服务商(google、github、microsoft、gitlab、linkedin、twitch)。
若用户请求OAuth认证,默认使用仅OAuth模式。除非用户明确要求,否则请勿添加OWASP防护或速率限制——OAuth已可阻止未认证访问。
带邮箱限制的OAuth认证——使用单独规则配合CEL表达式拒绝不符合条件的邮箱。请勿在OAuth动作中添加
allow
字段。
单个邮箱限制:
yaml
on_http_request:
  - actions:
      - type: oauth
        config:
          provider: google
  - expressions:
      - "actions.ngrok.oauth.identity.email != 'user@example.com'"
    actions:
      - type: deny
        config:
          status_code: 403
邮箱域名限制:
yaml
on_http_request:
  - actions:
      - type: oauth
        config:
          provider: google
  - expressions:
      - "!actions.ngrok.oauth.identity.email.endsWith('@your-company.com')"
    actions:
      - type: deny
        config:
          status_code: 403
多个邮箱限制——在表达式中使用
!(... in ['a@x.com', 'b@x.com'])
开放访问加固(无认证,但需防护)
yaml
on_http_request:
  - actions:
      - type: rate-limit
        config:
          name: default-rate-limit
          algorithm: sliding_window
          capacity: 200
          rate: "60s"
          bucket_key:
            - conn.client_ip
      - type: owasp-crs-request
        config:
          on_error: halt

on_http_response:
  - actions:
      - type: owasp-crs-response
        config:
          on_error: halt
编写完策略文件后,启动ngrok:
bash
ngrok http {PORT} --traffic-policy-file .ngrok/traffic-policy.yml &
sleep 3
curl -s http://localhost:4040/api/tunnels | grep -o '"public_url":"[^"]*"' | head -1
若使用特定域名,添加
--url https://{DOMAIN}
参数。

Step 3: Handle Errors

步骤3:错误处理

If a traffic policy action fails due to plan limitations:
  1. Tell the user which specific action requires an upgrade
  2. Offer to remove that action from the policy and retry
  3. Do NOT suggest switching to cloud endpoints as a workaround
若因套餐限制导致流量策略动作失败:
  1. 告知用户具体哪个动作需要升级套餐
  2. 提议从策略中移除该动作并重试
  3. 请勿建议切换至云端点作为替代方案

Step 4: Persistent Configuration (If Requested)

步骤4:持久化配置(若用户要求)

Save these files to the project:
  • .ngrok/traffic-policy.yml
    — the policy (if security was configured)
  • .ngrok/expose.sh
    :
bash
#!/bin/bash
set -e
echo "Your service will be at: https://{DOMAIN}"
ngrok http {PORT} --url https://{DOMAIN} --traffic-policy-file .ngrok/traffic-policy.yml
Omit
--traffic-policy-file
if no policy. Omit
--url
if no specific domain.
Optionally add to
package.json
:
json
{ "scripts": { "tunnel": "bash .ngrok/expose.sh" } }
将以下文件保存至项目中:
  • .ngrok/traffic-policy.yml
    —— 流量策略文件(若配置了安全防护)
  • .ngrok/expose.sh
bash
#!/bin/bash
set -e
echo "Your service will be at: https://{DOMAIN}"
ngrok http {PORT} --url https://{DOMAIN} --traffic-policy-file .ngrok/traffic-policy.yml
若无策略文件,省略
--traffic-policy-file
参数。若无特定域名,省略
--url
参数。
可选添加至
package.json
json
{ "scripts": { "tunnel": "bash .ngrok/expose.sh" } }

Teardown

停止服务

bash
pkill ngrok
bash
pkill ngrok

Cloud Endpoints (Advanced)

云端点(高级功能)

Only use if the user explicitly needs a URL that persists after the agent stops (e.g., webhooks, long-lived integrations).
Requires an API key:
ngrok config add-api-key <KEY>
(get at https://dashboard.ngrok.com/api-keys)
  1. Reserve domain:
    ngrok api reserved-domains create --domain "{DOMAIN}"
  2. Create cloud endpoint with a traffic policy that includes
    forward-internal
    as the last action:
bash
ngrok api endpoints create --url "https://{DOMAIN}" --bindings public --traffic-policy "$(cat .ngrok/traffic-policy.yml)"
The traffic policy must end with:
yaml
- type: forward-internal
  config:
    url: https://{NAME}.internal
  1. Start the internal agent:
    ngrok http {PORT} --url https://{NAME}.internal
  2. Teardown:
    ngrok api endpoints delete {ENDPOINT_ID}
仅当用户明确需要在Agent停止后仍可访问的URL时使用(例如:Webhook、长期集成)。
需要API密钥:
ngrok config add-api-key <KEY>
(获取地址:https://dashboard.ngrok.com/api-keys)
  1. 预留域名:
    ngrok api reserved-domains create --domain "{DOMAIN}"
  2. 创建带流量策略的云端点,其中
    forward-internal
    需作为最后一个动作:
bash
ngrok api endpoints create --url "https://{DOMAIN}" --bindings public --traffic-policy "$(cat .ngrok/traffic-policy.yml)"
流量策略必须以以下内容结尾:
yaml
- type: forward-internal
  config:
    url: https://{NAME}.internal
  1. 启动内部Agent:
    ngrok http {PORT} --url https://{NAME}.internal
  2. 停止服务:
    ngrok api endpoints delete {ENDPOINT_ID}