diff --git a/.env.example b/.env.example index f06c306..0986db0 100644 --- a/.env.example +++ b/.env.example @@ -63,8 +63,8 @@ REVERB_SERVER_PORT=8080 # browser-side (baked into built assets): the address a browser can reach VITE_REVERB_APP_KEY=change-me-app-key VITE_REVERB_HOST=localhost -VITE_REVERB_PORT=8080 -VITE_REVERB_SCHEME=http +VITE_REVERB_PORT=443 +VITE_REVERB_SCHEME=https VITE_APP_NAME=CluPilot # Vite HMR host the browser connects to (dev). Set to the reachable VM address @@ -174,6 +174,10 @@ ADMIN_HOSTS=admin.dev.clupilot.com,10.10.90.185,localhost,127.0.0.1 HOST_UID=1000 HOST_GID=1000 APP_PORT=80 +# Vite dev server (HMR). Off by default: over the HTTPS domains the +# browser cannot load assets from http://:5173. Set true only when +# working over http://10.10.90.185, then run: docker compose up -d app +VITE_AUTOSTART=false VITE_PORT=5173 REVERB_HOST_PORT=8080 DB_HOST_PORT=3306 diff --git a/bootstrap/app.php b/bootstrap/app.php index 4473a76..0a2ab22 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -24,6 +24,22 @@ return Application::configure(basePath: dirname(__DIR__)) // that an operator console is hosted here. Self-scoped to /admin*. $middleware->prependToGroup('web', \App\Http\Middleware\RestrictAdminHost::class); + // TLS is terminated by the reverse proxy (Zoraxy on the private LAN), so + // without this Laravel sees plain http and builds http:// URLs into an + // https page — every asset and redirect breaks as mixed content. + // + // X_FORWARDED_HOST is deliberately NOT trusted: the console is gated on + // the request host (ADMIN_HOSTS), and trusting that header would let + // anyone reach /admin through a public domain by sending + // "X-Forwarded-Host: admin.…". Zoraxy passes the real Host through, so + // nothing needs it. + $middleware->trustProxies( + at: ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', '127.0.0.1'], + headers: Request::HEADER_X_FORWARDED_FOR + | Request::HEADER_X_FORWARDED_PORT + | Request::HEADER_X_FORWARDED_PROTO, + ); + // Stripe posts server-to-server with its own signature (no CSRF token). $middleware->validateCsrfTokens(except: ['webhooks/stripe']); }) diff --git a/docker-compose.yml b/docker-compose.yml index 6412510..959dd0c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,6 +23,8 @@ services: environment: VITE_HMR_HOST: ${VITE_HMR_HOST:-localhost} VITE_PORT: ${VITE_PORT:-5173} + # Vite dev server is opt-in — see docker/supervisor/clupilot.conf. + VITE_AUTOSTART: ${VITE_AUTOSTART:-false} depends_on: mariadb: condition: service_healthy diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 5b5b6b7..ad4f146 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -18,6 +18,10 @@ elif printf '%s ' "$@" | grep -qE 'reverb:start|queue:work|schedule:work'; then fi if [ "$role" = "app" ]; then + # A container that was killed leaves public/hot behind, and Laravel then + # serves @vite from a dev server that is not running — every asset 404s. + # Vite recreates the file when it actually starts. + rm -f public/hot [ -f vendor/autoload.php ] || www "composer install --no-interaction --prefer-dist --no-progress" [ -x node_modules/.bin/vite ] || www "npm install --no-fund --no-audit" if [ -f .env ] && ! grep -qE '^APP_KEY=.+' .env; then diff --git a/docker/supervisor/clupilot.conf b/docker/supervisor/clupilot.conf index de70425..ccee43a 100644 --- a/docker/supervisor/clupilot.conf +++ b/docker/supervisor/clupilot.conf @@ -20,6 +20,10 @@ stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 [program:vite] +; Opt-in: over HTTPS domains the browser cannot load assets from +; http://:5173 (mixed content + CORS), so the default is the built manifest. +; Set VITE_AUTOSTART=true in .env for HMR while working over the IP. +autostart=%(ENV_VITE_AUTOSTART)s command=npm run dev -- --host 0.0.0.0 directory=/var/www/html user=www-data diff --git a/resources/views/livewire/admin/confirm-delete-datacenter.blade.php b/resources/views/livewire/admin/confirm-delete-datacenter.blade.php index bb7e151..c94cb06 100644 --- a/resources/views/livewire/admin/confirm-delete-datacenter.blade.php +++ b/resources/views/livewire/admin/confirm-delete-datacenter.blade.php @@ -10,7 +10,7 @@
- {{ __('datacenters.cancel') }} + {{ __('datacenters.cancel') }}
@else
@@ -23,7 +23,7 @@
- {{ __('datacenters.cancel') }} + {{ __('datacenters.cancel') }} {{ __('datacenters.delete_confirm') }} diff --git a/resources/views/livewire/admin/confirm-remove-host.blade.php b/resources/views/livewire/admin/confirm-remove-host.blade.php index 590e3f4..ab62e05 100644 --- a/resources/views/livewire/admin/confirm-remove-host.blade.php +++ b/resources/views/livewire/admin/confirm-remove-host.blade.php @@ -9,7 +9,7 @@
- {{ __('hosts.cancel') }} + {{ __('hosts.cancel') }} {{ __('hosts.remove_confirm') }} diff --git a/resources/views/livewire/admin/edit-datacenter.blade.php b/resources/views/livewire/admin/edit-datacenter.blade.php index 49ad576..5b4aee0 100644 --- a/resources/views/livewire/admin/edit-datacenter.blade.php +++ b/resources/views/livewire/admin/edit-datacenter.blade.php @@ -26,7 +26,7 @@
- {{ __('datacenters.cancel') }} + {{ __('datacenters.cancel') }} {{ __('datacenters.save') }}
diff --git a/resources/views/livewire/confirm-cancel-package.blade.php b/resources/views/livewire/confirm-cancel-package.blade.php index 3abe4f2..4312e08 100644 --- a/resources/views/livewire/confirm-cancel-package.blade.php +++ b/resources/views/livewire/confirm-cancel-package.blade.php @@ -22,7 +22,7 @@
- {{ __('settings.keep') }} + {{ __('settings.keep') }} {{ __('settings.cancel_confirm') }} diff --git a/resources/views/livewire/confirm-close-account.blade.php b/resources/views/livewire/confirm-close-account.blade.php index 14dfac6..a57fd67 100644 --- a/resources/views/livewire/confirm-close-account.blade.php +++ b/resources/views/livewire/confirm-close-account.blade.php @@ -10,7 +10,7 @@
- {{ __('settings.keep') }} + {{ __('settings.keep') }}
@else
@@ -28,7 +28,7 @@ @error('confirmWord')

{{ $message }}

@enderror
- {{ __('settings.keep') }} + {{ __('settings.keep') }} {{ __('settings.close_confirm') }}