Docker Compose for Laravel + PostgreSQL + Elasticsearch
Laravel is the most popular PHP framework for web development, known for its elegant syntax and rich ecosystem. It is the framework of choice for SaaS products, REST APIs, and rapid application development with Eloquent ORM and first-class queue support.
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?
Laravel 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.
docker compose up -d
http://localhost:8080
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
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
WEB_PORT=8080 POSTGRES_PORT=5432 POSTGRES_DB=app POSTGRES_USER=app POSTGRES_PASSWORD=secret ELASTICSEARCH_PORT=9200