Loading...
Loading...
Expose a local service to the public internet using ngrok. Starts a tunnel, optionally adds OAuth or WAF via Traffic Policy. Handles HTTP services and raw TCP (SSH, RDP, databases). Use when asked to expose, tunnel, share, or make a local service publicly accessible, or to reach a machine that has no public IP. Also covers sharing work-in-progress with a specific person and the dev-server quirks that break a shared preview.
npx skill4agent add ngrok/skills expose-localhostngrokngrok config add-authtoken <TOKEN>ngrok config checkngrok config add-authtoken <TOKEN>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?package.json--port.envPORT=docker-compose.ymlsomething.ngrok-free.devngrok http PORTERR_NGROK_15013ngrok http {PORT} &
sleep 3
curl -s http://localhost:4040/api/tunnels | grep -o '"public_url":"[^"]*"' | head -1--url https://{DOMAIN}on_http_request:
- actions:
- type: oauth
config:
provider: googlegoogleallowon_http_request:
- actions:
- type: oauth
config:
provider: google
- expressions:
- "actions.ngrok.oauth.identity.email != 'user@example.com'"
actions:
- type: deny
config:
status_code: 403on_http_request:
- actions:
- type: oauth
config:
provider: google
- expressions:
- "!actions.ngrok.oauth.identity.email.endsWith('@your-company.com')"
actions:
- type: deny
config:
status_code: 403in - expressions:
- "!(actions.ngrok.oauth.identity.email in ['a@x.com', 'b@x.com'])"
actions:
- type: deny
config:
status_code: 403on_http_request:
- actions:
- type: basic-auth
config:
credentials:
- "reviewer:{PASSWORD}"restrict-ipson_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: haltngrok 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}references/TROUBLESHOOTING.md.ngrok/traffic-policy.yml.ngrok/expose.sh#!/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--urlpackage.json{ "scripts": { "tunnel": "bash .ngrok/expose.sh" } }pkill ngrokngrok tcpngrok httpngrok tcp {PORT} &
sleep 3
curl -s http://localhost:4040/api/tunnels | grep -o '"public_url":"[^"]*"' | head -1tcp://1.tcp.ngrok.io:12345# local sshd on port 22, reached through the address above
ssh -p 12345 {USER}@1.tcp.ngrok.io22338954323306ngrok api reserved-addrs create --description "SSH for {NAME}" --region us
ngrok tcp {PORT} --url tcp://{ADDR}on_tcp_connectrestrict-ipson_tcp_connect:
- actions:
- type: restrict-ips
config:
enforce: true
allow:
- 203.0.113.0/24ngrok tcp {PORT} --traffic-policy-file .ngrok/traffic-policy.ymlgw_reserve_domaingw_create_cloud_endpointdelete_resourcengrok config add-api-key <KEY>ngrok-surfacesngrok api reserved-domains create --domain "{DOMAIN}"forward-internalngrok api endpoints create --url "https://{DOMAIN}" --bindings public --traffic-policy "$(cat .ngrok/traffic-policy.yml)"- type: forward-internal
config:
url: https://{NAME}.internalngrok http {PORT} --url https://{NAME}.internalngrok api endpoints delete {ENDPOINT_ID}secure-endpointreceive-webhooksrun-mcp-gatewayprovision-sandbox-accessERR_NGROK_*troubleshoot-ngrokngrok-setupngrok-enginengrok-surfaces