Dockerfile 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. # --- Stage 1: compile Tailwind CSS + vendor JS deps ----------------------
  2. # Runs the Tailwind JIT over views/, src/, and our JS so only classes that
  3. # are actually referenced end up in the output. No runtime <style> injection,
  4. # which lets the CSP drop 'unsafe-inline' for style-src.
  5. #
  6. # The same stage also vendors Alpine.js (CSP build), htmx, and SortableJS
  7. # from npm into /build/vendor/ — copied into the runtime image alongside the
  8. # CSS so the strict CSP can keep `script-src 'self'`.
  9. FROM node:20-alpine AS css-builder
  10. WORKDIR /build
  11. COPY package.json package-lock.json* ./
  12. RUN npm ci --no-audit --no-fund
  13. # Only the files that contribute to class discovery / the entry stylesheet.
  14. COPY tailwind.config.js ./
  15. COPY assets/css/input.css ./assets/css/input.css
  16. COPY views/ ./views/
  17. COPY src/ ./src/
  18. COPY public/assets/js/ ./public/assets/js/
  19. RUN npx tailwindcss -i ./assets/css/input.css -o /build/app.css --minify
  20. # Pin the vendored JS bundles. Alpine CSP is the variant that doesn't need
  21. # `unsafe-eval`; standard Alpine would require relaxing the CSP.
  22. RUN mkdir -p /build/vendor \
  23. && cp node_modules/@alpinejs/csp/dist/cdn.min.js /build/vendor/alpine-csp.min.js \
  24. && cp node_modules/htmx.org/dist/htmx.min.js /build/vendor/htmx.min.js \
  25. && cp node_modules/sortablejs/Sortable.min.js /build/vendor/sortable.min.js
  26. # --- Stage 2: the actual PHP runtime ------------------------------------
  27. FROM php:8.3-apache
  28. RUN apt-get update && apt-get install -y --no-install-recommends \
  29. libsqlite3-dev unzip git \
  30. && docker-php-ext-install pdo pdo_sqlite \
  31. && a2enmod rewrite \
  32. && rm -rf /var/lib/apt/lists/*
  33. COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
  34. WORKDIR /var/www/html
  35. COPY composer.json composer.lock* ./
  36. RUN composer install --no-dev --no-interaction --prefer-dist --no-progress
  37. COPY . .
  38. # Place the compiled CSS + vendored JS where Apache can serve them.
  39. COPY --from=css-builder /build/app.css /var/www/html/public/assets/css/app.css
  40. COPY --from=css-builder /build/vendor/ /var/www/html/public/assets/js/vendor/
  41. # Twig cache lives under data/ alongside the SQLite file. www-data must be
  42. # able to write there at request time so first-render template compilation
  43. # succeeds.
  44. RUN mkdir -p /var/www/data /var/www/data/sessions /var/www/html/data/twig-cache \
  45. && chown -R www-data:www-data /var/www/data /var/www/html/data \
  46. && printf '%s\n' \
  47. '<VirtualHost *:80>' \
  48. ' DocumentRoot /var/www/html/public' \
  49. ' <Directory /var/www/html/public>' \
  50. ' Options -Indexes +FollowSymLinks' \
  51. ' AllowOverride All' \
  52. ' Require all granted' \
  53. ' FallbackResource /index.php' \
  54. ' </Directory>' \
  55. ' ErrorLog ${APACHE_LOG_DIR}/error.log' \
  56. ' CustomLog ${APACHE_LOG_DIR}/access.log combined' \
  57. '</VirtualHost>' \
  58. > /etc/apache2/sites-available/000-default.conf
  59. EXPOSE 80
  60. CMD ["apache2-foreground"]