Assigned Vite ports
Several development Instances can run Vite on one Node. Orbit gives each development Instance its own Vite port on its Node. Thevp-dev Process preset runs Vite on that port and connects it to Caddy and to wake. Browsers never see the port: they load assets through the Route’s HTTPS origin.
The annotator Process uses a separate stored annotator_port and shares the Agentation allocator. Its reservation persists through pending proxy withdrawal and source retirement on transfer. Environment projection changes only existing unit files and does not activate a sleeping Vite Process. It does not change Vite’s reservation and retry behavior. See Annotator Process.
Assignment
Orbit assignsvite_port when it creates or registers a development Instance. Production Instances get none. An assignment creates or starts no Process. Caddy, wake, and the vp-dev preset use only that assigned port.
When this Instance already has a recorded port on the Node, the search starts there. When it has no recorded port, the search starts at 5173 and moves up to 65535. It never tries a port below its start. It skips:
- ports that other Instances on the Node hold,
- ports that any TCP socket on the Node uses, over IPv4 or IPv6, except in
TIME_WAIT, - common service ports:
3306,5432,5672,6379,8000,8080,8443,9000,9090,9200,11211,15672, and27017.
instance:list, instance:show, the API, and the SDK return vite_port. The assignment is a stored preference, not an open socket. It survives hibernation, dependency pruning, Process replacement, and reboots. Removal releases it after runtime cleanup. A transfer assigns a port on the destination and releases the source port after cleanup.
The vp-dev preset
Create the preset Process on a development Instance.--instance accepts an Instance ID or its exact Route domain.
/usr/local/bin/vp, a readable package.json, and an installed node_modules. It installs no dependencies and edits no application code. It sets the command, the working directory, and restart on failure. A custom command, runtime, or Docker option conflicts with the preset and is refused. An Instance has at most one preset Process. Naming a plain Process vp-dev has no effect. The Processes page lists every preset.
For a Laravel Instance, preparation checks package.json and node_modules in its application directory, and the Process runs from that same directory. With root server/web/public, both prerequisites live in <checkout>/server/web, and Laravel’s Vite plugin writes <checkout>/server/web/public/hot. Root public keeps these paths at the checkout root. Non-Laravel Instances keep checkout-root prerequisite checks and working directories. Orbit does not install missing dependencies during preparation.
The preset runs Vite on loopback with strict binding:
ORBIT_DEV_SERVER_PORT to the environment file before each start. Systemd reads it at start, so a new port needs no unit change. The removed certificate variables keep Vite on plain HTTP; Caddy terminates TLS.
Start, restart, and wake
Every start of the preset runs one preparation step:- If the preset’s Vite already answers on the port, start returns without restarting it.
- This also applies to automatic starts during wake, transfer restore, and activation. Orbit does not suspend traffic or re-project Caddy for a healthy endpoint.
- An explicit start marks the Instance awake only after Vite is ready.
- An automatic start that must prepare Vite suspends traffic and may clear the awake marker.
- Orbit checks the port again. Another listener on the port makes Orbit pick a new port. The other listener keeps running.
- It writes the environment file and points the workload Caddy’s
/__orbit/vitepath at the port. - It starts Vite and waits until Vite answers the client request on that port.
process:restart of the preset, the next HTTP request goes through the wake page. An explicit process:start marks the site awake after readiness. An automatic start preserves the awake marker only when its owned endpoint is already ready; a start that must prepare Vite suspends traffic and may clear the marker. When Vite does not become ready, the start fails with vite.not_ready.
Application setup
The workload Caddy proxieshttps://<domain>/__orbit/vite/ to the port and keeps the /__orbit/vite/ prefix. Every Process of a development Instance with a Route gets these variables. Instances without a Route get none:
Set Vite’s
server.origin to the origin of ORBIT_DEV_SERVER_ORIGIN and server.hmr.path to hmr. Configure assets and HMR for the Route origin. Laravel’s plugin writes the public URL into public/hot, but Orbit does not read that file. Plain Vite applications use the same setup.
Let Orbit pick the port. Do not select one by hand, and do not add keep_alive only to make the Process start on wake: --start already does that.
Why it works this way
These reasons explain the design. Check them before you propose a change.A stored port, not discovery
Vite can pick another port by itself, but Orbit would then have to find out which one.public/hot exists only for Laravel, and behind the proxy it holds the public URL, not the local port. A discovery plugin would add a dependency to every application. So Orbit stores the port and runs Vite with --strictPort.
Unique per Node
Ports only collide on one Node. A Cluster-wide rule would waste ports.No socket held while asleep
The stored assignment already keeps other Instances off the port. A process outside Orbit can still take it, and strict binding plus a new check at start handle that case.An explicit preset
Orbit does not guess from a Process name or command that it runs Vite. The stored preset connects start, restart, wake, and transfer to port preparation. Thevp-dev Process preset uses the assigned Vite port for a development Instance and does not apply to Node or Project targets.