expose-localhost
Expose a local service to the public internet using ngrok. Starts a tunnel, optionally adds OAuth or WAF via Traffic Policy. Use when asked to expose, tunnel, share, or make a local service publicly accessible.
What this skill does
# Expose Localhost
Expose a local service to the public internet using ngrok. Optionally add OAuth, OWASP protection, or rate limiting via Traffic Policy.
## Prerequisites
- ngrok CLI installed (`ngrok` command available)
- Auth token configured (`ngrok config add-authtoken <TOKEN>`)
## Workflow
### Step 1: Pre-flight & Configuration
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.
### Step 2: Start the Tunnel
#### 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}`.
#### With security (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 != '[email protected]'"
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 ['[email protected]', '[email protected]'])` 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.
### Step 3: Handle Errors
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
### Step 4: Persistent Configuration (If Requested)
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" } }
```
## Teardown
```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
```
3. Start the internal agent: `ngrok http {PORT} --url https://{NAME}.internal`
4. Teardown: `ngrok api endpoints delete {ENDPOINT_ID}`
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.