Skip to main content

yonder

your site, over yonder

CI Latest release npm PyPI Go reference Go version Node.js Platforms Downloads Stars Last commit Open issues Conventional Commits License: MIT

yonder lets you open a website running on your own computer (localhost) from your phone, your iPad, or a friend's laptop on the same network. It can also share a file or a whole folder, and let the other device send files back. One command prints a link and a QR code. Nothing needs to be installed on the other device.

yonder demo

Contents: Install · Quick start · Usage · Share files · How it works · Is it safe? · Known limitations · Firewalls · WSL · Documentation

Install

macOS / Linux, any distro

curl -fsSL https://raw.githubusercontent.com/dpologdvinity/yonder/master/install.sh | sh

The script checks the download's SHA-256 before installing. Set YONDER_VERSION=0.5.0 to install a specific version, or YONDER_INSTALL_DIR to choose the folder.

Homebrew (macOS and Linux)

brew install dpologdvinity/tap/yonder

Debian / Ubuntu (apt)

sudo curl -fsSLo /usr/share/keyrings/yonder.gpg https://dpologdvinity.github.io/packages/yonder.gpg
echo "deb [signed-by=/usr/share/keyrings/yonder.gpg] https://dpologdvinity.github.io/packages/apt ./" | sudo tee /etc/apt/sources.list.d/yonder.list
sudo apt update && sudo apt install yonder

Fedora / RHEL (dnf)

sudo curl -fsSLo /etc/yum.repos.d/yonder.repo https://dpologdvinity.github.io/packages/yonder.repo
sudo dnf install yonder

Arch Linux (pacman)

curl -fsSL https://dpologdvinity.github.io/packages/yonder.asc | sudo pacman-key --add -
sudo pacman-key --lsign-key 282804EB5779EA7EFFCF8308097AF7F74B2F93E5
printf '\n[yonder]\nServer = https://dpologdvinity.github.io/packages/arch/$arch\n' | sudo tee -a /etc/pacman.conf
sudo pacman -Sy yonder

Windows (Scoop)

scoop bucket add yonder https://github.com/dpologdvinity/scoop-bucket
scoop install yonder

npm / yarn / pip

npm install -g yonder-cli     # or: yarn global add yonder-cli
pip install yonder-cli        # or: uv tool install yonder-cli

Go

go install github.com/dpologdvinity/yonder@latest

Or download a binary, .deb, .rpm or Arch package from Releases. Every release lists the SHA-256 of each file in checksums.txt.

Quick start

  1. Start your site as usual, for example on port 3000.
  2. Run yonder 3000.
  3. Scan the QR code with the other device, or type the link it prints into a browser.
  4. Press Ctrl-C when you are done. The link stops working at once.
$ yonder 3000
yonder: sharing localhost:3000

  http://192.168.1.20:13000/?yonder=…
  <QR code>

Only people with this link or QR code can open it.

14:03:09  device connected  192.168.1.42
14:03:09  GET /  200  192.168.1.42

The other device must be on the same network as your computer. If it cannot connect, see Known limitations and Firewalls.

Usage

yonder <port>               share the site running on localhost:<port>
yonder <path>               share a file or a folder
yonder <folder> --upload    also let other devices send files into the folder
yonder <target> --open      share without the secret token (trusted networks only)
yonder <target> --for 30m   stop sharing after 30 minutes (also 2h, 1d; at most 7d)
yonder <target> --approve   allow each new device yourself, at the terminal
yonder <target> --public    share over the internet (needs cloudflared)
yonder <target> --listen N  use N as the public port
yonder --version            print the version
Option What it does
--listen N Uses port N for other devices. By default yonder uses the shared port plus 10000 (3000 becomes 13000), or 18000 when sharing files, so the link keeps the same port across restarts. If that port is busy, yonder picks a free one. With --listen, a busy port is an error.
--for TIME Stops sharing after TIME, such as 90s, 30m, 2h or 1d (more than zero, at most 7d). yonder prints when the link stops working, and at that time it says so and exits. The end time is checked against the clock on the wall, so a laptop that sleeps does not extend the link. Works with every other option.
--approve Asks you at the terminal before each new device is let in. See Approve each device. Needs the token, so it cannot be combined with --open.
--public Also shares over the internet through a Cloudflare quick tunnel. See Share over the internet. Sets --for 1h and --approve unless you choose otherwise. Cannot be combined with --open.
--no-approve With --public: let anyone with the link in without asking you.
--open Turns the secret token off. Anyone on the network can open the link.
--upload Lets other devices send files into a shared folder. Folders only.
--version, --help Print the version, or the usage text.

The terminal shows one line when a device first connects, and one line per request with the time, method, path, status and visitor address.

yonder runs a small proxy in front of your dev server, so you do not need to change its configuration:

  • It works with servers that only listen on 127.0.0.1 or ::1.
  • It rewrites the Host and Origin headers, so servers that check them (Vite, webpack, Next.js) accept the request.
  • Hot reload keeps working: WebSockets and server-sent events pass through.

Approve each device

On a network you do not fully trust, the link can leak: someone can photograph the QR code, or read the address over a shoulder. --approve adds a second lock. A device that opens the link waits on a page that reloads by itself, and you decide at the terminal:

$ yonder 3000 --approve
...
Allow Safari on an iPhone at 192.168.1.42 to open this? [y/N] y
Allowed.
  • Answer y or yes to allow. Anything else, including Enter, refuses. A refused device stays refused until yonder restarts.
  • A device is a browser, not an address, so two people on the same Wi-Fi are asked about separately. Your own phone's browser is asked once; later visits go straight in.
  • At most 10 devices can wait at once, and at most 2 from the same address, so one visitor cannot use up the places. A device whose waiting page is closed gives up its place after a minute.
  • Anything you typed before a question appeared is thrown away, so a stray key cannot answer a question you have not seen.
  • It needs a terminal to ask on, and yonder must be running in the foreground of it. It does not work with input redirected from a file, or with yonder ... &.
  • Combine it with --for to share for a limited time, with each person approved: yonder 3000 --for 1h --approve.

Share files

yonder ./photos        # a folder: the phone gets a list of files to tap and download
yonder notes.pdf       # one file: nothing else in its folder is reachable

The link, QR code and token work the same as when sharing a port.

  • Hidden files and folders (.env, .git, .ssh, anything starting with .) are never listed or served.
  • Symlinks inside the shared folder are skipped, and .. cannot reach outside it.
  • Folder pages show the first 5000 entries, alphabetically, with folders first. A subfolder page has a ../ link to go back up.
  • Share a dedicated folder, not your home directory.
  • Add --upload to let the other device send files into the folder: the page gets an Upload button (on a phone it opens the photo picker or Files). Existing files are never overwritten (photo (1).jpg), folder parts of a name are dropped (../../x.txt is saved as x.txt), hidden names are refused, and one upload is capped at 4 GB. Uploads are off unless you pass the flag. With uploads on, shared pages cannot run script (see Is it safe?).
  • A folder named like a number is a port to yonder: use yonder ./3000.

Share over the internet

--public shows a second link that works from anywhere, for example a client on mobile data. yonder starts cloudflared and uses a free Cloudflare "quick tunnel", which needs no account. Install cloudflared first (brew install cloudflared, or see the link); yonder never downloads it for you.

$ yonder 3000 --public
  Public link:     https://example-words.trycloudflare.com/?yonder=...
  On your network: http://192.168.1.20:13000/?yonder=...

Because anyone on the internet who gets the link can try it, --public is stricter by default:

  • The link stops after one hour (--for changes this, up to 7d).
  • --approve is on: you see the visitor's address and country and answer y or n. --no-approve turns it off.
  • --open is refused.
  • Visitors who come through the tunnel get Secure cookies. The tunnel points at its own port, which only programs on your computer can reach; the link on your network stays open as usual, so anyone on your network who has the link still needs your approval too.
  • If you refuse a device, that visitor address is blocked until you stop yonder. Several people behind one shared address (an office, a phone carrier) are blocked together.

Know the limits:

  • Cloudflare carries your traffic and can read it. Do not share secrets this way.
  • Quick tunnels are for testing: no uptime promise, at most 200 requests at once (more get a 429), no server-sent events, and the address changes on every run. Large request bodies (uploads of about 100 MB or more) may be refused by Cloudflare.
  • Link previews (iMessage, Slack, Discord) fetch the link and appear as a device to approve. Refuse them.
  • People who come through the tunnel do not get a "device connected" line; their requests appear in the log with their real address.
  • If yonder is killed without a chance to clean up (kill -9, a crash of the computer), cloudflared may keep running with nothing behind it. It serves nothing, but you can stop it with pkill cloudflared.

How it works

yonder is one program with no dependencies on the other device. It opens a server on all of your network interfaces and puts two things in front of what you share: the access gate and a request log.

phone ──▶ your computer, port 13000 ──▶ log ──▶ access gate ──┬──▶ proxy ──▶ your dev server (localhost:3000)
                                                              └──▶ file server ──▶ the shared folder
  • The access gate only lets a request through if it carries the secret token: in the link on the first visit, in a cookie after that.
  • The proxy forwards the request to your dev server and rewrites headers so the dev server believes the request came from localhost.
  • The file server lists and serves a folder, and receives uploads, using only operating-system calls that cannot leave that folder.

ARCHITECTURE.md explains each part, the security design, and why it was built this way.

Is it safe?

The link and QR code carry a secret token. Anyone without it gets a 403 and never reaches your app. The first visit swaps the token for a cookie, so it disappears from the address bar. Every restart makes a new token, which cuts off old links. Only the one port, file or folder you name is shared.

  • --open turns the token off. Use it only on networks you trust.
  • yonder speaks plain HTTP. On open (passwordless) Wi-Fi, or on WPA2 Wi-Fi with a shared password, others on the network can capture traffic and copy the token or cookie. Avoid sharing private data there. Enterprise Wi-Fi with per-user logins and WPA3 protect each device's traffic.
  • With --upload, files that are served carry a sandbox policy, so a web page someone uploaded cannot run script on your computer's address. This also means an HTML site shared from an upload-enabled folder will not run its scripts.
  • Stop sharing with Ctrl-C, or share for a limited time with --for.
  • --approve makes a leaked link useless on its own: nobody gets in until you say so.
  • --public sends traffic through Cloudflare, which can read it. See Share over the internet.

To report a vulnerability, see SECURITY.md.

Known limitations

  • Your app's own code may hardcode localhost. A frontend calling an API at http://localhost:8080 fails on the phone, because there localhost is the phone. Use relative API URLs or your dev server's proxy.
  • Response bodies are not rewritten. Absolute http://localhost:<port> links inside HTML or JS stay broken.
  • http://localhost counts as a secure context; http://192.168.x.x does not. Service workers, camera, geolocation, clipboard and crypto.subtle do not work on the other device yet.
  • Guest, campus and café networks sometimes block device-to-device traffic. If the other device cannot connect, try a phone hotspot.
  • The link on your network only works on private networks (10.x, 172.16-31.x, 192.168.x). Some networks give every computer a public address; there yonder stops with a message instead of putting your site on the internet. Only --public shares beyond your network, and only through its tunnel.
  • Cookies do not include the port, so another web service on the same IP address receives yonder's cookie.

Firewalls

The first time yonder listens for connections, your OS may block or ask:

  • Windows: allow yonder.exe in the Windows Defender Firewall prompt.
  • macOS: allow incoming connections when the application firewall asks.
  • WSL (mirrored mode): the Hyper-V firewall blocks inbound traffic to WSL by default, so the other device times out. See the WSL section below.

If the other device cannot connect, watch yonder's output. No device connected line means the connection never reached yonder: a firewall or the network dropped it.

WSL

In WSL's default NAT mode, other devices cannot reach WSL at all; yonder prints a hint when it detects this. Either set networkingMode=mirrored under [wsl2] in %UserProfile%\.wslconfig and run wsl --shutdown, or run the Windows build, yonder.exe.

In mirrored mode, open yonder's port once in an admin PowerShell. For yonder 8000 the port is 18000:

New-NetFirewallHyperVRule -Name yonder -DisplayName yonder -Direction Inbound -VMCreatorId '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}' -Protocol TCP -LocalPorts 18000
New-NetFirewallRule -DisplayName yonder -Direction Inbound -Protocol TCP -LocalPort 18000 -Action Allow -Profile Any

Remove them later with Remove-NetFirewallHyperVRule -Name yonder and Remove-NetFirewallRule -DisplayName yonder.

Documentation

Document What is in it
ARCHITECTURE.md How yonder is built: components, request flow, security design, decisions, testing and releases
CONTRIBUTING.md Set up a development environment, run the checks, and send a change
SECURITY.md How to report a vulnerability, and what yonder does and does not protect against
CHANGELOG.md What changed in each release

License

MIT. See LICENSE.

Metadata

Release files for yonder-cli 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for yonder-cli 0.6.0
File
yonder_cli-0.6.0-py3-none-win_arm64.whl Python 3 none Windows ARM64 Details
yonder_cli-0.6.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
yonder_cli-0.6.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_1_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64, Linux musl 1.1+ x86-64 Details
yonder_cli-0.6.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64, Linux musl 1.1+ ARM64 Details
yonder_cli-0.6.0-py3-none-macosx_12_0_x86_64.whl Python 3 none macOS 12.0+ x86-64 Details
yonder_cli-0.6.0-py3-none-macosx_12_0_arm64.whl Python 3 none macOS 12.0+ ARM64 Details

Total release size: 23.8 MB

Release files / yonder_cli-0.6.0-py3-none-win_arm64.whl

Download URL yonder_cli-0.6.0-py3-none-win_arm64.whl
Size 3.8 MB
Tags Python 3 Windows ARM64
SHA-256 checksum
How to use checksums
081f6af1c53c9718eafbb278fc9291863e8bbbce29cc109e64aee3f57d5f7deb
BLAKE2b-256 checksum
How to use checksums
c0d9847e06d03844f74b547a14571bbb38b5b429ac97a71089a7d013baca670a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / yonder_cli-0.6.0-py3-none-win_amd64.whl

Download URL yonder_cli-0.6.0-py3-none-win_amd64.whl
Size 4.2 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
018dedcc36d1d4c71cf82b21ac1fb71e9f8f4818d08b488c1004990802d00168
BLAKE2b-256 checksum
How to use checksums
39c4ba1e3b93dcc50e4f354cfa3b76986ec924ef40f73d7568b9b4433dd1f14f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / yonder_cli-0.6.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_1_x86_64.whl

Download URL yonder_cli-0.6.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_1_x86_64.whl
Size 4.1 MB
Tags Linux glibc 2.17+ x86-64 Linux musl 1.1+ x86-64 Python 3
SHA-256 checksum
How to use checksums
6e20ab7564ab5a8c1c6a791c48d2b68034cd52ccbf6aa265052a79a5ff621af8
BLAKE2b-256 checksum
How to use checksums
4568304be30a2a32186dd7e203a1a45dd8d33d073942f09a50684642210fcba3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / yonder_cli-0.6.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl

Download URL yonder_cli-0.6.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl
Size 3.7 MB
Tags Linux glibc 2.17+ ARM64 Linux musl 1.1+ ARM64 Python 3
SHA-256 checksum
How to use checksums
972c8eb2a100bb9b91180a95f3c1062980abb318e2f9125e5ce69ed51442c8c1
BLAKE2b-256 checksum
How to use checksums
7c7a56bb2bf695f9b8dba007ea266fd5bc5663ab33166e02f18539144ac74c91
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / yonder_cli-0.6.0-py3-none-macosx_12_0_x86_64.whl

Download URL yonder_cli-0.6.0-py3-none-macosx_12_0_x86_64.whl
Size 4.2 MB
Tags Python 3 macOS 12.0+ x86-64
SHA-256 checksum
How to use checksums
d34886d41b2da6a12c3b405983249cec2645109cd5f61084f21ad61ad7f4665a
BLAKE2b-256 checksum
How to use checksums
5ec4d8c8756c787106e3dfb746700e23ba09f24c59b434cd6941202e7a43e91c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / yonder_cli-0.6.0-py3-none-macosx_12_0_arm64.whl

Download URL yonder_cli-0.6.0-py3-none-macosx_12_0_arm64.whl
Size 3.8 MB
Tags Python 3 macOS 12.0+ ARM64
SHA-256 checksum
How to use checksums
625ce545c0193ce2488f7a07f36b37fe891d4421a024f7f43dd0d13abe6466d9
BLAKE2b-256 checksum
How to use checksums
6b0a0f7527b8bed2fd24ecd50eb6e057f0cb08546e4105a5c14e584664bb373d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Security for yonder-cli 0.6.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 6 files in this release have been uploaded with provenance metadata.

Select from 6 files

Attestation for yonder_cli-0.6.0-py3-none-win_arm64.whl

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page