Skip to the page

Share an Astro dev server, or its build, with a link

astro dev shares with hot reload and no allowedHosts change, and its forms post. Astro.url says localhost until allowedDomains. Or upload dist.

Updated

Share astro dev with ouicu and it works as it comes: the page, hot reload, and forms on pages rendered on demand. The one thing that still says localhost is Astro.url, until you list the link's domain in security.allowedDomains. For a client who looks later, upload the static build instead.

Astro at a glance
Astro
Dev server port4321
On your Wi-Finpm run dev -- --host
Host checkserver.allowedHosts
Build folder to uploaddist, from astro build

Blocked request, through other tunnels

Astro has answered only the hosts it knows since 5.4.0, through its server.allowedHosts setting. A tunnel that passes your public name on as Host gets 403 and this, from both astro dev and astro preview:

What the browser shows
Blocked request. This host ("calm-otter-4821.ouicu.app") is not allowed.

ouicu hands Astro Host: localhost:4321 instead, so the check passes with nothing listed, and the public name travels in X-Forwarded-Host. With another tunnel, add its name to server.allowedHosts in astro.config.mjs.

Astro through a ouicu link
Through the linkWhat it takes
The pageWorks, nothing to change
Hot reloadWorks, nothing to change
A form on an on-demand pageWorks, nothing to change

Share astro dev with ouicu

Start the dev server as usual and share its port in a second terminal. Getting started has the install.

npm run dev# in a second terminalouicu share 4321

Astro says Network use --host to expose as it starts, which is about your Wi-Fi, not the link: ouicu reaches the dev server on localhost. On Free, a share runs for up to 2 hours.

Hot reload comes along. The page opens its socket to wss://calm-otter-4821.ouicu.app/, on the link's own port, and ouicu hands it to Astro as coming from localhost. Save a .astro page and the page reloads on every screen that has the link open, with your change in it.

Forms on pages rendered on demand

Astro guards forms with security.checkOrigin, on by default since 4.9.0. “The check is executed only for pages rendered on demand”, which takes an adapter: we added the Node one with npx astro add node and a page with export const prerender = false. How it decides, from the configuration reference:

“This uses the Sec-Fetch-Site header for modern browsers and falls back to the Origin header when unavailable.”

Astro docs, Configuration Reference

A ouicu link is https, so the browser sends Sec-Fetch-Site: same-origin and the form posts, in astro dev and from the built server alike. Without that header Astro compares Origin, which is the link's, with the address it sees, http://localhost:4321, and refuses with 403:

What Astro answers
Cross-site POST form submissions are forbidden

We sent that request by hand, with the link's origin and no Sec-Fetch-Site; one marked cross-site is refused the same way. A visitor's browser on the link sends neither, so you shouldn't see it there.

Astro.url says localhost

The docs define it as “A normalized URL object derived from the current request.url value.” Through a link that request is ouicu's, so a page printing Astro.url showed http://localhost:4321/where. Canonical links and absolute addresses built from it point at localhost.

Since 5.14.2, Astro reads the proxy's headers for the domains you list, and only those: “When not configured, X-Forwarded-Host headers are not trusted and will be ignored.”

// astro.config.mjsexport default defineConfig({  security: {    allowedDomains: [{ hostname: '*.ouicu.app', protocol: 'https' }],  },  // adapter: node({ mode: 'standalone' }),})

With it, the on-demand page said https://calm-otter-4821.ouicu.app/live. A pattern starting *. “matches exactly one subdomain level”, which a ouicu name is. Pages that are prerendered still say localhost: the setting applies to pages rendered on demand.

Upload the static build

A site with no adapter builds to plain files in dist, which ouicu deploy uploads and keeps up with your laptop closed:

npx astro buildouicu deploy dist

Each page is its own HTML file, so there's no --spa to add. To look at the build before uploading, astro preview shares the same way as the dev server: it loaded through the link with nothing changed. On Free, an upload stays up for 7 days (Uploading a built site).

Or share the Node server

With pages rendered on demand, ouicu deploy can't serve them: it uploads static files only. Build and run the server the Node adapter makes, then share its port:

npx astro buildHOST=127.0.0.1 PORT=4321 node ./dist/server/entry.mjs# in a second terminalouicu share 4321

The adapter's docs give node ./dist/server/entry.mjs as the command, with HOST and PORT to set where it listens. Through the link, its form posted as in development.

Phones, and who can open it

ouicu prints the link as a QR code, which opens the site on any phone (QR codes). For the same Wi-Fi without a link, Astro needs npm run dev -- --host; see how to open localhost on your phone. Anyone with the link reaches every page the dev server answers, so for a client ask for a password, on Hobby and Pro: ouicu share 4321 --password.

Tested with Astro 7.3.7 on , with Node 24.21.0: the minimal starter from create-astro, shared with ouicu share through ouicu's edge and opened in Chromium at its https link: astro dev with an edit, the static build in astro preview, then with the Node adapter 11.1.7 a form, its origin check, Astro.url and allowedDomains, in development and built.

Sources

Prices, defaults and quotes about other products, and the day each was last checked at its source.

  1. CLI Commands, Astro docs. Checked .
  2. Configuration Reference, Astro docs. Checked .
  3. hostCheck.ts, Vite on GitHub. Checked .
  4. core/app/origin-check.ts, Astro on GitHub. Checked .
  5. Astro render context: url, Astro docs. Checked .
  6. @astrojs/node, Astro docs. Checked .