Skip to main content

weft-public-address

Read when a trigger needs the internet to reach weft (a route, a provider that pushes its events), when the user asks about a public URL or a tunnel, or when activation fails with "needs your weft to be reachable from the internet": what the error means, walking the user through ./setup.sh --public-url, the dial-out alternative, named tunnels, and the refusals that come from Cloudflare or Google rather than weft; and when the user wants other people to reach the project's site, hosting it from this computer behind an address of theirs: the Cloudflare login, the tunnel, starting the site and the tunnel, restarting them after a reboot, and listing and stopping what this machine is hosting.

Source facts

Repository
WeaveMindAI/weft
Last source activity
October 25, 2026 at 13:40
Detected SKILL.md language
English
Stars
2,025
Forks
223

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
weft-public-address
description
Read when a trigger needs the internet to reach weft (a route, a provider that pushes its events), when the user asks about a public URL or a tunnel, or when activation fails with "needs your weft to be reachable from the internet": what the error means, walking the user through ./setup.sh --public-url, the dial-out alternative, named tunnels, and the refusals that come from Cloudflare or Google rather than weft; and when the user wants other people to reach the project's site, hosting it from this computer behind an address of theirs: the Cloudflare login, the tunnel, starting the site and the tunnel, restarting them after a reboot, and listing and stopping what this machine is hosting.
# A public address Webhook-style triggers (a `Route`, a Drive watch, a Slack app installed in other workspaces) need the runtime reachable from the internet. Polling triggers (Telegram, email, sheets, RSS, cron) and everything local work without one. **The error, verbatim.** When a project with a dial-in trigger is activated on a weft the internet cannot reach, activation refuses with this, and a trigger already on stops with it when it next has to make its subscription again: > this trigger needs '<service>' to deliver events TO your weft, which > requires your weft to be reachable from the internet, and it is not. If > you accept making its public trigger surface reachable, rerun > `./setup.sh --public-url`, then `weft activate`, or, when the trigger is > already on, turn it off and on again (`weft deactivate --trigger <name>`, > then `weft activate --trigger <name>`); or use a connection that supports dialing > out (your own provider app), where the service offers one. See > https://weavemindai.github.io/weft/connections/events.html If you see that, or a user pastes it, this is the cause and nothing else. It is not a broken credential, a wrong path, or a bad subscription. Say so in one sentence before doing anything else, because the wording sends people hunting through their provider settings. **Walking a user through it.** The command is `./setup.sh --public-url`, always. Never `weft daemon start --public-url`: it exists, but every message weft prints names setup.sh, and the user should be typing the same thing the tool told them. Steps: 1. Say what it will do: open a Cloudflare quick tunnel so the provider can reach their machine, and expose only the event, signal, file-link and OAuth-callback routes. The management API stays unreachable. The book's [public address page](https://weavemindai.github.io/weft/build/public-address.html) lists the exact routes; offer it, do not paste it. 2. Get their consent before running it, because it makes a surface on their machine reachable from the internet. This is one of the `ask`-first moves. 3. Run `./setup.sh --public-url`, then `weft daemon status` to read back the hostname it minted. 4. If `weft status` shows the trigger off, run `weft activate`. If it is already on, take it down and up: `weft deactivate --trigger <node>`, then `weft activate --trigger <node>`. If the same error comes back, the transport was never the problem; go and read the trigger's own metadata for which transports its connection actually supports. **The alternative, and prefer it when it exists.** Several services can dial out instead. For Slack, pasting an app-level token with `connections:write` on the connection switches it to Socket Mode and drops the public-address requirement entirely. Offer that first: it needs no tunnel and nothing on the user's machine becomes reachable. **A quick tunnel's hostname changes** whenever the tunnel restarts, so any URL the user registered by hand at a provider goes stale. If they are registering webhook URLs anywhere, they want the named-tunnel setup (`WEFT_PUBLIC_TUNNEL_TOKEN` plus `WEFT_PUBLIC_TUNNEL_HOSTNAME`, both required, hostname HTTPS with no port or path), which is on the same book page. **Google Drive has a second requirement** on top of the address: it must be on a domain verified in the app's Google console, or Google refuses to create the watch. That refusal comes from Google, not weft, and no amount of tunnel work fixes it. **A `403` carrying `error code: 1010`** on a file link is Cloudflare's Browser Integrity Check refusing the client (Python's `urllib` is one it refuses), never weft. The fix is a Cloudflare configuration rule on the user's side, and the book's public address page walks through it. ## Hosting the site from this computer When the user wants other people to reach the project's site and there is no cloud install yet, you offer this before the cloud, in words like these: "Putting it on the cloud is a bigger step. Do you want to try it from your computer first? It stays online while your computer is on, at an address of yours that I set up, and it is fine for a handful of people at once. When that gets tight, we move it to the cloud." Then add how many people it can really carry, worked out from the program's heaviest job: a program that renders one video at a time serves a few people working at once and many more just browsing. With their yes, you do every step yourself. Their part is installing `cloudflared` (`cloudflared --version` says whether it is there) and having a Cloudflare account with a domain on it. This is the site's own address. The site's server still calls weft on this machine, so weft itself needs no public address for it. The exception is a page that holds a socket open or puts a link straight at weft in the browser: then the browser has to reach weft too, which is the public address at the top of this page. 1. **Log in.** `cloudflared tunnel login` prints a link and then waits for the user to use it, and your shell tool hands you a command's output only once it ends, so start it detached: `mkdir -p .hosting`, then `nohup cloudflared tunnel login > .hosting/login.log 2>&1 &`, and read the link in `.hosting/login.log`. Hand the user that link and nothing else, no tutorial, and carry on once `~/.cloudflared/cert.pem` exists. That goes for any tool that signs in through a link or a code: you run the command, the user only clicks. Never read a token out of `cert.pem` to call Cloudflare yourself; the `cloudflared` commands below are all you need. 2. **Ask which address.** The subdomain, and which domain if their account holds several. 3. **Make the tunnel and its address.** `cloudflared tunnel create <project name>` prints the tunnel's id and writes its credentials to `~/.cloudflared/<id>.json`. Then `cloudflared tunnel route dns <project name> <sub>.<domain>`. 4. **Write its config** into `<project>/.hosting/tunnel.yml` (`<project>` is the project folder's absolute path, here and in step 6, so the running tunnel's command line names its project), and add `.hosting/` to the project's `.gitignore`: ```yaml tunnel: <id> credentials-file: <home>/.cloudflared/<id>.json ingress: - hostname: <sub>.<domain> service: http://localhost:<port> - service: http_status:404 ``` `<port>` is a free port you pick for the site. `cloudflared tunnel --config .hosting/tunnel.yml ingress validate` answers `OK` when the file is right. 5. **Build the site and start it, detached.** `pnpm run build` in `front/`, then from `front/`: `PORT=<port> ORIGIN=https://<sub>.<domain> nohup node --env-file=.env build > ../.hosting/site.log 2>&1 & echo $! > ../.hosting/site.pid`. `ORIGIN` tells the server the address people reach it at; without it, a form post through the tunnel is refused as cross-site. A site on BetterAuth also takes `BETTER_AUTH_URL=https://<sub>.<domain>` on the same line, so BetterAuth takes the public address as its own (`baseURL`, which it otherwise guesses from each request). A site whose pages hold a socket or link straight at weft also takes `WEFT_PUBLIC_URL=<weft's public address>` there, once `./setup.sh --public-url` has given weft one: `front/.env` says `http://127.0.0.1:14111`, which no other computer reaches. 6. **Start the tunnel, detached.** From the project folder: `nohup cloudflared tunnel --config <project>/.hosting/tunnel.yml --pidfile <project>/.hosting/tunnel.pid run > .hosting/tunnel.log 2>&1 &` (the two flags go before `run`, which refuses them after it). 7. **Check it answers.** `curl -sS -I https://<sub>.<domain>/` shows the status line. A fresh DNS record can take a minute; `cloudflared tunnel info <project name>` says whether the tunnel is connected, and the two logs in `.hosting/` say what went wrong if it is not. 8. **Tell the user** the address, that it is online only while this computer is on and awake, and what to do after a restart: weft comes back on its own (`weft daemon status` says so), the tunnel, its address and its config stay, and only the site and the tunnel are started again, with the two commands of steps 5 and 6. Offer to do it for them when they ask. **What this machine is hosting.** If the user asks what is running, or before you start another site, look: `pgrep -a cloudflared` on Linux (`pgrep -lf cloudflared` on macOS) lists every tunnel running here with the config it was started with, whose path names its project; `ss -ltnp` on Linux (`lsof -iTCP -sTCP:LISTEN -n -P` on macOS) lists the ports listening and the process behind each; each project hosted this way has its pid files in `.hosting/`. `cloudflared tunnel list` shows every tunnel of the account and whether it is connected. To stop one, `kill` the pid from its project's `.hosting/site.pid` and `.hosting/tunnel.pid`, or the one the listing showed, never `pkill -f`, whose pattern matches your own shell too. Stopping a site that belongs to another project is the user's call: ask first, naming it. **Moving that name to a cloud install.** If the user wants the name this machine hosts at to become a cloud install's domain, the tunnel's record on it (a CNAME to `<tunnel id>.cfargotunnel.com`) has to go before the cloud's `A` record is made. You delete it through the Cloudflare API, the way the weft-deploying skill sets the record ("A name instead of the install's own address"), never with `cloudflared`. The tunnel itself can stay, or be pointed at another name with `cloudflared tunnel route dns`.
View on GitHub