开发时我们常常遇到这样的尴尬:本地写好的 Web 服务、API 或回调接口,只能通过 http://localhost:8000 访问,外网根本够不着。想在手机上调试、想给同事看个演示、想接收第三方平台的 Webhook 回调……都做不了。
ngrok 就是解决这个问题的“内网穿透”神器——它把本地端口映射成一个公网地址。而 pyngrok 是 ngrok 的 Python 封装库,它更进一步:自动下载并管理 ngrok 二进制文件,让你不用手动装 ngrok、不用记命令行参数,直接用 Python 代码就能开隧道。
它的特点:
- • 自带二进制管理:首次调用会自动下载对应平台的 ngrok,省去手动安装。
- • 纯 Python API:
ngrok.connect() 一行开隧道,返回对象可直接取公网地址。 - • 兼容 ngrok v2 / v3:默认使用 v3(当前主流)。
- • 附带命令行:安装后
ngrok 命令也可直接用,原生 CLI 功能全都有。
它非常适合本地开发调试、临时暴露服务、以及 Webhook 联调等场景。
一、安装
用 pip 安装即可:
pip install pyngrok
如果你用 conda:
conda install -c conda-forge pyngrok
先准备一个 authtoken
从 ngrok v3 开始必须认证:你需要去 ngrok 官网 免费注册一个账号,在控制台复制你的 authtoken(形如
2abc...xyz)。这一步是后面所有操作的前提。
最小示例
安装好,我们先在一个终端里起一个本地 HTTP 服务:
python -m http.server 8000
再新建一个 main.py,输入下面代码:
from pyngrok import ngrok
# 设置你的 authtoken(换成你自己的)
ngrok.set_auth_token("你的_AUTHTOKEN")
# 为本地 8000 端口开一条公网隧道
tunnel = ngrok.connect(8000)
print("公网地址:", tunnel.public_url)
运行脚本:
python main.py
终端会打印出类似 https://xxxx-xx-xx-xx-xx.ngrok-free.app 的地址。把它复制到浏览器打开,你就能从外网访问到本机的 8000 端口服务了。这就是 pyngrok 最直接的能力。
二、具体执行
本节把 pyngrok 的常用能力拆开讲:
- • 建立隧道(
connect() 与 NgrokTunnel)
2.1 配置 authtoken
有两种等价方式。其一,用 ngrok 官方 CLI 一次性写入配置文件:
ngrok config add-authtoken 你的_AUTHTOKEN
其二,在 Python 里设置(更推荐用于脚本/Colab):
from pyngrok import ngrok
ngrok.set_auth_token("你的_AUTHTOKEN")
set_auth_token() 会把 token 写进 ngrok 配置文件,之后就能使用更多特性(多个并发隧道、自定义域名等)。
小技巧:不要把 token 硬编码进代码,用环境变量读取更安全:
import os
from pyngrok import ngrok
ngrok.set_auth_token(os.environ["NGROK_AUTH_TOKEN"])
2.2 建立隧道:connect() 与 NgrokTunnel
ngrok.connect() 的概要签名如下:
ngrok.connect(addr=None, proto=None, name=None, pyngrok_config=None, **options) -> NgrokTunnel
参数说明:
- •
addr:本地地址,可以是端口号(8000 或 "8000")或 "主机:端口"。省略则默认 80。 - •
proto:协议,常用 "http"、"tcp"、"tls"。省略则默认 "http"。 - •
name:从 ngrok 配置文件里启动一个命名隧道。 - •
pyngrok_config:本次调用使用的配置(见 2.5),会覆盖默认值。 - •
**options:其余参数会被透传给 ngrok,如 domain、schemes 等。
它的返回值是一个 NgrokTunnel 对象,公网地址通过 .public_url 获取:
from pyngrok import ngrok
# 打开一个 HTTP 隧道,默认指向 80 端口
http_tunnel = ngrok.connect()
print(http_tunnel.public_url)
# https://xxxx.ngrok-free.app
print(http_tunnel.proto) # http
print(http_tunnel.config["addr"]) # http://localhost:80
# 打开一个 SSH(TCP)隧道
ssh_tunnel = ngrok.connect("22", "tcp")
print(ssh_tunnel.public_url)
# 从 ngrok 配置文件里启动命名隧道
named_tunnel = ngrok.connect(name="my-config-file-tunnel")
NgrokTunnel 的常用属性:
- •
config:包含 addr、inspect 等信息的字典。
2.3 选择协议与透传参数
由于 **options 会透传给 ngrok,你几乎可以用上 ngrok 的全部能力:
from pyngrok import ngrok
# 同时暴露 http 与 https
tunnel = ngrok.connect("8000", schemes=["http", "https"])
print(tunnel.public_url)
# 使用自定义域名(需账号支持)
tunnel = ngrok.connect(addr="9000", domain="my-app.ngrok.app")
# 给隧道加一层 Basic Auth 保护:用户名:密码
tunnel = ngrok.connect("8000, auth="user:pass")
""
# 负载均衡的 internal 端点
tunnel = ngrok.connect(
addr="9000",
domain="some-endpoint.internal",
pooling_enabled=True,
)
提示:Python 用下划线 pooling_enabled,pyngrok 会自动转换并传给 ngrok。
2.4 查看与管理隧道
from pyngrok import ngrok
# 1. 列出当前所有活动隧道
for t in ngrok.get_tunnels():
print(f"{t.name}: {t.public_url} -> {t.config['addr']}")
# 2. 关闭指定的某条隧道
tunnel = ngrok.connect("8000")
ngrok.disconnect(tunnel.public_url)
# 3. 关闭本项目下所有 ngrok 进程与隧道
ngrok.kill()
get_ngrok_process() 可以拿到 ngrok 进程对象,它暴露了 api_url(本地管理 API,通常是 http://127.0.0.1:4040)和 proc(底层进程句柄):
from pyngrok import ngrok
ngrok_process = ngrok.get_ngrok_process()
print("管理 API:", ngrok_process.api_url)
2.5 高级配置:PyngrokConfig
当你需要指定 ngrok 路径、区域、日志回调等,用
PyngrokConfig:
from pyngrok.conf import PyngrokConfig
from pyngrok import ngrok, conf
# 方式一:修改全局默认配置
conf.get_default().config_path = "/opt/ngrok/ngrok.yml" # 自定义配置文件
conf.get_default().region = "us" # 区域
conf.get_default().ngrok_version = "v3" # ngrok 版本
# 方式二:构造一个配置对象,按需传给 connect()
config = PyngrokConfig(
ngrok_path="/usr/local/bin/ngrok", # 指定 ngrok 二进制位置
region="us",
startup_timeout=15, # 启动超时(秒)
max_logs=100,
)
tunnel = ngrok.connect("8000", pyngrok_config=config)
PyngrokConfig 常用参数:ngrok_path、config_path、auth_token、region、log_event_callback、startup_timeout、max_logs、request_timeout、ngrok_version。
重要顺序:如果你自定义了 config_path,请先设置 config_path,再调用 set_auth_token(),否则 token 会被写进默认配置文件,导致“设置了却不生效”。
三、优化处理
基础用法掌握后,我们来看几个真实场景里的关键点。
3.1 保活隧道(脚本退出即断线)
这是新手最容易踩的坑:隧道只在 Python 进程存活期间有效
。如果脚本跑完就退出,隧道立刻断开。对于需要常驻的脚本,要阻塞在 ngrok 进程上:
from pyngrok import ngrok
ngrok.set_auth_token("你的_AUTHTOKEN")
tunnel = ngrok.connect("8000")
print(f"隧道已建立: {tunnel.public_url}")
ngrok_process = ngrok.get_ngrok_process()
try:
# 阻塞,直到用户按下 Ctrl+C
ngrok_process.proc.wait()
except KeyboardInterrupt:
print("\n正在关闭隧道……")
ngrok.kill()
3.2 用日志回调实时观测
通过给 PyngrokConfig 传 log_event_callback,可以实时拿到 ngrok 的运行日志,便于调试:
from pyngrok import ngrok
from pyngrok.conf import PyngrokConfig
def on_log(log):
# log 对象包含 level、msg 等字段
print(f"[ngrok] {log.line} {log.lvl}: {log.msg}")
config = PyngrokConfig(log_event_callback=on_log)
ngrok.set_auth_token("你的_AUTHTOKEN")
tunnel = ngrok.connect("8000", pyngrok_config=config)
print("公网地址:", tunnel.public_url)
3.3 实战:一行代码暴露本地 Flask 应用
from flask import Flask
from pyngrok import ngrok
app = Flask(__name__)
@app.route("/")
def index():
return "Hello from Flask, exposed via ngrok!"
if __name__ == "__main__":
ngrok.set_auth_token("你的_AUTHTOKEN")
# 为本地 5000 端口开隧道
tunnel = ngrok.connect("5000")
print("公网地址:", tunnel.public_url)
# app.run 会阻塞,保持进程存活,隧道也就一直在线
app.run(port=5000)
执行结果
四、「注意事项」
1、必须配置 authtoken:ngrok v3 起强制认证,未设置会报认证失败。用 ngrok config add-authtoken 或 ngrok.set_auth_token() 配置。
2、隧道随进程退出而关闭:Python 进程结束,隧道立即断开;常驻脚本需用 proc.wait() 阻塞保活。
3、免费版有限制:公网地址随机且每次重启会变,并有会话时长与请求速率限制;固定/自定义域名通常需要付费套餐(具体以 ngrok 官网当前政策为准)。
4、首次调用会自动下载 ngrok:pyngrok 会把二进制下载到默认路径;在离线或受限网络环境中会失败,可手动放置并用 ngrok_path 指定。
5、config_path 与 token 的顺序:自定义配置文件时,务必先设 config_path 再 set_auth_token,否则 token 写入错误文件。
6、这会真的把服务暴露到公网:隧道等于公开入口,务必加 auth="user:pass" 等保护,用完及时
ngrok.kill()。