Victor: generate a docker compose yaml file containing nginx reverse-proxy, php-fpm symfony app, and mercure hub. create an example nginx.conf


Raycast AI: Of course. Here is a complete setup for a Symfony application using Docker Compose with Nginx, PHP-FPM, and a Mercure hub.

This setup assumes you have a directory structure like this:

.
├── app/                  <-- Your Symfony project code goes here
├── docker/
│   ├── nginx/
│   │   └── nginx.conf    <-- Nginx configuration
│   └── php/
│       └── Dockerfile    <-- Custom PHP-FPM Dockerfile
└── docker-compose.yml    <-- The main Docker Compose file

1. The docker-compose.yml File

This file orchestrates the building and linking of your services.

docker-compose.yml

version: '3.8'

services:
  #--------------------------------------------------------------------------
  # PHP-FPM Service (Your Symfony App)
  #--------------------------------------------------------------------------
  app:
    build:
      context: ./docker/php
      dockerfile: Dockerfile
    container_name: symfony_app
    restart: unless-stopped
    volumes:
      - ./app:/var/www/html
    networks:
      - app-network
    environment:
      # Symfony environment variables
      APP_ENV: dev
      APP_SECRET: ${APP_SECRET:-!ChangeMe!} # Change this in a .env file
      DATABASE_URL: "postgresql://user:password@db:5432/app?serverVersion=16&charset=utf8"

      # Mercure configuration for Symfony Notifier/Web-Push
      # This URL is for server-to-server communication (app -> mercure)
      MERCURE_URL: <http://mercure/.well-known/mercure>
      # This URL is for the client-side browser to connect to Mercure
      MERCURE_PUBLIC_URL: <http://localhost/.well-known/mercure>
      # This secret MUST match MERCURE_JWT_KEY in the mercure service
      MERCURE_JWT_SECRET: ${MERCURE_JWT_KEY:-!ChangeThisSuperSecretKey!}

  #--------------------------------------------------------------------------
  # Nginx Service (Reverse Proxy)
  #--------------------------------------------------------------------------
  nginx:
    image: nginx:1.27-alpine
    container_name: symfony_nginx
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443" # Optional: For HTTPS
    volumes:
      - ./app:/var/www/html:ro # Mount app code as read-only
      - ./docker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - app
      - mercure
    networks:
      - app-network

  #--------------------------------------------------------------------------
  # Mercure Hub Service
  #--------------------------------------------------------------------------
  mercure:
    image: dunglas/mercure:v0.14
    container_name: symfony_mercure
    restart: unless-stopped
    environment:
      # The secret key to sign and verify JWTs.
      # MUST match MERCURE_JWT_SECRET in the app service.
      MERCURE_JWT_KEY: ${MERCURE_JWT_KEY:-!ChangeThisSuperSecretKey!}
      MERCURE_ADDR: ':80' # Listen on port 80 inside the container
      SERVER_NAME: ':80'
      MERCURE_ALLOW_ANONYMOUS: '1' # Allow anonymous subscribers for development
      MERCURE_CORS_ALLOWED_ORIGINS: '*' # Allow all origins for development
      MERCURE_PUBLISH_ALLOWED_ORIGINS: '<http://nginx>, http://symfony_nginx' # Allow Nginx to publish updates
    networks:
      - app-network

#--------------------------------------------------------------------------
# Networks
#--------------------------------------------------------------------------
networks:
  app-network:
    driver: bridge

2. Custom PHP Dockerfile

This Dockerfile for PHP installs necessary extensions for a typical Symfony application.

docker/php/Dockerfile

# Use an official PHP-FPM image as a base
FROM php:8.3-fpm-alpine

# Set working directory
WORKDIR /var/www/html

# Install system dependencies needed for PHP extensions
RUN apk add --no-cache \\\\
    $PHPIZE_DEPS \\\\
    icu-dev \\\\
    libzip-dev \\\\
    postgresql-dev # Use 'mysql-dev' for MySQL/MariaDB

# Install PHP extensions required by Symfony
RUN docker-php-ext-install \\\\
    intl \\\\
    pdo pdo_pgsql \\\\ # Use 'pdo_mysql' for MySQL/MariaDB
    zip \\\\
    opcache

# Install Composer globally
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Clear cache
RUN apk del .phpize-deps && rm -rf /var/cache/apk/*

# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]

3. Nginx Configuration

This configuration file acts as a reverse proxy. It serves static files directly and forwards PHP requests to the app (PHP-FPM) service and Mercure requests to the mercure service.

docker/nginx/nginx.conf

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

    # Log files
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    # Set a higher client body size
    client_max_body_size 25M;

    # Main location block for the Symfony application
    location / {
        # Try to serve the file directly, otherwise fall back to index.php
        try_files $uri /index.php$is_args$args;
    }

    # Location block for PHP files
    # This is the entry point for all dynamic requests
    location ~ ^/index\\\\.php(/|$) {
        # Forward requests to the PHP-FPM service
        # 'app' is the service name from docker-compose.yml
        fastcgi_pass app:9000;
        fastcgi_split_path_info ^(.+\\\\.php)(/.*)$;
        include fastcgi_params;

        # When you are using symlinks to link the document root to the
        # real one, you must ensure that essences like SCRIPT_FILENAME
        # and DOCUMENT_ROOT are set correctly.
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;

        # Prevents Nginx from sending the "Content-Type" header to the client
        # when the FastCGI server returns a "Status" header.
        fastcgi_intercept_errors off;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
    }

    # Location block for the Mercure Hub
    # All requests to /.well-known/mercure will be proxied to the Mercure service
    location /.well-known/mercure {
        # 'mercure' is the service name from docker-compose.yml
        proxy_pass <http://mercure>;

        # These headers are required for Server-Sent Events (SSE) to work
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Connection '';
        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_read_timeout 10m; # A long timeout is important for long-lived connections
    }

    # Deny access to .php files in the /bundles directory
    location ~ /bundles/.*\\\\.php$ {
        deny all;
    }

    # Block access to dotfiles (.git, .htaccess)
    location ~ /\\\\. {
        deny all;
    }
}

How to Use This Setup

  1. Create the Directories: Create the docker/nginx and docker/php directories.
  2. Place the Files: Save each code block above into its corresponding file (docker-compose.yml, docker/php/Dockerfile, and docker/nginx/nginx.conf).