Skip to the page

Share a Laravel site from your laptop, styles and forms included

php artisan serve shares as it is, but its links, forms and built styles say localhost until trustProxies. Vite's hot file needs a build instead.

Updated

Shared through ouicu, php artisan serve answers the link as it comes, but every address Laravel writes into a page says http://localhost:8000: links, form actions and the styles from your build. One line in bootstrap/app.php makes them the link's. Vite's dev server is the other catch, and the answer there is a build.

Laravel at a glance
Laravel
Dev server port8000
On your Wi-Fiphp artisan serve --host=0.0.0.0
Host checkNone as it comes

Links, forms and styles that say localhost

ouicu hands Laravel Host: localhost:8000, so there's no host to allow: “By default, Laravel will respond to all requests it receives regardless of the content of the HTTP request's Host header.” The same paragraph of the docs gives the catch: “In addition, the Host header's value will be used when generating absolute URLs to your application during a web request.”

So through the link, a new project's welcome page loads, and everything absolute points at your laptop. What we saw, opening each through a ouicu link:

What Laravel wrote through the link, before the fix
In the pageWhat Laravel wroteFor the visitor
url()->current()http://localhost:8000/whereTheir own computer's address
action="{{ route('echo') }}"http://localhost:8000/echoSending the form leaves the link
The stylesheet from npm run buildhttp://localhost:8000/build/assets/app-….cssThe page arrives unstyled

Redirects are the exception. ouicu turns a redirect to http://localhost:8000 into one to the link, so a form that posts to a path, action="/echo", lands back on the link with its session intact.

Laravel through a ouicu link
Through the linkWhat it takes
The pageNeeds $middleware->trustProxies(at: '*')
Hot reloadDoesn't come through; use npm run build instead
A form POSTNeeds $middleware->trustProxies(at: '*')

Fix it: trustProxies in bootstrap/app.php

Tell Laravel to believe the proxy's headers. A new project has an empty withMiddleware call in bootstrap/app.php; give it one line:

->withMiddleware(function (Middleware $middleware): void {    $middleware->trustProxies(at: '*');})

Laravel then reads X-Forwarded-Host and X-Forwarded-Proto, which ouicu sends with every request. url() gives https://calm-otter-4821.ouicu.app/where, the route() form posts to the link and lands back on it, and the built stylesheet loads. The docs describe the same symptom behind any proxy that ends https:

“When running your applications behind a load balancer that terminates TLS / SSL certificates, you may notice your application sometimes does not generate HTTPS links when using the url helper.”

Laravel docs, HTTP Requests: Configuring Trusted Proxies

For a proxy whose address you can't know, they say “you may use * to trust all proxies”. On your laptop, ouicu is that proxy. In production, list your own proxies rather than everyone.

419 Page Expired

Laravel answers a form it won't accept with status 419 and a page that says:

The page Laravel sends
Page Expired

Through a ouicu link you're unlikely to meet it. Laravel 13.0 changed the check; the upgrade guide says:

“Laravel's CSRF middleware has been renamed from VerifyCsrfToken to PreventRequestForgery, and now includes request-origin verification using the Sec-Fetch-Site header.”

Laravel docs, Upgrade Guide: Request Forgery Protection

And the CSRF docs: “If the header indicates the request came from the same origin, the request is allowed immediately without any token verification.” A ouicu link is https, so the browser sends that header. In our test, a POST from the page went through with no token at all, and a form with @csrf passed too. A POST without the header and without a token got Page Expired. The docs give the reason it can be missing: “The Sec-Fetch-Site header is only sent by browsers over secure (HTTPS) connections.” So keep @csrf in your forms, for a phone on your Wi-Fi over plain http.

Vite's hot file sends visitors home

npm run dev starts Vite on a port of its own and writes its address to public/hot. Here it held http://[::1]:5173. While that file exists, @vite points every page at it, so through the link the visitor's browser asks its own computer for your styles and scripts. None of them loaded, and hot reload never connected. The link carries one port, and Vite's is a second.

Stop npm run dev, check public/hot is gone, and build:

npm run buildphp artisan serve# in a second terminalouicu share 8000

With trustProxies set, the built files load from the link. A Blade edit still shows when the page loads again: we changed the welcome page's heading and it was there on the next load. A change to your CSS or JavaScript needs another build.

Share php artisan serve with ouicu

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

php artisan serve# in a second terminalouicu share 8000

Laravel listens on your computer alone, and says so as it starts:

In the terminal
Server running on [http://127.0.0.1:8000].

That's all ouicu needs. On Free, a share runs for up to 2 hours. A phone on your Wi-Fi needs php artisan serve --host=0.0.0.0 and your computer's address; the QR code ouicu prints needs neither (QR codes, how to open localhost on your phone).

Herd, and sites on .test names

Laravel Herd has a share command of its own. “Herd uses Expose to share your sites.” “To share your site using Expose, you first need to create a free Expose account.” ouicu shares a port instead, and hands the server Host: localhost with that port. A server that picks the site by its .test name won't find yours that way, and we haven't tested Herd or Valet behind ouicu. Run php artisan serve in the project and share its port.

Debug pages, and who can open the link

A new project's .env has APP_DEBUG=true, so an error shows whoever hit it Laravel's full error page. The docs warn of it in production:

“If the variable is set to true in production, you risk exposing sensitive configuration values to your application's end users.”

Laravel docs, Configuration: Debug Mode

A shared dev server is closer to production than it looks: anyone with the link reaches it. For a client, ask for a password, on Hobby and Pro:

ouicu share 8000 --password

Or name the people allowed in, on Pro, with --allow. ouicu asks at the door, before Laravel sees the request. The link carries web pages only: a download, a video or a PDF from storage is kept back, as is anything over 50 MB (what isn't passed on).

Why not upload it

Laravel renders each page on the server, and ouicu deploy uploads static files only, so a Laravel site is shared live, from your laptop. To show a client, share it while you walk them through; see show a client a website before it goes live.

Tested with Laravel 13.35.0 on , with PHP 8.5.11: composer create-project laravel/laravel with a Blade form, served by php artisan serve in the official composer Docker image and shared with ouicu share through ouicu's edge: the welcome page, url(), forms with and without a token, npm run dev and npm run build, before and after trustProxies, in Chromium at the https link, whose own localhost went nowhere, as a client's would.

Sources

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

  1. ServeCommand.php, Laravel on GitHub. Checked .
  2. HTTP Requests: Configuring Trusted Proxies, Laravel docs. Checked .
  3. Exceptions/views/419.blade.php, Laravel on GitHub. Checked .
  4. Upgrade Guide: Request Forgery Protection, Laravel docs. Checked .
  5. CSRF Protection, Laravel docs. Checked .
  6. laravel/vite-plugin: src/index.ts, Laravel on GitHub. Checked .
  7. Sharing Sites, Laravel Herd docs. Checked .
  8. laravel/laravel: .env.example, Laravel on GitHub. Checked .
  9. Configuration: Debug Mode, Laravel docs. Checked .