fix(dev): support root bind mounts and LAN Vite access
Keep the dev container as root for s6 init so composer can create vendor/ on root-owned mounts, then chown writable paths to www-data. Move init-setup into a shell script and expose VITE_HOST/PORT for remote HMR (LAN/Tailscale) with Vite listening on 0.0.0.0.
This commit is contained in:
parent
913d033c75
commit
e2c2180f4f
20 changed files with 80 additions and 44 deletions
|
|
@ -30,6 +30,14 @@ DB_PORT=5432
|
|||
# Enable Laravel Telescope for debugging
|
||||
TELESCOPE_ENABLED=false
|
||||
|
||||
# Enable Laravel Debugbar (disabled by default; set true when needed)
|
||||
DEBUGBAR_ENABLED=false
|
||||
|
||||
# Vite dev server. Defaults to localhost. For phone/LAN/Tailscale access, set to
|
||||
# the host machine's reachable IP (e.g. VITE_HOST=100.75.155.70), then recreate vite.
|
||||
VITE_HOST=localhost
|
||||
VITE_PORT=5173
|
||||
|
||||
# Enable Laravel Nightwatch monitoring
|
||||
NIGHTWATCH_ENABLED=false
|
||||
NIGHTWATCH_TOKEN=
|
||||
|
|
|
|||
0
bootstrap/cache/.gitignore
vendored
Normal file → Executable file
0
bootstrap/cache/.gitignore
vendored
Normal file → Executable file
|
|
@ -96,6 +96,7 @@ services:
|
|||
container_name: coolify-vite
|
||||
working_dir: /var/www/html
|
||||
environment:
|
||||
# Set VITE_HOST in .env to a browser-reachable IP/hostname for LAN/Tailscale access
|
||||
VITE_HOST: "${VITE_HOST:-localhost}"
|
||||
VITE_PORT: "${VITE_PORT:-5173}"
|
||||
ports:
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ services:
|
|||
container_name: coolify-vite
|
||||
working_dir: /var/www/html
|
||||
environment:
|
||||
# Set VITE_HOST in .env to a browser-reachable IP/hostname for LAN/Tailscale access
|
||||
VITE_HOST: "${VITE_HOST:-localhost}"
|
||||
VITE_PORT: "${VITE_PORT:-5173}"
|
||||
ports:
|
||||
|
|
|
|||
|
|
@ -98,5 +98,8 @@ RUN mkdir -p /etc/nginx/conf.d && \
|
|||
COPY --from=minio-client /usr/bin/mc /usr/bin/mc
|
||||
RUN chmod +x /usr/bin/mc
|
||||
|
||||
# Switch to non-root user
|
||||
USER www-data
|
||||
# Stay as root for s6 init so bind-mounted workspaces work even when the host
|
||||
# tree is root-owned (CI, Jean, rootful Docker). PHP-FPM/nginx still run as
|
||||
# www-data via their service configs. Do NOT set USER www-data here — that
|
||||
# makes init-setup (composer install) fail with "vendor could not be created".
|
||||
USER root
|
||||
|
|
|
|||
22
docker/development/etc/s6-overlay/s6-rc.d/init-setup/up
Normal file → Executable file
22
docker/development/etc/s6-overlay/s6-rc.d/init-setup/up
Normal file → Executable file
|
|
@ -1,22 +1,6 @@
|
|||
#!/command/execlineb -P
|
||||
|
||||
# Use with-contenv to ensure environment variables are available
|
||||
# s6 oneshots are execline pipelines (shebang shell scripts are not run as sh).
|
||||
# Delegate to a real shell script for readable setup logic.
|
||||
with-contenv
|
||||
cd /var/www/html
|
||||
foreground {
|
||||
composer
|
||||
install
|
||||
}
|
||||
foreground {
|
||||
php
|
||||
artisan
|
||||
migrate
|
||||
--step
|
||||
}
|
||||
foreground {
|
||||
php
|
||||
artisan
|
||||
dev
|
||||
--init
|
||||
}
|
||||
|
||||
/etc/s6-overlay/scripts/init-setup.sh
|
||||
|
|
|
|||
42
docker/development/etc/s6-overlay/scripts/init-setup.sh
Executable file
42
docker/development/etc/s6-overlay/scripts/init-setup.sh
Executable file
|
|
@ -0,0 +1,42 @@
|
|||
#!/command/with-contenv sh
|
||||
set -eu
|
||||
|
||||
cd /var/www/html
|
||||
|
||||
# When the project is bind-mounted, host ownership may be root:root while the
|
||||
# app runs as www-data (UID 1000). Fix the minimum needed so composer/laravel
|
||||
# can write, without a recursive chown of the whole tree.
|
||||
prepare_bind_mount() {
|
||||
mkdir -p \
|
||||
storage/framework/cache \
|
||||
storage/framework/sessions \
|
||||
storage/framework/views \
|
||||
storage/logs \
|
||||
bootstrap/cache
|
||||
|
||||
if [ "$(id -u)" = "0" ]; then
|
||||
# Top-level only: allows creating vendor/ when the mount is root-owned
|
||||
chown www-data:www-data /var/www/html 2>/dev/null || true
|
||||
chown -R www-data:www-data storage bootstrap/cache 2>/dev/null || true
|
||||
git config --global --add safe.directory /var/www/html 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
prepare_bind_mount
|
||||
|
||||
echo "👉 init-setup: composer install..."
|
||||
# Run as root when needed so a root-owned bind mount cannot block vendor/
|
||||
# creation, then hand writable paths to www-data for PHP-FPM.
|
||||
composer install --no-interaction
|
||||
|
||||
echo "👉 init-setup: migrate..."
|
||||
php artisan migrate --step --force
|
||||
|
||||
echo "👉 init-setup: artisan dev --init..."
|
||||
php artisan dev --init
|
||||
|
||||
if [ "$(id -u)" = "0" ]; then
|
||||
chown -R www-data:www-data vendor storage bootstrap/cache 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo "👉 init-setup: done"
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"scripts": {
|
||||
"setup": "cp $JEAN_ROOT_PATH/.env . && mkdir -p .claude && cp $JEAN_ROOT_PATH/.claude/settings.local.json .claude/settings.local.json",
|
||||
"setup": "cp $JEAN_ROOT_PATH/.env .",
|
||||
"teardown": null,
|
||||
"run": "docker rm -f coolify coolify-minio-init coolify-realtime coolify-minio coolify-testing-host coolify-redis coolify-db coolify-mail coolify-vite; spin up; spin down"
|
||||
"run": "docker rm -f coolify coolify-minio-init coolify-realtime coolify-minio coolify-testing-host coolify-redis coolify-db coolify-mail coolify-vite; docker compose -f docker-compose.yml -f docker-compose.dev.yml up; docker compose -f docker-compose.yml -f docker-compose.dev.yml down"
|
||||
},
|
||||
"ports": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"dev": "vite --host",
|
||||
"build": "vite build"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
0
storage/app/.gitignore
vendored
Normal file → Executable file
0
storage/app/.gitignore
vendored
Normal file → Executable file
0
storage/app/public/.gitignore
vendored
Normal file → Executable file
0
storage/app/public/.gitignore
vendored
Normal file → Executable file
0
storage/debugbar/.gitignore
vendored
Normal file → Executable file
0
storage/debugbar/.gitignore
vendored
Normal file → Executable file
0
storage/framework/.gitignore
vendored
Normal file → Executable file
0
storage/framework/.gitignore
vendored
Normal file → Executable file
0
storage/framework/cache/.gitignore
vendored
Normal file → Executable file
0
storage/framework/cache/.gitignore
vendored
Normal file → Executable file
0
storage/framework/sessions/.gitignore
vendored
Normal file → Executable file
0
storage/framework/sessions/.gitignore
vendored
Normal file → Executable file
0
storage/framework/testing/.gitignore
vendored
Normal file → Executable file
0
storage/framework/testing/.gitignore
vendored
Normal file → Executable file
0
storage/framework/views/.gitignore
vendored
Normal file → Executable file
0
storage/framework/views/.gitignore
vendored
Normal file → Executable file
0
storage/logs/.gitignore
vendored
Normal file → Executable file
0
storage/logs/.gitignore
vendored
Normal file → Executable file
0
storage/pail/.gitignore
vendored
Normal file → Executable file
0
storage/pail/.gitignore
vendored
Normal file → Executable file
|
|
@ -2,33 +2,30 @@ import { defineConfig, loadEnv } from "vite";
|
|||
import laravel from "laravel-vite-plugin";
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd(), '')
|
||||
const viteHost = env.VITE_HOST || null;
|
||||
const vitePort = Number(env.VITE_PORT || 5173);
|
||||
const env = loadEnv(mode, process.cwd(), "");
|
||||
// Prefer process.env so Docker Compose can override without writing .env.
|
||||
// Set VITE_HOST to a browser-reachable hostname/IP when accessing the app
|
||||
// from another device (LAN / Tailscale), e.g. VITE_HOST=100.75.155.70
|
||||
const viteHost = (process.env.VITE_HOST || env.VITE_HOST || "localhost").trim();
|
||||
const vitePort = Number(process.env.VITE_PORT || env.VITE_PORT || 5173);
|
||||
|
||||
return {
|
||||
server: {
|
||||
watch: {
|
||||
ignored: [
|
||||
"**/dev_*_data/**",
|
||||
"**/storage/**",
|
||||
],
|
||||
ignored: ["**/dev_*_data/**", "**/storage/**"],
|
||||
},
|
||||
// Listen on all interfaces so Docker / remote clients can reach the dev server
|
||||
host: "0.0.0.0",
|
||||
port: vitePort,
|
||||
strictPort: true,
|
||||
allowedHosts: true,
|
||||
cors: {
|
||||
origin: [
|
||||
/^https?:\/\/localhost(:\d+)?$/,
|
||||
/^https?:\/\/127\.0\.0\.1(:\d+)?$/,
|
||||
/^https?:\/\/\[::1\](:\d+)?$/,
|
||||
...(env.APP_URL ? [env.APP_URL] : []),
|
||||
...(viteHost ? [`http://${viteHost}:${vitePort}`, `https://${viteHost}:${vitePort}`] : []),
|
||||
],
|
||||
// App (:8000) and Vite (:5173) are different origins; allow any host in dev
|
||||
cors: true,
|
||||
origin: `http://${viteHost}:${vitePort}`,
|
||||
hmr: {
|
||||
host: viteHost,
|
||||
clientPort: vitePort,
|
||||
},
|
||||
origin: viteHost ? `http://${viteHost}:${vitePort}` : undefined,
|
||||
hmr: viteHost
|
||||
? { host: viteHost, clientPort: vitePort }
|
||||
: true,
|
||||
},
|
||||
plugins: [
|
||||
laravel({
|
||||
|
|
@ -36,5 +33,5 @@ export default defineConfig(({ mode }) => {
|
|||
refresh: true,
|
||||
}),
|
||||
],
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue