Dockerfile
Rama main · réplica de lectura del repositorio original.
# syntax=docker/dockerfile:1.28@sha256:bb22d9815c728170f72750f4e5b0d672e06176142e1d602c7e66c050100b7e5b
# Renovate needs the complete image reference to update both the tag and digest.
ARG PHP_IMAGE=php:8.5-apache@sha256:08af36df144462d84c7f16190557eec06cb9f656882685610b712a15eec54d46
# Keep PHP_VERSION overrides working without applying the default image's digest.
ARG PHP_VERSION
ARG PHP_VERSION_IMAGE=${PHP_VERSION:+php:${PHP_VERSION}-apache}
ARG NODE_VERSION=26
FROM ${PHP_VERSION_IMAGE:-${PHP_IMAGE}} AS php-base
RUN set -eux; \
savedAptMark="$(apt-mark showmanual)"; \
apt-get update; \
apt-get install -y --no-install-recommends \
ca-certificates \
cron \
curl \
libbz2-dev \
libfreetype6-dev \
libicu-dev \
libjpeg62-turbo-dev \
libpng-dev \
libzip-dev \
unzip \
zlib1g-dev; \
docker-php-ext-configure gd --with-freetype --with-jpeg; \
docker-php-ext-install -j"$(nproc)" bz2 gd intl pdo_mysql zip; \
a2enmod rewrite; \
apt-mark auto '.*' > /dev/null; \
apt-mark manual \
${savedAptMark} \
ca-certificates \
cron \
curl \
unzip; \
find /usr/local -type f \( -perm /0111 -o -name '*.so' \) -exec sh -c 'ldd "$@" 2>/dev/null' sh '{}' + \
| awk 'NF == 4 && $2 == "=>" { print $3 } NF == 2 && $1 ~ /^\// { print $1 }' \
| sort -u \
| while read -r library; do \
library="$(readlink -e "${library}")"; \
dpkg-query --search "${library}" 2>/dev/null | grep -v '^diversion ' | head -n1 | cut -d: -f1; \
done \
| sort -u \
| xargs -r apt-mark manual; \
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
apt-get clean; \
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
FROM php-base AS composer-base
WORKDIR /app
COPY --from=composer:2@sha256:8de2184c6de224f4689e8f80ed5f5edaf0030b6b8b7839a22a2bcb6722ac87d0 /usr/bin/composer /usr/bin/composer
RUN apt-get update \
&& apt-get install -y --no-install-recommends git \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/*
FROM composer-base AS php-vendor
COPY composer.json composer.lock ./
COPY src/core ./src/core
COPY src/library ./src/library
COPY src/modules ./src/modules
RUN --mount=type=cache,target=/tmp/composer-cache,id=composer-prod \
set -eux; \
find ./src/modules -type d -name tests -prune -exec rm -rf {} +; \
COMPOSER_CACHE_DIR=/tmp/composer-cache \
composer install --prefer-dist --no-dev --optimize-autoloader --no-interaction --no-progress
FROM composer-base AS php-dev-vendor
COPY composer.json composer.lock ./
COPY src/core ./src/core
COPY src/library ./src/library
COPY src/modules ./src/modules
RUN --mount=type=cache,target=/tmp/composer-cache,id=composer-dev \
COMPOSER_CACHE_DIR=/tmp/composer-cache \
composer install --prefer-dist --optimize-autoloader --no-interaction --no-progress
FROM node:${NODE_VERSION}-bookworm-slim AS frontend-assets
WORKDIR /app
COPY package.json package-lock.json ./
COPY src/themes/default/admin/package.json src/themes/default/admin/package.json
COPY src/themes/default/client/package.json src/themes/default/client/package.json
RUN --mount=type=cache,target=/root/.npm npm ci
COPY tsconfig.json ./
COPY src/themes/default/admin ./src/themes/default/admin
COPY src/themes/default/client ./src/themes/default/client
COPY src/modules ./src/modules
COPY frontend ./frontend
RUN NODE_ENV=production npm run build
FROM php-base AS release-tree
WORKDIR /app
ARG FOSSBILLING_VERSION=0.0.1
ARG FOSSBILLING_VERSION_TRUNCATE=0
ARG SENTRY_DSN=
ARG INSTALL_TRANSLATIONS=true
ARG TRANSLATIONS_URL=https://github.com/FOSSBilling/locale/releases/latest/download/translations.zip
ARG TRANSLATIONS_SHA256=
COPY --from=composer:2@sha256:8de2184c6de224f4689e8f80ed5f5edaf0030b6b8b7839a22a2bcb6722ac87d0 /usr/bin/composer /usr/bin/composer
COPY composer.json ./composer.json
COPY src ./src
COPY README.md LICENSE ./src/
COPY --from=php-vendor /app/src/vendor ./src/vendor
COPY --from=frontend-assets /app/src/public/assets ./src/public/assets
COPY --from=frontend-assets /app/src/themes/default/admin/assets/build ./src/themes/default/admin/assets/build
COPY --from=frontend-assets /app/src/themes/default/client/assets/build ./src/themes/default/client/assets/build
RUN set -eux; \
find ./src/modules -type d -name tests -prune -exec rm -rf {} +; \
mkdir -p ./src/locale; \
if [ "${INSTALL_TRANSLATIONS}" = "true" ]; then \
curl -fsSL "${TRANSLATIONS_URL}" -o /tmp/translations.zip; \
if [ -n "${TRANSLATIONS_SHA256}" ]; then \
echo "${TRANSLATIONS_SHA256} /tmp/translations.zip" | sha256sum -c -; \
fi; \
unzip -oq /tmp/translations.zip -d ./src/locale; \
rm /tmp/translations.zip; \
fi; \
FOSSBILLING_VERSION="${FOSSBILLING_VERSION}" \
FOSSBILLING_VERSION_TRUNCATE="${FOSSBILLING_VERSION_TRUNCATE}" \
SENTRY_DSN="${SENTRY_DSN}" \
php -r '$version = getenv("FOSSBILLING_VERSION") ?: "0.0.1"; $truncate = (int) (getenv("FOSSBILLING_VERSION_TRUNCATE") ?: 0); if ($truncate > 0) { $version = substr($version, 0, $truncate); } $versionFile = "./src/core/System/Version.php"; $contents = file_get_contents($versionFile); $quote = chr(39); $pattern = "/public const string VERSION = " . $quote . "[^" . $quote . "]+" . $quote . ";/"; $replacement = "public const string VERSION = " . var_export($version, true) . ";"; $contents = preg_replace($pattern, $replacement, $contents, 1, $count); if ($contents === null || $count !== 1) { fwrite(STDERR, "Failed to replace FOSSBilling version.\n"); exit(1); } file_put_contents($versionFile, $contents); $dsn = getenv("SENTRY_DSN"); if ($dsn !== false && $dsn !== "") { $sentryFile = "./src/core/SentryHelper.php"; file_put_contents($sentryFile, str_replace("--replace--this--during--release--process--", $dsn, file_get_contents($sentryFile))); }'; \
php -r '$version = getenv("FOSSBILLING_VERSION") ?: "0.0.1"; if (!preg_match("/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/", $version)) { exit(0); } foreach (glob("./src/modules/*/manifest.json") as $file) { $new = preg_replace("/\"version\": \"[^\"]+\"/", "\"version\": \"{$version}\"", file_get_contents($file), 1, $count); if ($new === null || $count !== 1) { fwrite(STDERR, "Failed to stamp the version in {$file}.\n"); exit(1); } file_put_contents($file, $new); }'; \
php -r '$composer = json_decode(file_get_contents("./composer.json"), true, 512, JSON_THROW_ON_ERROR); $composer["autoload"]["psr-4"]["FOSSBilling\\Core\\"] = "core/"; $composer["autoload"]["psr-4"]["Box\\Mod\\"] = "modules/"; $composer["autoload"]["classmap"] = ["library/"]; $composer["config"]["vendor-dir"] = "vendor"; file_put_contents("./src/composer.json", json_encode($composer, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . PHP_EOL);'; \
composer --no-plugins dump-autoload --working-dir=./src --no-dev --optimize --no-interaction; \
php -r '$class = "FOSSBilling\\Core\\Cache\\CacheFactory"; require "./src/vendor/autoload.php"; if (!class_exists($class)) { fwrite(STDERR, "Release Composer autoloader is missing {$class}.\n"); exit(1); }'; \
rm ./composer.json ./src/composer.json; \
chmod -R u=rwX,go=rX ./src
FROM scratch AS release-artifact
COPY --from=release-tree /app/src /
FROM php-base AS runtime
WORKDIR /var/www/html
COPY --from=release-tree --chown=www-data:www-data /app/src/ ./
RUN set -eux; \
mkdir -p data/cache data/log data/uploads; \
touch /var/log/cron.log; \
chown -R www-data:www-data data /var/log/cron.log; \
echo '*/5 * * * * /usr/local/bin/php /var/www/html/cron.php >> /var/log/cron.log 2>&1' > /tmp/www-data.cron; \
crontab -u www-data /tmp/www-data.cron; \
rm /tmp/www-data.cron
CMD ["sh", "-c", "cron & exec apache2-foreground"]
FROM runtime AS test
WORKDIR /workspace
COPY --from=release-tree /app/src ./src
COPY src/modules ./src/modules
COPY --from=php-dev-vendor /app/src/vendor ./src/vendor
COPY composer.json composer.lock phpstan.neon phpunit.xml.dist ./
COPY tests ./tests
COPY tools ./tools
RUN set -eux; \
php -r '$config = require "./src/config-sample.php"; file_put_contents("./src/config.php", "<?php\nreturn " . var_export($config, true) . ";\n");'; \
mkdir -p ./src/data/cache ./src/data/log ./src/data/uploads; \
chown -R www-data:www-data ./src/data ./src/config.php