trypost/docker/entrypoint.sh
André Dantas 1a74dfc60e fix(docker): production build/runtime fixes from homelab deploy
- Add libwebp-dev + libavif-dev and --with-webp --with-avif to GD
  configure (fixes imagewebp() undefined at runtime)
- Merge wayfinder-gen into asset-build stage: PHP + Node together
  so @laravel/vite-plugin-wayfinder can invoke artisan during build
- Pass VITE_* as build args and ENV so they bake into the bundle
- Stub APP_URL=http://localhost so artisan boot doesn't crash on null
- mkdir -p storage/framework/{cache/data,sessions,views} storage/logs
  bootstrap/cache before artisan runs (dirs stripped by .dockerignore)
- Production stage: rm vendor + bootstrap/cache/*.php before swapping
  to prod-only deps (prevents missing-provider errors from dev cache)
- Switch production chown from app:app to www-data:www-data to match
  Alpine php-fpm default pool user
2026-05-12 23:44:55 -03:00

112 lines
4 KiB
Bash
Executable file

#!/bin/sh
# TryPost — container entrypoint. Idempotent first-run setup, then exec supervisord.
set -e
cd /var/www/html
TARGET="${TRYPOST_TARGET:-dev}"
# 1) Bootstrap .env from the Docker template on first dev boot. The bind-mount
# in dev hides /var/www/html/.env.docker.example, so prefer docker/ first.
if [ "${TRYPOST_DOCKER_BOOTSTRAP:-0}" = "1" ] && [ ! -f .env ]; then
if [ -f docker/.env.docker.example ]; then
echo "[entrypoint] seeding .env from docker/.env.docker.example"
cp docker/.env.docker.example .env
elif [ -f .env.docker.example ]; then
echo "[entrypoint] seeding .env from .env.docker.example"
cp .env.docker.example .env
fi
# Hand the seeded .env over to the host user so they can edit it.
chown "${UID:-1000}:${GID:-1000}" .env 2>/dev/null || true
fi
# 2) Skip-bootstrap escape hatch for advanced users.
if [ "${TRYPOST_SKIP_BOOTSTRAP:-0}" = "1" ]; then
echo "[entrypoint] TRYPOST_SKIP_BOOTSTRAP=1 — exec'ing supervisord without setup"
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
fi
# 3) Re-install composer deps if vendor was wiped (down -v in dev).
if [ "${TARGET}" = "dev" ] && [ ! -f vendor/autoload.php ]; then
echo "[entrypoint] vendor/ missing — running composer install"
composer install --no-interaction --prefer-dist
fi
# 4) Re-install node_modules if empty/wiped (dev only; vite needs them).
# Anonymous volumes pre-create the dir, so check for npm's lockfile instead.
if [ "${TARGET}" = "dev" ] && [ ! -f node_modules/.package-lock.json ]; then
echo "[entrypoint] node_modules/ empty — running npm ci"
npm ci --no-audit --no-fund
fi
# 5) APP_KEY — generate on first boot if blank.
if [ -f .env ] && ! grep -qE '^APP_KEY=base64:' .env; then
echo "[entrypoint] generating APP_KEY"
php artisan key:generate --force
fi
# 6) Wait for Postgres to be reachable.
DB_HOST_VALUE="${DB_HOST:-pgsql}"
DB_PORT_VALUE="${DB_PORT:-5432}"
DB_USER_VALUE="${DB_USERNAME:-postgres}"
DB_NAME_VALUE="${DB_DATABASE:-trypost}"
echo "[entrypoint] waiting for postgres at ${DB_HOST_VALUE}:${DB_PORT_VALUE}"
WAIT_ATTEMPTS=0
until pg_isready -h "${DB_HOST_VALUE}" -p "${DB_PORT_VALUE}" -U "${DB_USER_VALUE}" -d "${DB_NAME_VALUE}" >/dev/null 2>&1; do
WAIT_ATTEMPTS=$((WAIT_ATTEMPTS + 1))
if [ "${WAIT_ATTEMPTS}" -gt 60 ]; then
echo "[entrypoint] postgres not reachable after 60s — continuing anyway"
break
fi
sleep 1
done
# 7) Run migrations (graceful: succeeds even when nothing to migrate).
echo "[entrypoint] running migrations"
php artisan migrate --force --graceful || true
# 8) storage:link if missing.
if [ ! -L public/storage ]; then
echo "[entrypoint] linking storage"
php artisan storage:link --force || true
fi
# 9) Passport keys on first boot.
if [ ! -f storage/oauth-private.key ]; then
echo "[entrypoint] generating Passport keys"
php artisan passport:keys --force || true
fi
# 10) Wayfinder TS regen — Vite needs the files before it boots.
echo "[entrypoint] regenerating wayfinder helpers"
php artisan wayfinder:generate --with-form || true
# 11) Cache strategy: prod = pre-cache; dev = clear.
if [ "${TARGET}" = "production" ]; then
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
else
php artisan config:clear
php artisan route:clear
php artisan view:clear
php artisan event:clear
fi
# 12) Permissions. Production php-fpm pool runs as www-data (Alpine default),
# so storage and bootstrap/cache must be writable by that user — Laravel
# needs to write session files, view cache, log files, etc.
if [ "${TARGET}" = "production" ]; then
chown -R www-data:www-data storage bootstrap/cache
else
# Dev: ensure UID-mapped user owns runtime dirs.
APP_UID="${UID:-1000}"
APP_GID="${GID:-1000}"
chown -R "${APP_UID}:${APP_GID}" storage bootstrap/cache 2>/dev/null || true
fi
echo "[entrypoint] ready — handing off to supervisord"
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf