fix: Docker UID-mapping + storage permissions + CDN font removal

- Replace www-data usermod hack with dedicated app user (ARG UID/GID=1000)
  so container processes map to host user nexxo, preventing Permission denied
  on node_modules/.vite-temp and storage/logs/laravel.log
- Explicitly mkdir + chown storage/* and bootstrap/cache to app:app (775)
  inside Dockerfile so PHP-FPM can write logs/sessions/views/cache
- Add UID/GID build args to all four services (app, queue, scheduler, reverb)
- Remove Breeze-scaffold tailwind.config.js (Tailwind v4 uses @theme in CSS)
- Remove fonts.bunny.net CDN from welcome.blade.php; switch to local fonts

Verified: npm run build exit 0, 44/44 tests pass, /login HTTP 200,
storage write OK, manifest.json + 38KB CSS generated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main
Boban Blaskovic 2026-05-22 14:18:01 +02:00
parent d522f0d376
commit 58e99c74e8
16 changed files with 41 additions and 39 deletions

0
bootstrap/cache/.gitignore vendored Normal file → Executable file
View File

View File

@ -3,6 +3,9 @@ services:
build: build:
context: . context: .
dockerfile: docker/app/Dockerfile dockerfile: docker/app/Dockerfile
args:
UID: 1000
GID: 1000
volumes: volumes:
- .:/var/www/html - .:/var/www/html
- app_storage:/var/www/html/storage/app - app_storage:/var/www/html/storage/app
@ -31,6 +34,9 @@ services:
build: build:
context: . context: .
dockerfile: docker/app/Dockerfile dockerfile: docker/app/Dockerfile
args:
UID: 1000
GID: 1000
command: php artisan queue:work --sleep=3 --tries=3 command: php artisan queue:work --sleep=3 --tries=3
volumes: volumes:
- .:/var/www/html - .:/var/www/html
@ -48,6 +54,9 @@ services:
build: build:
context: . context: .
dockerfile: docker/app/Dockerfile dockerfile: docker/app/Dockerfile
args:
UID: 1000
GID: 1000
command: sh -c "while true; do php artisan schedule:run --verbose --no-interaction; sleep 60; done" command: sh -c "while true; do php artisan schedule:run --verbose --no-interaction; sleep 60; done"
volumes: volumes:
- .:/var/www/html - .:/var/www/html
@ -65,6 +74,9 @@ services:
build: build:
context: . context: .
dockerfile: docker/app/Dockerfile dockerfile: docker/app/Dockerfile
args:
UID: 1000
GID: 1000
command: php artisan reverb:start --host=0.0.0.0 --port=8081 command: php artisan reverb:start --host=0.0.0.0 --port=8081
ports: ports:
- "8080:8081" - "8080:8081"

View File

@ -12,9 +12,24 @@ RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get install -y nodejs \ && apt-get install -y nodejs \
&& apt-get clean && rm -rf /var/lib/apt/lists/* && apt-get clean && rm -rf /var/lib/apt/lists/*
RUN usermod -u 1000 www-data && groupmod -g 1000 www-data ARG UID=1000
ARG GID=1000
RUN groupadd -g ${GID} app \
&& useradd -u ${UID} -g app -m -s /bin/bash app
WORKDIR /var/www/html WORKDIR /var/www/html
COPY . . COPY . .
RUN composer install --no-dev --optimize-autoloader \ RUN composer install --no-dev --optimize-autoloader
&& chown -R www-data:www-data storage bootstrap/cache
RUN mkdir -p /var/www/html/storage/logs \
/var/www/html/storage/framework/cache \
/var/www/html/storage/framework/sessions \
/var/www/html/storage/framework/views \
/var/www/html/storage/app/public \
/var/www/html/storage/app/uploads \
/var/www/html/bootstrap/cache \
&& chown -R app:app /var/www/html/storage /var/www/html/bootstrap/cache \
&& chmod -R 775 /var/www/html/storage /var/www/html/bootstrap/cache
USER app

20
package-lock.json generated
View File

@ -1,5 +1,5 @@
{ {
"name": "html", "name": "lernschiff",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
@ -3401,9 +3401,9 @@
} }
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.360", "version": "1.5.361",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.360.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.361.tgz",
"integrity": "sha512-GkcBt6YYAw9SxFWn+xVar4cLVGlXVuswwtRLBozi2zp0GjXs4ZnOrqV4zbXzg35n7w81hCkyJNYicgXlVHAmBA==", "integrity": "sha512-Q6Hts7N9FnJc5LeGRINFvLhCI9xZmNtTDe5ZbcVezQz7cU4a8Aua3GH1b8J2XY8Al9PF+OCwYqhgsOOheMdvkA==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@ -3415,9 +3415,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/enhanced-resolve": { "node_modules/enhanced-resolve": {
"version": "5.21.6", "version": "5.22.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.0.tgz",
"integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", "integrity": "sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -4995,9 +4995,9 @@
} }
}, },
"node_modules/node-releases": { "node_modules/node-releases": {
"version": "2.0.45", "version": "2.0.46",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.45.tgz", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz",
"integrity": "sha512-iIbHXV9eBB2nB0wa7oTsrrXq+qQt+9SIlx9AX3T96YgobtEQfis5n6TJ6vV+3QP8DwdriEAcGhARaFCu37peBg==", "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {

View File

@ -6,14 +6,10 @@
<title>Laravel</title> <title>Laravel</title>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,600&display=swap" rel="stylesheet" />
<!-- Styles --> <!-- Styles -->
@vite(['resources/css/app.css', 'resources/js/app.js']) @vite(['resources/css/app.css', 'resources/js/app.js'])
</head> </head>
<body class="antialiased font-sans"> <body class="antialiased font-display">
<div class="bg-gray-50 text-black/50 dark:bg-black dark:text-white/50"> <div class="bg-gray-50 text-black/50 dark:bg-black dark:text-white/50">
<img id="background" class="absolute -left-20 top-0 max-w-[877px]" src="https://laravel.com/assets/img/welcome/background.svg" /> <img id="background" class="absolute -left-20 top-0 max-w-[877px]" src="https://laravel.com/assets/img/welcome/background.svg" />
<div class="relative min-h-screen flex flex-col items-center justify-center selection:bg-[#FF2D20] selection:text-white"> <div class="relative min-h-screen flex flex-col items-center justify-center selection:bg-[#FF2D20] selection:text-white">

0
storage/app/.gitignore vendored Normal file → Executable file
View File

0
storage/app/private/.gitignore vendored Normal file → Executable file
View File

0
storage/app/public/.gitignore vendored Normal file → Executable file
View File

0
storage/framework/.gitignore vendored Normal file → Executable file
View File

0
storage/framework/cache/.gitignore vendored Normal file → Executable file
View File

0
storage/framework/cache/data/.gitignore vendored Normal file → Executable file
View File

0
storage/framework/sessions/.gitignore vendored Normal file → Executable file
View File

0
storage/framework/testing/.gitignore vendored Normal file → Executable file
View File

0
storage/framework/views/.gitignore vendored Normal file → Executable file
View File

0
storage/logs/.gitignore vendored Normal file → Executable file
View File

View File

@ -1,21 +0,0 @@
import defaultTheme from 'tailwindcss/defaultTheme';
import forms from '@tailwindcss/forms';
/** @type {import('tailwindcss').Config} */
export default {
content: [
'./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',
'./storage/framework/views/*.php',
'./resources/views/**/*.blade.php',
],
theme: {
extend: {
fontFamily: {
sans: ['Figtree', ...defaultTheme.fontFamily.sans],
},
},
},
plugins: [forms],
};