Modern Laravel 10 Deployment with Docker (2024β2025 Best Practices)
- Best Practice
π A modern, production-friendly approach to running Laravel 10 with Docker on Ubuntu 22.04 / 24.04 β cleaner, safer, and easier to maintain.
π¦ Stack Overview
Section titled βπ¦ Stack Overviewβ- Laravel 10
- PHP-FPM 8.1+
- MySQL 8.0
- phpMyAdmin (optional, non-production)
- Nginx (Reverse Proxy)
- Docker Compose v2
π§ Key Improvements vs Legacy Setup
Section titled βπ§ Key Improvements vs Legacy Setupβ- No static container IPs
- No exposed database ports (internal network only)
- Environment variables via
.env - Named volumes for persistence
- Docker Compose v2 (
docker compose) - phpMyAdmin marked as optional / non-prod
π³ Step 1 β Install Docker Engine (Official Method)
Section titled βπ³ Step 1 β Install Docker Engine (Official Method)βsudo apt update -ysudo apt install -y ca-certificates curl gnupgsudo install -m 0755 -d /etc/apt/keyringscurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpgecho \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \ https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update -ysudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginVerify:
docker versiondocker compose versionπ Step 2 β Project Structure
Section titled βπ Step 2 β Project StructureβDirectorylaravel-docker/
Directoryapp/ # Laravel source code
- β¦
Directorydocker/
Directorynginx/
- default.conf
Directoryphp/
- Dockerfile
- php.ini
- docker-compose.yml
- .env
π Step 3 β Environment Configuration (.env)
Section titled βπ Step 3 β Environment Configuration (.env)βAPP_NAME=LaravelAPP_ENV=localAPP_KEY=APP_DEBUG=trueAPP_URL=http://localhost
DB_CONNECTION=mysqlDB_HOST=dbDB_PORT=3306DB_DATABASE=laravelDB_USERNAME=laravelDB_PASSWORD=secretπ οΈ Step 4 β Dockerfile PHP-FPM
Section titled βπ οΈ Step 4 β Dockerfile PHP-FPMβdocker/php/Dockerfile:
FROM php:8.1-fpm
RUN apt-get update && apt-get install -y \ git curl zip unzip libpng-dev libonig-dev libxml2-dev \ && docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/htmlπ§© Step 5 β docker-compose.yml (Clean & Modern)
Section titled βπ§© Step 5 β docker-compose.yml (Clean & Modern)βservices: app: build: context: . dockerfile: docker/php/Dockerfile container_name: laravel-app volumes: - ./app:/var/www/html env_file: - .env depends_on: - db
web: image: nginx:alpine container_name: nginx ports: - "80:80" volumes: - ./app:/var/www/html - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - app
db: image: mysql:8.0 container_name: mysql restart: always environment: MYSQL_DATABASE: laravel MYSQL_USER: laravel MYSQL_PASSWORD: secret MYSQL_ROOT_PASSWORD: root volumes: - dbdata:/var/lib/mysql
phpmyadmin: image: phpmyadmin container_name: phpmyadmin ports: - "8081:80" environment: PMA_HOST: db profiles: - debug
volumes: dbdata:π Step 6 β Nginx Configuration
Section titled βπ Step 6 β Nginx Configurationβdocker/nginx/default.conf:
server { listen 80; index index.php index.html; root /var/www/html/public;
location / { try_files $uri $uri/ /index.php?$query_string; }
location ~ \.php$ { fastcgi_pass app:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; }}π Step 7 β Run the Stack
Section titled βπ Step 7 β Run the Stackβdocker compose up -d --buildGenerate Laravel key:
docker compose exec app php artisan key:generateAccess the app:
- Laravel: http://localhost
- phpMyAdmin (debug): http://localhost:8081
π§ Production Notes
Section titled βπ§ Production Notesβ- Use
.env.production - Disable phpMyAdmin
- Add HTTPS (Traefik / Nginx + Certbot)
- Use non-root containers if needed
- Consider queue & scheduler containers
β Final Thoughts
Section titled ββ Final ThoughtsβThis setup is intentionally boring β and thatβs a good thing.
Simple Compose files, predictable networking, and fewer moving parts mean fewer 3 AM incidents.
If youβre migrating from an older Laravel Docker setup, this structure is a solid baseline going forward.