"I'm presenting in 30 minutes and I need to share my laptop's app with the room. I don't care if the URL changes tomorrow — I just need it to work right now."
One command. Open the URL. Done.
You have a process listening on some port. You want anyone with the
URL to be able to hit it. You don't want to write a manifest, edit
a config file, or think about it longer than necessary.
You'll need asd installed and one-time-only asd login.
$ asd expose 3000
✓ Exposed http://localhost:3000 → https://3000-xyz1.eu2.tn.example.com
🔑 Basic auth: user "asd", password "<copy from asd expose auth>"
Two things to know before you paste the URL into chat:
1. The default has basic auth on. Get the password:
$ asd expose auth
Username: asd
Password: faaw997xezmwdyl5753627zl9rvqhb1_
Send the room the URL and the credentials. Or, if you want a
fully open URL (no password):
$ asd expose 3000 --auth=none
2. Pick a friendlier subdomain. 3000-xyz1.… is what you get
by default. Make it human:
$ asd expose 3000 demo
✓ Exposed http://localhost:3000 → https://demo-xyz1.eu2.tn.example.com
Anyone with the URL (and the credentials, if auth is on) reaches
your app. Stays up as long as the asd expose process runs. Stop
with Ctrl-C or:
$ asd expose stop 3000
# or by name:
$ asd expose stop demo
To see everything you've exposed so far (useful when you forgot
about a tunnel from this morning):
$ asd expose list
NAME PORT URL STATUS
demo 3000 https://demo-xyz1.eu2.tn.example ✅ healthy
asd expose is the zero-config path. No asd.yaml required,
no manifest, no asd net apply. It writes a transient registry
entry, adds one Caddy route, brings up one tunnel daemon — torn
down again when you Ctrl-C.
The URL is stable as long as the process is. Same
subdomain (<port> or <name>), same machine, same client id —
the URL doesn't rotate. If you stop and restart with the same
arguments, you get the same URL back.
Basic auth on by default is intentional. The Reddit /
Hacker News classic of "I shared my localhost in chat for a demo
and it got crawled by a botnet 30 seconds later" is solved by the
default. Use --auth=none only when you actually need it
(public demo, embedded iframe, etc.).
learn/02-first-service — write it as a manifest, get a stable URL across restarts.cookbook/tunnel-a-dev-server — same flow with the framework-specific gotchas.cookbook/put-an-api-behind-sso — but that's longer than 30 minutes.