Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/alber1802/AvaluoVehicular/llms.txt

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

This guide covers deploying Avalúo Vehicular to a production server using Docker and Docker Compose. The application ships with a fully self-contained multi-stage Dockerfile that compiles React/Vite frontend assets, installs PHP production dependencies via Composer, and assembles a final PHP 8.4 FPM + Nginx + Supervisor image — no separate Node.js or Composer installation required on the host. All application state (SQLite database, uploaded files, and logs) is persisted via Docker volumes so container rebuilds and updates are non-destructive.
Always set APP_DEBUG=false in production. Enabling debug mode exposes stack traces, environment variables, and internal application details to any visitor. The .env.docker file ships with APP_DEBUG=false and APP_ENV=production — do not override these values in production.

Requirements

RequirementMinimum Version
Docker Engine20.x or later
Docker Composev2.x (compose plugin)
Available RAM512 MB
Disk space~1 GB (image + data)
No other runtime dependencies are needed on the host. PHP, Node.js, Composer, Nginx, and Supervisor are all bundled inside the container image.

Dockerfile Architecture (Multi-Stage Build)

The Dockerfile uses a four-stage multi-stage build to produce a lean, production-ready image. Each stage performs a single responsibility and only its artifacts are carried forward to the next stage.

Stage 1 — composer-builder

FROM composer:2.7 AS composer-builder

WORKDIR /app
COPY composer.json composer.lock ./

RUN composer install \
    --no-dev \
    --no-scripts \
    --no-interaction \
    --prefer-dist \
    --optimize-autoloader \
    --ignore-platform-reqs
Installs PHP production dependencies without dev packages (--no-dev). The --optimize-autoloader flag generates a classmap for faster class resolution in production. The --ignore-platform-reqs flag is required because the Composer image does not include all PHP extensions (those are installed in the final stage).

Stage 2 — wayfinder-generator

FROM php:8.4-cli-alpine AS wayfinder-generator

WORKDIR /app
RUN apk add --no-cache sqlite sqlite-dev \
    && docker-php-ext-install pdo pdo_sqlite

COPY --from=composer-builder /app/vendor ./vendor
COPY . .

RUN touch database/database.sqlite \
    && cp .env.docker .env \
    && php artisan key:generate --force \
    && php artisan wayfinder:generate --with-form || true
Generates Wayfinder TypeScript route helpers used by the React frontend (resources/js/routes/ and resources/js/actions/). These generated files must exist before Vite compiles the frontend.

Stage 3 — frontend-builder

FROM node:20-alpine AS frontend-builder

WORKDIR /app
COPY package*.json ./
COPY tsconfig.json ./
COPY vite.config.ts ./
COPY components.json ./
COPY eslint.config.js ./
COPY .prettierrc ./
COPY .prettierignore ./

RUN npm ci --prefer-offline --no-audit

COPY resources ./resources
COPY public ./public
COPY --from=wayfinder-generator /app/resources/js ./resources/js

RUN SKIP_WAYFINDER=true npm run build
Runs npm ci followed by Vite’s production build (npm run build). The SKIP_WAYFINDER=true env var prevents the Vite plugin from attempting to regenerate Wayfinder types (PHP is not available in this Node-only stage). The compiled output lands in public/build/.

Stage 4 — production (Final Image)

FROM php:8.4-fpm-alpine

RUN apk add --no-cache sqlite sqlite-dev libpng-dev libjpeg-turbo-dev \
    freetype-dev zip unzip git curl nginx supervisor \
    && docker-php-ext-install pdo pdo_sqlite gd bcmath opcache

# OPcache tuned for production
RUN { \
    echo 'opcache.enable=1'; \
    echo 'opcache.memory_consumption=256'; \
    echo 'opcache.interned_strings_buffer=16'; \
    echo 'opcache.max_accelerated_files=10000'; \
    echo 'opcache.revalidate_freq=2'; \
    echo 'opcache.validate_timestamps=0'; \
    } > /usr/local/etc/php/conf.d/opcache.ini

COPY --from=composer-builder /app/vendor ./vendor
COPY . .
COPY --from=frontend-builder /app/public/build ./public/build

EXPOSE 80
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
The final image is based on php:8.4-fpm-alpine and bundles:
  • PHP 8.4 FPM — processes PHP requests forwarded by Nginx
  • Nginx — serves static assets directly, proxies dynamic requests to PHP-FPM
  • Supervisor — keeps PHP-FPM, Nginx, and the Laravel queue worker running as supervised processes
  • OPcache — pre-compiles PHP files into shared memory for faster execution
  • SQLite + PDO — the database driver used in production
  • GD + BCMath — required for image processing and financial calculations

Docker Compose Configuration

The docker-compose.yml defines a single app service that maps host port 8080 to container port 80, mounts three persistent volumes, and loads environment variables from .env.docker.
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: avaluo-app
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      # Persist the SQLite database
      - ./database/database.sqlite:/var/www/html/database/database.sqlite
      # Persist application logs
      - ./storage/logs:/var/www/html/storage/logs
      # Persist user-uploaded files
      - ./storage/app:/var/www/html/storage/app
    env_file:
      - .env.docker
    environment:
      - APP_ENV=production
      - APP_DEBUG=false
    networks:
      - avaluo-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

networks:
  avaluo-network:
    driver: bridge
The default host port is 8080. To change it, update the left-hand side of "8080:80" in docker-compose.yml — for example, "443:80" for a reverse-proxy setup, or "80:80" if no other web server is running on the host.

Environment Variables

Production environment variables are defined in .env.docker. Copy this file and customize before the first build.
# Application
APP_NAME="Avaluo Vehicular"
APP_ENV=production
APP_KEY=base64:CHANGE_ME_RUN_php_artisan_key_generate
APP_DEBUG=false
APP_URL=http://127.0.0.1:8080

APP_LOCALE=es
APP_FALLBACK_LOCALE=es
APP_FAKER_LOCALE=es_ES

APP_MAINTENANCE_DRIVER=file

PHP_CLI_SERVER_WORKERS=4

BCRYPT_ROUNDS=12

# Logging
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=error

# Database (SQLite — absolute path inside container)
DB_CONNECTION=sqlite
DB_DATABASE=/var/www/html/database/database.sqlite

# Session (stored in SQLite via database driver)
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null

BROADCAST_CONNECTION=log

# Filesystem
FILESYSTEM_DISK=local

# Queue and cache (also SQLite-backed)
QUEUE_CONNECTION=database
CACHE_STORE=database

# Mail (configure as needed)
MAIL_MAILER=resend
MAIL_FROM_ADDRESS="notificaciones@your-domain.com"
MAIL_FROM_NAME="Sistema de Avalúo"

RESEND_API_KEY=your-resend-api-key-here

AUTO_MIGRATE=false

VITE_APP_NAME="${APP_NAME}"
VariableProduction ValueNotes
APP_ENVproductionDisables debug-only service providers
APP_DEBUGfalseNever true in production
APP_URLhttp://127.0.0.1:8080Used for asset URLs and email links; update to your domain in production
DB_CONNECTIONsqliteSQLite file path set in DB_DATABASE
SESSION_DRIVERdatabaseSession table must exist (run migrations)
QUEUE_CONNECTIONdatabaseQueue jobs stored in SQLite
CACHE_STOREdatabaseCache entries stored in SQLite
LOG_LEVELerrorOnly errors logged in production
AUTO_MIGRATEfalseMigrations run manually, not on startup

Persistent Volumes

The three bind-mount volumes ensure your data survives container rebuilds, image upgrades, and docker-compose down operations.
Host PathContainer PathContents
./database/database.sqlite/var/www/html/database/database.sqliteAll application data (SQLite database)
./storage/logs/var/www/html/storage/logslaravel.log and other log files
./storage/app/var/www/html/storage/appUploaded vehicle images and PDF reports
Before the first docker-compose up, create the SQLite file on the host so Docker mounts it as a file (not a directory):
touch database/database.sqlite

First-Time Setup

1

Clone the repository and configure environment

git clone https://github.com/alber1802/AvaluoVehicular.git
cd AvaluoVehicular

# Create the SQLite file before mounting
touch database/database.sqlite
mkdir -p storage/logs storage/app
2

Build the Docker image

The multi-stage build compiles frontend assets and installs all dependencies. This may take several minutes on the first run.
docker-compose build
3

Start the container in detached mode

docker-compose up -d
Verify the container started correctly:
docker-compose ps
docker-compose logs -f
4

Generate the application key

docker-compose exec app php artisan key:generate
This writes a base64:... value to APP_KEY in the running container. For a persistent key, update .env.docker with the generated value and rebuild.
5

Run database migrations

docker-compose exec app php artisan migrate --force
The --force flag bypasses the production confirmation prompt. This creates all tables including sessions, jobs, and cache_locks (required for SESSION_DRIVER=database and QUEUE_CONNECTION=database).
6

Verify the application

Open your browser to http://your-server-ip:8080. You should see the Avalúo Vehicular login page. The health check endpoint is also available:
curl http://localhost:8080/health

Update Procedure

1

Stop the running container

docker-compose down
Your data is safe — it lives in the bind-mounted volumes on the host, not inside the container.
2

Pull the latest code

git pull origin main
3

Rebuild the image

docker-compose build
Use --no-cache if you need a completely clean rebuild (e.g., after changing system-level dependencies):
docker-compose build --no-cache
4

Restart the container

docker-compose up -d
5

Run any new migrations

docker-compose exec app php artisan migrate --force
6

Clear compiled caches

docker-compose exec app php artisan optimize:clear

Supervisor Process Management

Supervisor runs inside the container and manages three processes: nginx, php-fpm, and the Laravel queue worker. The configuration is loaded from docker/supervisor/supervisord.conf. Check the status of all supervised processes:
docker-compose exec app supervisorctl status
Restart a specific process (e.g., the queue worker after a code change):
docker-compose exec app supervisorctl restart laravel-worker
Reload Supervisor configuration without stopping all processes:
docker-compose exec app supervisorctl reread
docker-compose exec app supervisorctl update

Health Check

Docker Compose monitors the container’s health using the built-in health check:
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost/health"]
  interval: 30s
  timeout: 10s
  retries: 3
  start_period: 40s
The /health endpoint returns an HTTP 200 when the application is running. The start_period: 40s gives the entrypoint script time to complete before health checks begin. You can query the health status manually with:
docker inspect --format='{{.State.Health.Status}}' avaluo-app

Production Optimizations

The Docker image includes the following production optimizations out of the box:
OptimizationHow It’s Configured
OPcacheEnabled with validate_timestamps=0 — PHP files are never re-checked on disk
OPcache memorymemory_consumption=256 (MB), interned_strings_buffer=16, max_accelerated_files=10000
Autoloader classmapcomposer dump-autoload --optimize --no-dev --classmap-authoritative
No dev dependenciescomposer install --no-dev removes ~60% of packages
Vite production buildAssets are minified, tree-shaken, and content-hashed
Nginx gzipConfigured in docker/nginx/default.conf
Static file cachingNginx serves public/build/ assets with a 1-year Cache-Control header
PHP upload limitsupload_max_filesize=20M, post_max_size=20M, memory_limit=256M
To apply Laravel’s own config, route, and view caches inside a running container:
docker-compose exec app php artisan config:cache
docker-compose exec app php artisan route:cache
docker-compose exec app php artisan view:cache

Build docs developers (and LLMs) love