Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Nieto2020/portalhub/llms.txt

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

PortalHub ships with a complete Docker Compose configuration that provisions an isolated, reproducible environment with three coordinated services. This page explains each service, the volume strategy, the required environment variables, and what the PHP-FPM image installs — along with the production hardening considerations you must address before exposing the portal externally.

Docker Compose Services

The docker-compose.yml at the project root defines three services connected on a shared bridge network named portal-network.
services:

  nginx:
    image: nginx:latest
    container_name: portal-nginx
    ports:
      - "80:80"
    volumes:
      - ./frontend:/var/www/frontend
      - ./backend:/var/www/backend
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php
    networks:
      - portal-network

  php:
    build:
      context: .
      dockerfile: docker/php/Dockerfile
    container_name: portal-php
    volumes:
      - ./frontend:/var/www/frontend
      - ./backend:/var/www/backend
    networks:
      - portal-network

  mysql:
    image: mysql:8.4
    container_name: portal-mysql
    restart: unless-stopped
    env_file:
      - .env
    ports:
      - "3306:3306"
    volumes:
      - mysql-data:/var/lib/mysql
      - ./database:/docker-entrypoint-initdb.d
    networks:
      - portal-network

volumes:
  mysql-data:

networks:
  portal-network:

Service Breakdown

ServiceImage / BuildExposed PortRole
nginxnginx:latest80:80Reverse proxy — serves static frontend assets and forwards PHP requests to portal-php via FastCGI.
phpBuilt from docker/php/Dockerfile (PHP 8.3-FPM)Internal onlyExecutes all backend PHP scripts and API endpoints.
mysqlmysql:8.43306:3306Relational data store — bootstrapped automatically from database/ on first run.

Volume Mounts

Both nginx and php mount the same two host directories, ensuring that Nginx can resolve static files and PHP can access backend code from identical absolute paths inside the containers:
Host PathContainer PathPurpose
./frontend/var/www/frontendHTML, CSS, and JavaScript assets served by Nginx.
./backend/var/www/backendPHP API modules, config, middleware, and uploaded files.
./nginx/default.conf/etc/nginx/conf.d/default.confNginx virtual host configuration (FastCGI pass to portal-php).
MySQL uses a named volume (mysql-data) for durable data persistence and mounts ./database into /docker-entrypoint-initdb.d, which causes MySQL to automatically execute schema.sql (and seed.sql if present) on container initialisation.

Environment Variables

The mysql service reads credentials from a .env file in the project root via env_file. The same variables are consumed by backend/config/config.php at runtime through getenv(). Create a .env file at the project root before running docker-compose up:
MYSQL_HOST=mysql
MYSQL_DATABASE=consultoria
MYSQL_USER=consultancy
MYSQL_PASSWORD=consultancy123
VariableDefaultDescription
MYSQL_HOSTmysqlHostname of the MySQL container as resolved inside portal-network.
MYSQL_DATABASEconsultoriaName of the database schema to create and connect to.
MYSQL_USERconsultancyApplication database user (non-root).
MYSQL_PASSWORDconsultancy123Password for MYSQL_USER. Change this in any non-development environment.

PHP-FPM Dockerfile

The custom PHP image is built from docker/php/Dockerfile using php:8.3-fpm as its base:
FROM php:8.3-fpm

# System dependencies
RUN apt-get update && apt-get install -y \
    zip \
    unzip \
    git \
    libzip-dev \
    libpng-dev \
    libjpeg62-turbo-dev \
    libfreetype6-dev \
    libonig-dev \
    && docker-php-ext-install pdo pdo_mysql mysqli zip

# Working directory
WORKDIR /var/www

# Timezone
ENV TZ=America/Mexico_City

CMD ["php-fpm"]
The image installs four PHP extensions required by the application:
ExtensionPurpose
pdoPHP Data Objects core — required by the PDO connection in conexion.php.
pdo_mysqlMySQL driver for PDO — enables new PDO("mysql:host=...").
mysqliMySQLi procedural/OOP interface — available for any legacy or utility scripts.
zipZIP archive support — used for bundled document download features.
The ENV TZ=America/Mexico_City directive aligns the container clock with the timezone set in backend/config/config.php, ensuring consistent timestamp values across PHP and MySQL.

Network

All three services join the portal-network bridge network defined at the bottom of docker-compose.yml. Container-to-container communication uses service names as hostnames — portal-php reaches the database at mysql:3306 and Nginx proxies PHP requests to php:9000 — without any host-level exposure of internal ports.

Production Considerations

The default .env credentials (consultancy / consultancy123) are public knowledge. Before deploying to any internet-accessible server you must replace all four environment variable values with strong, randomly generated secrets. Never commit a production .env file to version control.Additionally, you should:
  • Terminate TLS at Nginx or an upstream load balancer and redirect all HTTP traffic to HTTPS. The config.php session hardening (Secure cookie flag, HttpOnly, SameSite=Lax) only takes full effect over HTTPS.
  • Restrict backend/uploads/ so that files are never served directly from a public URL. Uploaded documents may contain sensitive fiscal data; access should be gated through an authenticated PHP endpoint that validates the requester’s role and file ownership before streaming the response.
  • Limit the MYSQL_USER account to only the privileges required by the application (SELECT, INSERT, UPDATE, DELETE on the consultoria schema). Do not use the MySQL root account as the application database user.
The backend/uploads/ directory includes a .htaccess file that blocks direct HTTP access to uploaded files when the application is served by Apache. If you are using the Docker Compose Nginx setup, confirm that the equivalent deny all location block is present in your nginx/default.conf to ensure the same protection applies to the Nginx-served environment.

Build docs developers (and LLMs) love