12- Configuración de Nginx y MySQL para Laravel con Docker

 

 Configuración de Nginx y MySQL para Laravel con Docker

Introducción

En este tutorial configuraremos los servicios de Nginx (servidor web) y MySQL (base de datos) para nuestro proyecto Laravel, completando así el entorno de desarrollo completo con Docker.


Paso 1: Detener Contenedores Existentes

Antes de modificar la configuración, debemos detener los contenedores activos:

bash
# Verificar contenedores en ejecución
docker ps

# Detener todos los servicios (Docker Compose V2)
docker compose down

# Verificar que no queden contenedores
docker ps

Paso 2: Crear Estructura de Directorios para Configuraciones

2.1 Crear carpetas para Nginx

bash
# Crear directorios para configuraciones
mkdir -p docker/nginx

# Verificar estructura
ls -la docker/

Estructura resultante:

text
laravel/
├── docker/
│   └── nginx/
├── Dockerfile
├── docker-compose.yml
└── (archivos de Laravel)

Paso 3: Configurar Nginx

3.1 Crear archivo de configuración de Nginx

bash
nano docker/nginx/app.conf

3.2 Configuración actualizada de Nginx para Laravel

nginx
server {
    listen 80;
    server_name localhost;
    root /var/www/html/public;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";

    index index.php index.html;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    # Configuración de Laravel 11+ con Vite
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    location ~ \.php$ {
        fastcgi_pass app:9000;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

3.3 Puntos clave a verificar

ConfiguraciónValorExplicación
root/var/www/html/publicDirectorio público de Laravel
fastcgi_passapp:9000Puerto de PHP-FPM (debe coincidir)
listen80Puerto interno del contenedor

Nota: La configuración de Nginx mostrada es un boilerplate oficial de Laravel. Puedes encontrarla en la documentación oficial de Laravel.


Paso 4: Actualizar docker-compose.yml

4.1 Agregar servicio de Nginx

Abrir el archivo:

bash
nano docker-compose.yml

Agregar servicio Nginx:

yaml
  nginx:
    image: nginx:alpine
    container_name: laravel_nginx
    restart: unless-stopped
    ports:
      - "8000:80"
    volumes:
      - ./:/var/www/html
      - ./docker/nginx:/etc/nginx/conf.d
    networks:
      - laravel
    depends_on:
      - app

4.2 Agregar servicio de MySQL

yaml
  db:
    image: mysql:8.0
    container_name: laravel_db
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${DB_DATABASE:-laravel}
      MYSQL_USER: ${DB_USERNAME:-laravel}
      MYSQL_PASSWORD: ${DB_PASSWORD:-secret}
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-rootsecret}
    ports:
      - "3306:3306"
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - laravel

4.3 Agregar volúmenes persistentes

yaml
volumes:
  db_data:

4.4 Configuración completa de networks

yaml
networks:
  laravel:
    driver: bridge

Paso 5: Configurar Variables de Entorno (.env)

5.1 Modificar el archivo .env de Laravel

bash
nano .env

Configuración actualizada para 2024-2026:

env
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost:8000

LOG_CHANNEL=stack
LOG_LEVEL=debug

# Configuración de base de datos
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=secret

# Configuración de MySQL (variables para el contenedor)
MYSQL_DATABASE=laravel
MYSQL_USER=laravel
MYSQL_PASSWORD=secret
MYSQL_ROOT_PASSWORD=rootsecret

# Redis (opcional)
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379

# Configuración de sesión
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_DOMAIN=localhost

# Configuración de cache
CACHE_DRIVER=file
QUEUE_CONNECTION=sync

# Configuración de mail (para desarrollo)
MAIL_MAILER=smtp
MAIL_HOST=mailpit
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"

Paso 6: Dockerfile Actualizado (Opcional)

6.1 Instalar extensión PDO MySQL

Si aún no está instalada, agregar al Dockerfile:

dockerfile
RUN docker-php-ext-install pdo_mysql

Paso 7: Comandos para Levantar el Entorno

7.1 Levantar todos los servicios

bash
# Levantar en segundo plano
docker compose up -d

# Verificar contenedores activos
docker compose ps

# Ver logs en tiempo real
docker compose logs -f

7.2 Salida esperada

text
CONTAINER ID   IMAGE           COMMAND                  CREATED         STATUS         PORTS                    NAMES
abc123def456   nginx:alpine    "/docker-entrypoint.…"   2 minutes ago   Up 2 minutes   0.0.0.0:8000->80/tcp     laravel_nginx
def456ghi789   mysql:8.0       "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes   0.0.0.0:3306->3306/tcp   laravel_db
ghi789jkl012   laravel-app     "docker-php-entrypoi…"   2 minutes ago   Up 2 minutes   9000/tcp                 laravel_app

Paso 8: Configuración Adicional (Recomendaciones 2024-2026)

✅ Servicio de Base de Datos (MySQL 8.0 vs 5.7)

MySQL 8.0 introduce cambios importantes:

yaml
# Para MySQL 8.0, agregar en el servicio db:
command: --default-authentication-plugin=mysql_native_password

Versión recomendada: MySQL 8.0 o MariaDB 10.11+

✅ Alternativa: MariaDB (más ligero)

yaml
  db:
    image: mariadb:10.11
    container_name: laravel_db
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_USER: ${DB_USERNAME}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - laravel

✅ Healthcheck para servicios

yaml
  db:
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${DB_ROOT_PASSWORD}"]
      timeout: 20s
      retries: 10
      interval: 10s

✅ Service de Mailpit (para pruebas de email)

yaml
  mailpit:
    image: axllent/mailpit
    container_name: laravel_mailpit
    restart: unless-stopped
    ports:
      - "8025:8025"
      - "1025:1025"
    networks:
      - laravel

Paso 9: Verificación Final

9.1 Acceder a la aplicación

Abrir en navegador: http://localhost:8000

9.2 Verificar conexión a base de datos

bash
# Ejecutar migraciones
docker compose exec app php artisan migrate

# Verificar conexión
docker compose exec app php artisan db:show

9.3 Verificar logs

bash
# Logs de Nginx
docker compose logs nginx

# Logs de MySQL
docker compose logs db

# Logs de la app
docker compose logs app

Errores Comunes y Soluciones

ErrorCausaSolución
Connection refusedDB_HOST incorrectoUsar db no localhost
Access deniedCredenciales incorrectasVerificar variables en .env
No such file or directoryRuta de Nginx mal configuradaVerificar root en app.conf
Port already allocatedPuerto 8000 ocupadoCambiar a 8001:80
SQLSTATE[HY000] [2002]MySQL no listoEsperar o usar depends_on con healthcheck
FastCGI sent in stderrPHP-FPM no disponibleVerificar fastcgi_pass apunta al servicio app

Resumen del Flujo de Trabajo


Archivos Finales

Estructura completa del proyecto:

text
laravel/
├── Dockerfile
├── docker-compose.yml
├── .env
├── docker/
│   └── nginx/
│       └── app.conf
├── app/
├── bootstrap/
├── config/
├── database/
├── public/
├── resources/
├── routes/
├── storage/
├── tests/
├── vendor/
├── composer.json
├── composer.lock
└── .gitignore

¡Listo! Ahora tienes un entorno completo de desarrollo para Laravel con Nginx como servidor web y MySQL como base de datos, todo orquestado con Docker Compose V

Comentarios

Entradas más populares de este blog

12. Hola Mundo en Docker.

11¿Qué es Docker? y ¿Por qué debo saberlo?

14. Publish and Detached modes