Host Behind Nginx

Introduction

When moving from php artisan serve to a local Nginx/PHP-FPM stack or a production deployment, you must ensure your environment variables and file permissions are correctly configured.

Step 1 — Directory Permissions

Ensure the web server user (e.g., www-data or nginx) has write permissions to the storage and bootstrap/cache directories.

bash
chown -R www-data:www-data storage bootstrap/cache

If you are using the default SQLite database, the web server must also have write access to both the database file *and the directory containing it* to write the WAL files.

bash
chown www-data:www-data database/
chown www-data:www-data database/database.sqlite

Step 2 — Configuring Vite HMR

If you are running the Vite development server (npm run dev) behind an Nginx proxy, set the origin and port in your .env file so the hot-module replacement websocket connects successfully:

env
VITE_DEV_SERVER_PORT=5173
VITE_DEV_SERVER_ORIGIN=http://my-app.test:5173

Ensure your Nginx vhost proxies /vite-hmr to the correct Vite port.

Step 3 — SSR in Slim Deployment Images

If you deploy the built app without node_modules (a common container pattern: copy bootstrap/ssr into a slim runtime image), the Inertia SSR server will crash on boot with ERR_MODULE_NOT_FOUND: react — and pages silently fall back to client-side rendering. Vite externalizes SSR dependencies by default, expecting to resolve them from node_modules at runtime. Bundle them instead in vite.config.ts:

ts
export default defineConfig(({ command, mode }) => {
    return {
        // ...
        ssr: { noExternal: true },
        // ...
    };
});

Starters generated from v0.1.19 onward ship this by default. Older generated apps must add the line by hand — vite.config.ts is host-owned and is not updated by evolayer:resync. It is harmless for classic deploys where node_modules is present.

Was this page helpful?

Source: xuple/evodevops/resources/js/pages/docs/evolayer-base/how-to/host-behind-nginx.tsx