# ---------- Stage 1: build the client (resources/js -> public/build) ---------- FROM node:22-alpine AS client WORKDIR /build COPY package.json package-lock.json ./ RUN npm ci --no-audit --no-fund COPY vite.config.js ./ COPY resources ./resources RUN npm run build # ---------- Stage 2: Laravel runtime (php-fpm / reverb / simulate) ---------- FROM php:8.5-fpm-alpine AS app WORKDIR /var/www/html RUN apk add --no-cache linux-headers libzip-dev oniguruma-dev sqlite-dev && \ docker-php-ext-install -j"$(nproc)" mbstring sockets pcntl bcmath pdo_sqlite && \ rm -rf /var/cache/apk/* # opcache defaults for single-container deployments RUN { \ echo 'opcache.enable=1'; \ echo 'opcache.validate_timestamps=0'; \ echo 'opcache.memory_consumption=64'; \ echo 'opcache.interned_strings_buffer=16'; \ echo 'opcache.max_accelerated_files=10000'; \ } > /usr/local/etc/php/conf.d/zz-opcache.ini COPY --from=composer:2 /usr/bin/composer /usr/bin/composer COPY composer.json composer.lock ./ RUN composer install \ --no-dev \ --no-interaction \ --prefer-dist \ --no-progress \ --no-scripts \ --no-autoloader COPY --from=client /build/public/build ./public/build COPY . . RUN rm -f bootstrap/cache/services.php bootstrap/cache/packages.php bootstrap/cache/config.php && \ composer dump-autoload --optimize --no-scripts --no-interaction && \ chown -R www-data:www-data storage bootstrap/cache && \ chmod -R ug+rw storage bootstrap/cache COPY entrypoint.sh /usr/local/bin/entrypoint.sh RUN chmod +x /usr/local/bin/entrypoint.sh STOPSIGNAL SIGTERM ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] CMD ["php-fpm", "-F"] # ---------- Stage 3: nginx serving public/ + proxying /app to Reverb ---------- FROM nginx:alpine AS web COPY nginx/default.conf /etc/nginx/conf.d/default.conf COPY --from=app /var/www/html/public /var/www/html/public