From ea351d2e6d8d487ea7131727f00b9cd873f472d6 Mon Sep 17 00:00:00 2001 From: u00lipp Date: Thu, 23 Oct 2025 08:25:29 +0200 Subject: [PATCH] fix: build and permissions --- Dockerfile | 66 +++++++++++++++++++--------------- deploy/entrypoint.sh | 47 +++++++++--------------- deploy/nginx/default.conf | 4 --- deploy/php-fpm/zz-logging.conf | 2 ++ deploy/php-fpm/zz-socket.conf | 8 ----- deploy/supervisord.conf | 4 +-- 6 files changed, 57 insertions(+), 74 deletions(-) create mode 100644 deploy/php-fpm/zz-logging.conf diff --git a/Dockerfile b/Dockerfile index 7fa8175..8ddb992 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -# ---------- 1) Build Composer deps (no scripts; avoids artisan during build) ---------- +# -------- 1) Composer deps (no scripts; avoids artisan during build) -------- FROM composer:2 AS vendor ARG COMPOSER_NO_DEV=1 WORKDIR /app @@ -9,15 +9,15 @@ composer install --prefer-dist --no-progress --no-interaction --no-scripts; \ fi - # ---------- 2) Bring in app sources ---------- + # -------- 2) App source -------- FROM alpine:3.20 AS app_src WORKDIR /app COPY . ./ - # ---------- 3) Final image: Nginx + PHP-FPM + PGSQL ---------- + # -------- 3) Final: Nginx + PHP-FPM + PGSQL drivers -------- FROM php:8.4-fpm-alpine - # System deps (build + runtime) + # Build + runtime deps (incl. oniguruma for mbstring, GD runtime libs) RUN set -eux; \ apk add --no-cache --virtual .build-deps \ $PHPIZE_DEPS icu-dev libzip-dev postgresql-dev \ @@ -26,14 +26,10 @@ && apk add --no-cache \ icu-libs libzip libpq tzdata bash git curl \ nginx supervisor \ - oniguruma \ - freetype libjpeg-turbo libpng \ - # PHP extensions + oniguruma freetype libjpeg-turbo libpng \ && docker-php-ext-configure intl \ && docker-php-ext-configure gd --with-freetype --with-jpeg \ - && docker-php-ext-install -j"$(nproc)" \ - intl opcache zip bcmath mbstring gd pdo pdo_pgsql pgsql \ - # Cleanup + && docker-php-ext-install -j"$(nproc)" intl opcache zip bcmath mbstring gd pdo pdo_pgsql pgsql \ && apk del .build-deps \ && rm -rf /var/cache/apk/* /tmp/* @@ -54,27 +50,39 @@ echo "opcache.max_accelerated_files=20000"; \ } > /usr/local/etc/php/conf.d/laravel.ini - # Prepare dirs + # Dirs RUN mkdir -p /run/php /run/nginx /var/log/supervisor /var/www/html /etc/nginx/http.d - # Copy app and vendor + # Copy app + vendor COPY --from=app_src /app /var/www/html COPY --from=vendor /app/vendor /var/www/html/vendor -# Copy configs -COPY deploy/nginx/default.conf /etc/nginx/http.d/default.conf -COPY deploy/supervisord.conf /etc/supervisord.conf -COPY deploy/php-fpm/zz-socket.conf /usr/local/etc/php-fpm.d/zz-socket.conf -COPY deploy/entrypoint.sh /usr/local/bin/entrypoint.sh - -# Ensure executable -RUN chmod +x /usr/local/bin/entrypoint.sh - -# Healthcheck and ports (unchanged) -EXPOSE 80 -HEALTHCHECK --interval=30s --timeout=5s --retries=5 \ - CMD curl -fsS http://localhost/healthz || exit 1 - -# Use the entrypoint to run artisan warmups, then exec supervisord -ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] -CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"] \ No newline at end of file + # Nginx, PHP-FPM socket, Supervisor, entrypoint + COPY deploy/nginx/default.conf /etc/nginx/http.d/default.conf + COPY deploy/php-fpm/zz-socket.conf /usr/local/etc/php-fpm.d/zz-socket.conf + COPY deploy/php-fpm/zz-logging.conf /usr/local/etc/php-fpm.d/zz-logging.conf + COPY deploy/supervisord.conf /etc/supervisord.conf + COPY deploy/entrypoint.sh /usr/local/bin/entrypoint.sh + RUN chmod +x /usr/local/bin/entrypoint.sh + + WORKDIR /var/www/html + + # Never ship stale compiled caches + RUN rm -rf bootstrap/cache/*.php || true + + # Laravel write perms + RUN set -eux; \ + mkdir -p storage bootstrap/cache; \ + chown -R www-data:www-data storage bootstrap/cache; \ + find storage -type d -exec chmod 775 {} \; ; \ + find storage -type f -exec chmod 664 {} \; ; \ + chmod -R 775 bootstrap/cache + + EXPOSE 80 + HEALTHCHECK --interval=30s --timeout=5s --retries=5 \ + CMD curl -fsS http://localhost/healthz || exit 1 + + # Default: just start services; artisan is opt-in via env + ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] + CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"] + \ No newline at end of file diff --git a/deploy/entrypoint.sh b/deploy/entrypoint.sh index 448d1c0..e179105 100644 --- a/deploy/entrypoint.sh +++ b/deploy/entrypoint.sh @@ -1,31 +1,23 @@ #!/usr/bin/env sh set -e -# -------- Options (env flags) -------- -: "${ARTISAN_BOOT:=1}" # set to 0 to skip all artisan work -: "${ARTISAN_DB_WAIT:=0}" # set to 1 to wait for DB before artisan -: "${ARTISAN_MIGRATE:=0}" # set to 1 to run php artisan migrate --force -: "${ARTISAN_HORIZON:=0}" # set to 1 to start Horizon under supervisord (add program if you want) -: "${ARTISAN_VERBOSE:=0}" # set to 1 for more logs +# Default: DO NOT run artisan on boot (avoid provider issues) +: "${ARTISAN_BOOT:=0}" +: "${ARTISAN_DB_WAIT:=0}" +: "${ARTISAN_MIGRATE:=0}" +: "${ARTISAN_VERBOSE:=0}" log() { [ "$ARTISAN_VERBOSE" = "1" ] && echo "[entrypoint] $*"; } warn() { echo "[entrypoint] $*" 1>&2; } cd /var/www/html || true -if [ "$ARTISAN_BOOT" != "1" ]; then - log "ARTISAN_BOOT=0 → skipping artisan boot steps." +if [ "$ARTISAN_BOOT" != "1" ] || [ ! -f artisan ]; then + [ ! -f artisan ] && warn "artisan not found; skipping artisan." exec /usr/bin/supervisord -c /etc/supervisord.conf fi -if [ ! -f artisan ]; then - warn "artisan not found; skipping artisan steps." - exec /usr/bin/supervisord -c /etc/supervisord.conf -fi - -# -------- Optional: wait for Postgres -------- if [ "$ARTISAN_DB_WAIT" = "1" ] && [ -n "$DB_HOST" ] && [ -n "$DB_PORT" ]; then - # Use PHP + sockets to test TCP if pg_isready isn't available log "Waiting for DB ${DB_HOST}:${DB_PORT} ..." i=0 until php -r ' @@ -33,26 +25,19 @@ if [ "$ARTISAN_DB_WAIT" = "1" ] && [ -n "$DB_HOST" ] && [ -n "$DB_PORT" ]; then $s=@fsockopen($h,$p,$errno,$errstr,1.0); if($s){fclose($s); exit(0);} exit(1); '; do - i=$((i+1)) - if [ $i -gt 60 ]; then - warn "DB wait timed out after 60s — continuing anyway." - break - fi + i=$((i+1)); [ $i -gt 60 ] && warn "DB wait timed out after 60s" && break sleep 1 done fi -# -------- Safe, cache-warming steps -------- -# Don’t fail the container if any step errors (env may be partial in some setups) -php artisan package:discover --ansi || warn "package:discover failed" -php artisan config:cache --ansi || warn "config:cache failed" -php artisan route:cache --ansi || warn "route:cache failed" -php artisan view:cache --ansi || warn "view:cache failed" - -# -------- (Optional) database migrations -------- -if [ "$ARTISAN_MIGRATE" = "1" ]; then - php artisan migrate --force --no-interaction --ansi || warn "migrate failed" +if php artisan package:discover --ansi; then + php artisan config:cache --ansi || warn "config:cache failed" + php artisan route:cache --ansi || warn "route:cache failed" + php artisan view:cache --ansi || warn "view:cache failed" +else + warn "package:discover failed — skipping caches." fi -# -------- Hand off to supervisord -------- +[ "$ARTISAN_MIGRATE" = "1" ] && php artisan migrate --force --no-interaction --ansi || true + exec /usr/bin/supervisord -c /etc/supervisord.conf diff --git a/deploy/nginx/default.conf b/deploy/nginx/default.conf index 0e81bae..0c7c6f4 100644 --- a/deploy/nginx/default.conf +++ b/deploy/nginx/default.conf @@ -5,10 +5,8 @@ server { root /var/www/html/public; index index.php; - # Health check (no PHP) location = /healthz { return 200 "ok\n"; add_header Content-Type text/plain; } - # Static assets location ~* \.(?:css|js|mjs|map|jpg|jpeg|png|gif|ico|svg|webp|avif|ttf|otf|woff|woff2)$ { access_log off; log_not_found off; expires 7d; @@ -16,12 +14,10 @@ server { try_files $uri =404; } - # Laravel front controller location / { try_files $uri $uri/ /index.php?$query_string; } - # PHP via unix socket (shared with php-fpm) location ~ \.php$ { include fastcgi_params; fastcgi_index index.php; diff --git a/deploy/php-fpm/zz-logging.conf b/deploy/php-fpm/zz-logging.conf new file mode 100644 index 0000000..77d59b5 --- /dev/null +++ b/deploy/php-fpm/zz-logging.conf @@ -0,0 +1,2 @@ +[global] +error_log = /dev/stderr diff --git a/deploy/php-fpm/zz-socket.conf b/deploy/php-fpm/zz-socket.conf index fc278b2..e232229 100644 --- a/deploy/php-fpm/zz-socket.conf +++ b/deploy/php-fpm/zz-socket.conf @@ -1,24 +1,16 @@ -; Use a unix socket and ensure nginx can access it -[global] -; (keep global defaults) - [www] listen = /run/php/php-fpm.sock listen.owner = www-data listen.group = nginx listen.mode = 0660 - -; Keep default user/group for PHP workers user = www-data group = www-data -; Sensible FPM settings pm = dynamic pm.max_children = 10 pm.start_servers = 2 pm.min_spare_servers = 2 pm.max_spare_servers = 5 -; Clear env for security, but allow PATH clear_env = yes env[PATH] = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin diff --git a/deploy/supervisord.conf b/deploy/supervisord.conf index 5273030..8d306b7 100644 --- a/deploy/supervisord.conf +++ b/deploy/supervisord.conf @@ -4,7 +4,7 @@ logfile=/var/log/supervisor/supervisord.log [program:php-fpm] command=/usr/local/sbin/php-fpm -F -user=www-data +; run as root (master); FPM will drop to www-data for workers autorestart=true priority=10 stdout_logfile=/dev/stdout @@ -14,7 +14,7 @@ stderr_logfile_maxbytes=0 [program:nginx] command=/usr/sbin/nginx -g "daemon off;" -user=nginx +; run as root (master); nginx will use 'user nginx;' for workers autorestart=true priority=20 stdout_logfile=/dev/stdout