Files
ADconsle/docker/php/Dockerfile
T
kzbkowskiandClaude Sonnet 5 b313c126ce
CI / PHP 8.2 (push) Failing after 1m40s
CI / PHP 8.3 (push) Failing after 55s
CI / PHP 8.4 (push) Failing after 1m11s
Release image / image (push) Successful in 2m33s
ADconsole v1.1.0
Config backup, a Docker dev/prod split, and a Gitea-built release image.

Added
- /settings -> General -> "Configuration backup": JSON export/import of the
  panel's general settings + attribute definitions
  (App\Services\ConfigBackupService); audited as config.export / config.import.
  Export can leave out the attribute-encryption key. No AD data included.
- docker/compose.dev.yaml: live-reload dev stack that bind-mounts the working
  tree. docker/php/Dockerfile is now multi-stage (base -> dev / prod).
- .github/workflows/release.yml: on every vX.Y.Z tag, builds the prod image and
  pushes gitea.kzbikowski.pl/kzbkowski/adconsole:{X.Y.Z,X.Y,latest}.

Changed
- docker/compose.yaml: self-contained prod image (app code + composer install
  --no-dev baked in via COPY); persistent state in docker/data/{app_storage,db};
  defaults to the released image (ADCONSOLE_VERSION pins a tag, ADCONSOLE_IMAGE
  replaces the ref). Apache now honours public/.htaccess (AllowOverride All).
  Run from the repo root with --env-file .env.
- Repo root now holds only README.md; CHANGELOG / CONTRIBUTING / SECURITY /
  CODE_OF_CONDUCT moved under docs/.

Upgrade notes: docs/upgrading.md#v110--docker-layout. Full log: docs/CHANGELOG.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JKT9p3bfP8RZesExdYCS52
2026-09-10 09:13:04 +02:00

105 lines
4.3 KiB
Docker

# syntax=docker/dockerfile:1
# =============================================================================
# ADconsole container image — PHP 8.4 + Apache. Multi-stage:
#
# base : PHP + extensions + Apache (docroot = public/) + Composer + entrypoint
# dev : base only. The repo is bind-mounted at runtime (compose.dev.yaml);
# the entrypoint installs deps + generates APP_KEY on first boot and
# opcache re-checks files on every request, so edits are live.
# prod : base + the application COPYed in and `composer install --no-dev`
# run at build time → a self-contained image (docker/compose.yaml, or
# `docker build`) that you can tag and push straight from the repo;
# only .env and docker/data/ are mounted at runtime.
#
# Build context is the repo root. Default target is `prod` (last stage):
# docker build -f docker/php/Dockerfile -t adconsole:local .
# =============================================================================
FROM php:8.4-apache AS base
# --- System packages + PHP extensions -------------------------------------
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
libcurl4-openssl-dev \
libonig-dev \
libzip-dev \
libldap2-dev \
unzip \
git \
&& docker-php-ext-install -j"$(nproc)" curl mbstring zip pdo pdo_mysql ldap opcache \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Apache: enable rewrite + serve from public/ + honour Laravel's public/.htaccess.
ENV APACHE_DOCUMENT_ROOT=/var/www/html/public
RUN a2enmod rewrite headers \
&& sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf \
&& sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf \
&& printf '<Directory ${APACHE_DOCUMENT_ROOT}>\n\tAllowOverride All\n\tRequire all granted\n</Directory>\n' \
> /etc/apache2/conf-available/adconsole.conf \
&& a2enconf adconsole
# Composer (from the official image, no network installer).
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
COPY docker/php/entrypoint.sh /usr/local/bin/adconsole-entrypoint
RUN chmod +x /usr/local/bin/adconsole-entrypoint
ENV COMPOSER_ALLOW_SUPERUSER=1
WORKDIR /var/www/html
ENTRYPOINT ["adconsole-entrypoint"]
CMD ["apache2-foreground"]
# =============================================================================
# dev — no app code baked in; compose.dev.yaml bind-mounts the repo over
# /var/www/html. opcache revalidates on every hit so changes show immediately.
# =============================================================================
FROM base AS dev
ENV ADCONSOLE_ENV=dev
RUN { \
echo 'opcache.enable=1'; \
echo 'opcache.enable_cli=0'; \
echo 'opcache.validate_timestamps=1'; \
echo 'opcache.revalidate_freq=0'; \
} > /usr/local/etc/php/conf.d/opcache.ini
# =============================================================================
# prod (default) — self-contained image. The build context is trimmed by
# .dockerignore (no vendor/, node_modules/, tests/, docs/, .env, ./data …).
# =============================================================================
FROM base AS prod
ENV ADCONSOLE_ENV=prod
# Aggressive opcache: the code in the image never changes at runtime.
RUN { \
echo 'opcache.enable=1'; \
echo 'opcache.enable_cli=0'; \
echo 'opcache.memory_consumption=128'; \
echo 'opcache.max_accelerated_files=20000'; \
echo 'opcache.validate_timestamps=0'; \
} > /usr/local/etc/php/conf.d/opcache.ini
# 1. Dependencies — manifests first so this layer survives code-only edits.
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-interaction --prefer-dist --no-scripts --no-autoloader
# 2. Application code.
COPY . .
# 3. Optimised autoloader + package discovery, then the writable runtime tree.
RUN composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader \
&& mkdir -p \
storage/framework/cache/data \
storage/framework/sessions \
storage/framework/views \
storage/logs \
storage/app/public \
storage/app/private \
bootstrap/cache \
&& chown -R www-data:www-data storage bootstrap/cache