Share a running app
On this page
Share a public link when someone else should try the app running on your Template box or devbox — for example, a teammate who wants to click through a feature before you open the pull request. They will open the link in their own browser, without installing boxes.dev or signing in to boxes.dev.
Create the link
Anyone with the link will be able to reach your app. Before sharing, check that the app uses its own authentication for private data or actions. Don't share an unauthenticated admin console or database browser.
- Select the Template box or devbox where your app is running. If needed, ask its agent to start the HTTP server, or start it yourself in Terminal.
- Open Ports in the desktop titlebar and find the app's port.
- Hover over the port's row and choose Share publicly.
- Read and accept the confirmation, then choose Copy link and send the link to your reviewer.
If Share publicly isn't available, check that the app shows in Ports as a detected HTTP app — its row offers a web URL — and that its port is allowed by the project's rules under Configure port forwarding… in Ports (see changing forwarding rules). If the port isn't listed at all, check the server's output in Terminal (see resolving a missing port).
The HTTPS link points to that exact machine and port. Switching threads or
closing the desktop app won't change its destination, and it doesn't depend
on local port forwarding. Its address looks like
user-preview-<token>.onboxes.dev. The address is hard to guess, but it can
appear in browser history, referrer information, and request records; it
isn't a substitute for your app's authentication.
Some development servers only answer requests for hostnames they recognize.
If Vite shows "Blocked request. This host is not allowed" when the link is
opened, add '.onboxes.dev' to server.allowedHosts in your Vite config,
keeping any hosts already listed, then restart the server. The leading dot
covers every public link and Project URL, so you won't need to change it again
when you share the port later. Don't turn the host check off entirely.
Keep the app available
A public link works while its box is awake and the app is running. Traffic through the link can keep an awake box active. When visitor traffic and other activity stop, the box can sleep on its own; leaving the server running doesn't prevent sleep.
While the box sleeps, Ports marks the link as paused, and visitors will see a page with a Wake devbox button. Anyone with the link can press it without signing in to boxes.dev. Waking will use your box-hours, and your plan's limits still apply: if you already have as many awake devboxes as your plan allows, or billing blocks the wake, the page will tell the visitor. Once the box is awake, the page will reload into your app. Other requests to the link, such as API calls, won't wake the box.
Sleeping keeps the app's memory, so an app that was running when the box fell asleep will normally be running again when it wakes. If the app is stopped, visitors will see an unavailable page. Stopping your app doesn't remove its public link. To restore access, restart the app — the same link will work again. After restarting the app, allow a few seconds for detection and link availability to refresh, then have your visitor retry.
If boxes.dev recovered the machine after an unexpected stop, check the recovered app before sending anyone back to it. If recovery replaced the machine, the old public link was revoked, so share a new one.
Handle long requests
A public link has its own time limits, separate from any timeout set in your app. The link closes its connection to your app after 2 minutes without any data, including while a request is still waiting for the start of its response. Each request also needs to finish within 10 minutes. Treat these as ceilings, because the visitor's browser or client can stop waiting sooner and connections can drop. Raising your app's own timeout won't extend them.
A request that is still waiting after 2 minutes can fail with Application timed out (HTTP 504), or with Application unavailable (HTTP 502) if your app has sent only its response headers. If part of the response has already reached the visitor and your app then goes quiet, the visitor will get an incomplete response.
A timeout or a dropped connection ends the request, but it doesn't necessarily stop the work your app started. Depending on how your app handles a closed connection, that work may keep running and finish. Before retrying an action such as an import, a payment, or sending a message, check your app's own record of it, such as an order or job status, so it doesn't run twice. If the original request included an idempotency key that your app or API accepts, retry with that same key.
For work that can take more than a minute or two, or that shouldn't run twice, choose one of these approaches:
- Stream progress: send the first part of the response right away, then keep the gaps well under 2 minutes, for example by sending a server-sent event or a progress line every 30 seconds. Check that your framework, and any proxy your app runs behind, sends each chunk as it's written instead of buffering the whole response. End with a message that says the work is done, because a closed connection or a 200 status alone doesn't show that it finished. A streamed response still needs to finish within 10 minutes.
- Run the work as a job: have your app save the job, return its ID right away (for example, with HTTP 202), and offer a status URL that the page or client can check until the job finishes. This works for jobs longer than 10 minutes, and after a disconnect the client can look up the same job instead of starting a new one. Your app runs the job and stores its status, so keep the Template box or devbox awake until long jobs finish.
Manage and stop sharing
Open Ports to copy, open, or stop sharing a link on the selected box; links stay listed there even after their apps stop. To manage links across all of the project's machines, open Public links in the sidebar or choose All public links… from Ports. The sidebar row appears while the project has at least one active link. Its page names the box that owns each link and lets you open, copy, or stop sharing any link without switching boxes.
Choose Stop sharing when the reviewer is finished. This will block new requests and close public WebSocket connections within 30 seconds. It can't take back what a visitor already has: an HTTP response already in progress may finish, and anything they downloaded or cached will remain with them. Your app will keep running, and any other way of reaching it will be unaffected. Sharing the port again later will create a new URL.
Share from a script or agent
An agent or shell script on the Template box or devbox can manage that
machine's links with dvb-onbox, the command installed on the machine
itself. The dvb CLI belongs on your laptop. Use the following commands
to create a link, list active links, or stop sharing when you're finished:
# Create a link
dvb-onbox ports share --port 4000
# List active links
dvb-onbox ports list-public
# Stop sharing when you're finished
dvb-onbox ports stop-sharing --port 4000
Replace 4000 with your app's detected HTTP port. The same conditions apply
as in Ports: the port must be allowed by the project's forwarding rules, and
excluded, undetected, and non-HTTP ports are rejected. The commands act only
on the machine where they run — there is no project or machine selector.
The share command prints the URL so a script can capture it, and repeating
it will return the same active link. Add --json to any command for
structured output. Links created by an agent will also appear in the desktop
app, where you can stop sharing them yourself.
For a callback or API address that you can move between devboxes without changing the URL, use a Project URL.