← Customise this setup

Docker Compose for Symfony + PostgreSQL + Elasticsearch

Stack
PHP-FPM + Nginx + PostgreSQL + Elasticsearch

Symfony is a mature PHP framework built for performance and reliability. Its component architecture powers many major projects including Drupal and Shopware, making it a common choice for APIs, e-commerce platforms, and complex business applications.

PostgreSQL 15 is a powerful, ACID-compliant relational database with strong support for JSON, full-text search, and complex queries. Both Symfony (Doctrine) and Laravel (Eloquent) support PostgreSQL natively and it is increasingly preferred for new projects.

Elasticsearch provides distributed full-text search and real-time analytics. It requires at least 1 GB of dedicated memory — ensure your Docker host has sufficient RAM before starting the stack.

When should you use this stack?

Symfony with PostgreSQL and Elasticsearch is a solid default for local development when your production environment matches it. If you're evaluating alternatives, the related configurations below swap one piece at a time — same framework with a different database, or the same data layer under a different framework — so you can compare without starting from scratch.

Quick start
Start stack docker compose up -d
Web http://localhost:8080

compose.yml

compose.yml
services:
  nginx:
    image: nginx:latest
    ports:
      - "${WEB_PORT-8080}:80"
    volumes:
      - .:/var/www/html
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - php

  php:
    image: php:8.5-fpm
    volumes:
      - .:/var/www/html

  postgres:
    image: postgres:15
    environment:
      POSTGRES_DB: ${POSTGRES_DB-app}
      POSTGRES_USER: ${POSTGRES_USER-app}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD-secret}
    ports:
      - "${POSTGRES_PORT-5432}:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready"]
      interval: 10s
      timeout: 5s
      retries: 5

  elasticsearch:
    image: elasticsearch:8.11.0
    environment:
      discovery.type: single-node
      xpack.security.enabled: "false"
      ES_JAVA_OPTS: "-Xms512m -Xmx512m"
    ports:
      - "${ELASTICSEARCH_PORT-9200}:9200"
    volumes:
      - elasticsearch_data:/usr/share/elasticsearch/data
    healthcheck:
      test: ["CMD-SHELL", "curl -s http://localhost:9200/_cluster/health | grep -q status"]
      interval: 30s
      timeout: 10s
      retries: 5

volumes:
  postgres_data:
  elasticsearch_data:

docker/nginx/default.conf

Run mkdir -p docker/nginx first

docker/nginx/default.conf
server {
    listen 80;
    server_name localhost;

    root /var/www/html/public;
    index index.php index.html;

    location / {
        try_files $uri /index.php$is_args$args;
    }

    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

.env.example

Optional — Compose uses ${VAR-default} fallbacks

.env.example
WEB_PORT=8080

POSTGRES_PORT=5432
POSTGRES_DB=app
POSTGRES_USER=app
POSTGRES_PASSWORD=secret

ELASTICSEARCH_PORT=9200

Frequently asked questions

How do I start this Symfony stack?
Download the files, run `docker compose up -d` from the project root, then open http://localhost:8080 in your browser. The web port is configurable via the `WEB_PORT` variable in `.env`.
Which PHP version does this configuration use?
This page uses PHP 8.5 by default. Use the generator above to pick 8.1 through 8.5 and regenerate the files with your chosen version.
How do I connect to PostgreSQL from my host machine?
From your host, connect with `psql -h 127.0.0.1 -p 5432 -U app app` (password `secret` by default). From other containers on the same network, use host `postgres` and port 5432.
What port does Elasticsearch run on?
Elasticsearch listens on port 9200 for HTTP requests. Check cluster health with `curl http://localhost:9200/_cluster/health`.
Is this configuration production-ready?
No — it is tuned for local development (bind-mounted source, default credentials, exposed ports). For production, remove the bind mounts, set real secrets, and add resource limits and restart policies.

Related configurations