Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/lerichardv/patolab-platform/llms.txt

Use this file to discover all available pages before exploring further.

PatoLab ships with a production-ready dockerfile that packages the Laravel application, Nginx, PHP-FPM, and Chromium into a single self-contained image. The container runs Nginx and PHP-FPM concurrently under Supervisor, exposes the application on port 8080, and includes the Node.js toolchain and Chromium binary needed for PDF invoice generation via Spatie Browsershot. Frontend assets are compiled during the image build so the final container has no runtime dependency on Node or npm.

Dockerfile Overview

The build uses a single-stage image based on php:8.3-fpm:
FROM php:8.3-fpm

System packages installed

The following system packages are installed at build time:
  • nginx — reverse proxy / web server
  • supervisor — process manager that keeps Nginx and PHP-FPM alive
  • chromium — headless browser for Browsershot PDF generation
  • nodejs / npm — required to compile React/TypeScript frontend assets during the build
  • git, unzip, curl, zip — general-purpose utilities used during dependency installation
  • PHP extension dependencies: libzip-dev, libpng-dev, libjpeg62-turbo-dev, libfreetype6-dev, libonig-dev

PHP extensions installed

pdo  pdo_mysql  mbstring  bcmath  gd  zip  opcache

Build steps summary

StageWhat happens
System installapt-get installs Nginx, Supervisor, Chromium, Node.js, and PHP extension libs
PHP extensionsdocker-php-ext-install compiles pdo pdo_mysql mbstring bcmath gd zip opcache
Composer installcomposer install --no-dev --optimize-autoloader with a dependency-cache layer
npm installnpm ci with a dependency-cache layer
Application copyFull source is copied into /app
Storage setupstorage/ and bootstrap/cache/ directories are created and chowned to www-data
Autoload dumpcomposer dump-autoload --no-dev --optimize re-generates the classmap after the full source copy
Asset buildphp artisan storage:link, php artisan wayfinder:generate --with-form, then npm run build compile the React bundle
Nginx configInline RUN echo writes the virtual-host config to /etc/nginx/sites-available/default
Supervisor configInline RUN echo writes the php-fpm + nginx process definitions

Working directory and exposed port

WORKDIR /app
EXPOSE 8080
Nginx listens on port 8080 (not 80) to allow the container to run without root network privileges.

Process manager (CMD)

The container entrypoint fixes runtime permissions, then hands off to Supervisor:
CMD ["sh", "-c", "\
    chmod -R 775 /app/storage /app/bootstrap/cache && \
    chmod -R 755 /app/public && \
    chown -R www-data:www-data /app/storage /app/bootstrap/cache /app/public && \
    /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf"]
Supervisor runs two long-lived processes:
ProgramCommand
php-fpmphp-fpm
nginxnginx -g "daemon off;"
Both are configured with autorestart=true and write their logs to stdout/stderr so they appear in docker logs.

Required Environment Variables

Pass these variables to the container via --env flags or a --env-file:

Application

VariableRequiredExample value
APP_KEYbase64:... (generate with php artisan key:generate --show)
APP_URLhttps://patolab.example.com
APP_ENVproduction
APP_DEBUGfalse

Database

VariableRequiredExample value
DB_CONNECTIONmysql or pgsql
DB_HOSTdb (service name) or IP address
DB_PORT3306 (MySQL) / 5432 (PostgreSQL)
DB_DATABASEpatolab
DB_USERNAMEpatolab_user
DB_PASSWORDstrongpassword

Queue and PDF

VariableRequiredExample value
QUEUE_CONNECTIONdatabase
BROWSERSHOT_CHROME_PATH/usr/bin/chromium
PUPPETEER_EXECUTABLE_PATHRecommended/usr/bin/chromium
The Dockerfile pre-sets PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium as a build-time ENV. Passing it at runtime overrides the build-time value if Chromium lives in a different path on your base image.

Storage Volume Mount

The Laravel storage/ directory holds uploaded files, generated PDFs, compiled views, and session data. Mount it as a persistent named volume so data survives container restarts and upgrades:
-v patolab_storage:/app/storage
Without this mount, all uploaded files and cached assets are lost every time the container is replaced.

docker run Example

docker run -d \
  --name patolab \
  -p 8080:8080 \
  -e APP_KEY="base64:YOUR_GENERATED_KEY_HERE" \
  -e APP_URL="https://patolab.example.com" \
  -e APP_ENV="production" \
  -e APP_DEBUG="false" \
  -e DB_CONNECTION="mysql" \
  -e DB_HOST="your-db-host" \
  -e DB_PORT="3306" \
  -e DB_DATABASE="patolab" \
  -e DB_USERNAME="patolab_user" \
  -e DB_PASSWORD="strongpassword" \
  -e QUEUE_CONNECTION="database" \
  -e BROWSERSHOT_CHROME_PATH="/usr/bin/chromium" \
  -e PUPPETEER_EXECUTABLE_PATH="/usr/bin/chromium" \
  -v patolab_storage:/app/storage \
  patolab-platform:latest
After the container starts, run migrations against your production database:
docker exec patolab php artisan migrate --force

Collaboration Server

The real-time collaborative report editor runs as a separate Node.js WebSocket server (editor-collaboration-server/) on port 1234. This process is not included in the main container’s Supervisor configuration. You have two options:
Add the collaboration server as a third Supervisor program in the same container. This is simpler to operate but couples the two processes together.
The collaboration server communicates back to Laravel via the /api/collaboration webhook endpoint — make sure the two containers can reach each other over the network.

Chromium Warning

Chromium requires --no-sandbox inside Docker.Docker containers run without the Linux user-namespace isolation that Chromium normally relies on. If PDF generation fails with a “Chrome process exited too early” or sandbox-related error, add the following to your .env inside the container:
BROWSERSHOT_CHROME_ARGUMENTS='--no-sandbox --disable-setuid-sandbox --disable-dev-shm-usage'
The Dockerfile sets XDG_CONFIG_HOME=/tmp/.chromium and XDG_CACHE_HOME=/tmp/.chromium to give Chromium a writable profile directory without needing a home folder for the www-data user.

Local Development with Laravel Sail

For local Docker development, use Laravel Sail — a lightweight wrapper around docker-compose that comes pre-configured with the correct service definitions.
# Start all services (app, database, etc.)
./vendor/bin/sail up

# Run in the background
./vendor/bin/sail up -d

# Stop services
./vendor/bin/sail down
Sail is included as a dev dependency (laravel/sail) and provides a ready-made docker-compose.yml. It is much faster to iterate with than building and running the production Dockerfile directly.

Build docs developers (and LLMs) love