tina4 3.8.74

Tina4 — Unified CLI for Python, PHP, Ruby, and Node.js frameworks
# Tina4 PHP — PHP-FPM + nginx production image. Generated by
# `tina4 deploy docker --runtime fpm`.
#
# WHEN TO PICK THIS. FPM is the boring, safe default for a mixed web app:
# every request gets a FRESH process state, so nothing leaks between requests
# and a fatal in one request cannot poison the next. It is what most PHP
# hosting already runs, so it is the easiest to operate and to hand to an ops
# team that has never heard of Tina4.
#
# The trade is per-request bootstrap cost. OPcache removes most of it (the
# bytecode is cached across requests), but the app object is still rebuilt
# each time. For an API where that cost dominates, the swoole image keeps the
# app resident instead - at the price of the resident-state rules documented
# there.
#
# nginx and php-fpm both run here, started by a tiny entrypoint rather than
# supervisord: two processes, one of which must not outlive the other. The
# entrypoint execs nginx in the foreground after php-fpm is up, so a dead
# php-fpm takes the container down instead of leaving nginx serving 502s.
ARG TINA4_CLI_IMAGE=ghcr.io/tina4stack/tina4-cli:v3.8.63
FROM ${TINA4_CLI_IMAGE} AS tina4cli

FROM composer:2 AS deps
WORKDIR /app
COPY composer.json composer.lock* ./
RUN composer install --no-dev --optimize-autoloader --no-scripts

FROM php:8.4-fpm
WORKDIR /app
COPY --from=tina4cli /usr/local/bin/tina4 /usr/local/bin/tina4

RUN apt-get update \
 && apt-get install -y --no-install-recommends nginx libsqlite3-dev \
 && docker-php-ext-install -j"$(nproc)" pdo_sqlite opcache \
 && rm -rf /var/lib/apt/lists/*

# Production OPcache. Without this every request re-compiles every PHP file,
# which is the single biggest avoidable cost on the FPM path.
RUN { \
      echo 'opcache.enable=1'; \
      echo 'opcache.memory_consumption=192'; \
      echo 'opcache.max_accelerated_files=20000'; \
      echo 'opcache.validate_timestamps=0'; \
    } > /usr/local/etc/php/conf.d/99-opcache.ini

# NOTE: no pcntl here, deliberately. php-fpm supplies the worker pool, so the
# framework's own forking and TINA4_SERVE_WORKERS are not used on this path -
# index.php is invoked per request by fpm and never runs the accept loop.
COPY --from=deps /app/vendor /app/vendor
COPY . /app

COPY nginx.fpm.conf /etc/nginx/sites-available/default
COPY docker-entrypoint.fpm.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh \
 && chown -R www-data:www-data /app

ENV TINA4_OVERRIDE_CLIENT=true \
    TINA4_DEBUG=false
EXPOSE 7145

CMD ["/usr/local/bin/docker-entrypoint.sh"]