pinggy-tunnel – skill DevOps & Hạ tầng cho agent AI
Tạo tunnel localhost qua SSH không cần cài đặt bằng Pinggy.
Cài skill pinggy-tunnel bằng một lệnh
Chọn công cụ bạn đang dùng, copy lệnh và dán vào terminal. Skill sẽ nằm trong thư mục skills của công cụ đó và sẵn sàng dùng ở phiên làm việc tiếp theo.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/pinggy-tunnel-ca8aa.tgz | tar xz -C ~/.claude/skills
Gọi trong Claude Code: /pinggy-tunnel – rồi mô tả công việc bạn muốn làm.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/pinggy-tunnel-ca8aa.tgz | tar xz -C ~/.codex/skills
Gọi trong Codex: $pinggy-tunnel – rồi mô tả công việc bạn muốn làm.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/pinggy-tunnel-ca8aa.tgz | tar xz -C ~/.hermes/skills
Gọi trong Hermes Agent: /pinggy-tunnel – rồi mô tả công việc bạn muốn làm.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/pinggy-tunnel-ca8aa.tgz | tar xz -C ~/.deepcode/skills
Gọi trong DeepSeek: /pinggy-tunnel – rồi mô tả công việc bạn muốn làm.
Nội dung SKILL.md
Nội dung SKILL.md gốc bằng tiếng Anh.
Pinggy Tunnel Skill
Expose a local service (dev server, webhook receiver, MCP endpoint, demo) to the public internet using a Pinggy SSH reverse tunnel. No daemon to install — the user's stock SSH client connects to a.pinggy.io:443 and Pinggy hands back a public HTTP/HTTPS URL.
Free tier: 60-minute tunnels, random subdomain, no signup. Pro tier ($3/mo) is an opt-in with a token.
When to Use
- User asks to "expose this locally", "share my dev server", "make this URL public", "tunnel port N", "get a public URL for a webhook"
- Need to receive a webhook callback during a local task (Stripe, GitHub, Discord, AgentMail)
- Sharing a one-off HTTP demo (MCP server, Ollama/vLLM endpoint, dashboard) with a remote party
- The host has SSH but no
cloudflared/ngrokbinary, and installing one would be overkill
If the host already has cloudflared configured, prefer the cloudflared-quick-tunnel skill — Cloudflare quick tunnels don't expire after 60 minutes.
Prerequisites
sshon PATH (ssh -V). Default on Linux, macOS, and Windows 10+. No other install.- A local service listening on
127.0.0.1:<port>before the tunnel starts. Pinggy will return URLs but they'll 502 until the local origin is up.
Optional:
PINGGY_TOKENenv var for paid Pro features (persistent subdomain, custom domain, multiple tunnels, no 60-minute cap). Free tier needs no credentials.
Quick Reference
# Plain HTTP/HTTPS tunnel for port 8000 (free tier)
ssh -p 443 -o StrictHostKeyChecking=no -o ServerAliveInterval=30 \
-R0:localhost:8000 [email protected]
# TCP tunnel (databases, raw SSH, etc.)
ssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:5432 [email protected]
# TLS tunnel (Pinggy can't decrypt — bring your own certs at origin)
ssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:443 [email protected]
# Basic auth gate (b:user:pass)
ssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \
"b:admin:[email protected]"
# Bearer token gate (k:token)
ssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \
"k:[email protected]"
# IP whitelist (w:CIDR)
ssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \
"w:203.0.113.0/[email protected]"
# Enable CORS + force HTTPS redirect
ssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \
"co+x:[email protected]"
# Pro tier (persistent URL, no 60-min cap)
ssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 "$PINGGY_TOKEN+a.pinggy.io"Procedure — Start a Tunnel and Get the URL
The model SHOULD use the terminal tool. The tunnel must stay alive for the duration of the share, so run it as a background process and parse the public URL from stdout.
1. Confirm a local origin is up
curl -sI http://127.0.0.1:8000/ | head -1
# expect HTTP/1.x 200 (or any non-connection-refused response)If nothing is listening yet, start it first (e.g. python -m http.server 8000 --bind 127.0.0.1). Pinggy will happily return a URL pointed at nothing — the user will see 502 until the origin comes up.
2. Launch the tunnel as a background process
Use terminal(background=True) and capture output to a logfile (Pinggy prints the URLs on stdout, then keeps the connection open):
LOG=~/.hermes/cache/scratch/pinggy-8000.log
nohup ssh -p 443 \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-R0:localhost:8000 [email protected] \
> "$LOG" 2>&1 &
echo $! > ~/.hermes/cache/scratch/pinggy-8000.pidStrictHostKeyChecking=no + UserKnownHostsFile=/dev/null skips the first-run host-key prompt. ServerAliveInterval=30 keeps the SSH session from getting torn down by an idle NAT.
3. Parse the URL out of the log
sleep 4
grep -oE 'https://[a-z0-9-]+\.[a-z]+\.pinggy\.link' ~/.hermes/cache/scratch/pinggy-8000.log | head -1Expected output looks like:
You are not authenticated.
Your tunnel will expire in 60 minutes.
http://yqycl-98-162-69-48.a.free.pinggy.link
https://yqycl-98-162-69-48.a.free.pinggy.linkHand the https://...pinggy.link URL to the user.
4. Verify
curl -sI https://<the-url>/ | head -3
# expect 200/302/whatever the local origin actually returnsIf you get 502 Bad Gateway, the SSH session is up but the local origin isn't listening — fix step 1 first.
5. Teardown
kill "$(cat ~/.hermes/cache/scratch/pinggy-8000.pid)"
# or, if the pid file got lost:
pkill -f 'ssh -p 443 .* free@a\.pinggy\.io'If you have a session_id from terminal(background=True), prefer process(action='kill', session_id=...).
Access Control via Username Keywords
Pinggy stacks control flags into the SSH username separated by +. Always quote the whole user@host argument when it contains a +:
| Keyword | Effect |
|---------|--------|
| b:user:pass | HTTP Basic auth gate |
| k:token | Bearer-token header gate (Authorization: Bearer <token>) |
| w:CIDR | IP whitelist (single IP or CIDR, repeatable) |
| co | Add Access-Control-Allow-Origin: * (CORS) |
| x:https | Force HTTPS — auto-redirect HTTP to HTTPS |
| a:Name:Value | Add request header |
| u:Name:Value | Update request header |
| r:Name | Remove request header |
| qr | Print a QR code of the URL to stdout (handy for mobile sharing) |
Combine freely: "b:admin:secret+co+x:[email protected]".
Web Debugger (optional)
Pinggy can mirror the inbound traffic to localhost:4300 for inspection. Add a local forward to the SSH command:
ssh -p 443 -L4300:localhost:4300 -R0:localhost:8000 [email protected]Then open http://localhost:4300 in a browser to see live request/response pairs.
Pitfalls
- 60-minute hard cap on the free tier. The SSH session terminates at the 60-minute mark; the URL goes dead. For longer shares, either use
PINGGY_TOKEN(Pro) or auto-restart with a shell loop (note that the URL changes on every restart for free-tier). - Free-tier URL is random and changes on restart. Don't bookmark it, don't paste it into a config file. Re-parse from the log each time.
- Concurrent free tunnels are limited to one per source IP. Starting a second tunnel from the same machine usually kills the first. Pro tier lifts this.
+in usernames must be quoted. Baressh ... b:admin:[email protected]works in bash but breaks under shells that treat+specially or when assembled programmatically. Always wrap in double quotes.- Don't tunnel anything sensitive without an access-control flag. A bare HTTP tunnel is reachable by anyone with the URL. Use
b:,k:, orw:for non-public services. process(action='log')may miss SSH banner output. Pinggy prints the URLs and then the SSH session goes interactive. Always redirect to a logfile andgrepthe file directly — same pattern ascloudflared-quick-tunnel.- Host-key prompt on first run. Default OpenSSH config asks the user to accept Pinggy's host key. Always pass
-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/nullfor unattended runs. - TCP and TLS tunnels return a
<subdomain>.a.pinggy.online:<port>pair, not an https URL. Parse with a different regex (tcp://and a port). Don't assume every Pinggy tunnel is HTTP. - Pro mode requires the token as the username, not a flag. Use
"$PINGGY_TOKEN+a.pinggy.io"(nofree@). With a token you can also add:persistentfor a stable subdomain — seepinggy.io/docs/.
Recipes
Composite patterns combining a local origin with a Pinggy tunnel. Each recipe is self-contained — start the origin, start the tunnel, parse the URL, hand it back to the user.
Recipe 1 — Receive a webhook callback
Use this when an external service (Stripe, GitHub, Discord, AgentMail, etc.) needs to POST to a publicly reachable URL during a local task.
# 1. Tiny capturing server: every request gets appended to ~/.hermes/cache/scratch/webhook-hits.log
cat >~/.hermes/cache/scratch/webhook-server.py <<'PY'
import http.server, json, datetime, pathlib
LOG = pathlib.Path("~/.hermes/cache/scratch/webhook-hits.log").expanduser()
class H(http.server.BaseHTTPRequestHandler):
def _capture(self):
n = int(self.headers.get("content-length") or 0)
body = self.rfile.read(n).decode("utf-8", "replace") if n else ""
rec = {"t": datetime.datetime.utcnow().isoformat(), "path": self.path,
"method": self.command, "headers": dict(self.headers), "body": body}
with LOG.open("a") as f: f.write(json.dumps(rec) + "\n")
self.send_response(200); self.send_header("content-type","application/json")
self.end_headers(); self.wfile.write(b'{"ok":true}\n')
def do_GET(self): self._capture()
def do_POST(self): self._capture()
def log_message(self,*a,**k): pass
http.server.HTTPServer(("127.0.0.1", 18080), H).serve_forever()
PY
nohup python ~/.hermes/cache/scratch/webhook-server.py >~… (nội dung đầy đủ có trong gói tải về)
Skill liên quan
- cloudflare-workers – Xây dựng và triển khai edge function với Cloudflare Workers và Wrangler. Dùng cho API…
- cloudformation – Triển khai tài nguyên AWS bằng template CloudFormation. Tạo stack, dùng nested stack và…
- cloudish – Triển khai Dockerfile, thư mục mã nguồn hoặc image có sẵn lên Cloudish dưới dạng…
- quantized-export – Xuất mô hình đã tinh chỉnh và đã được duyệt sang định dạng triển khai phù hợp…
- kubernetes-operator – Dùng khi xây dựng Kubernetes Operator — controller tùy chỉnh đối chiếu trạng thái CRD…
- kubernetes-operator – Dùng khi xây dựng Kubernetes Operator — controller tùy chỉnh đối chiếu trạng thái CRD…
- product-price-monitor – Theo dõi giá sản phẩm, chuyến bay hoặc tin rao bán; cảnh báo khi đạt mức mục tiêu.
- risk-metrics-calculation – Tính toán các chỉ số rủi ro danh mục đầu tư gồm VaR, CVaR, Sharpe, Sortino và phân tích…