Support Online
Skip to main content

Installing Laravel with Docker Compose on Ubuntu 22.04

💡 What You Will Learn in This Guide

In this guide, you will learn how to run your Laravel application in an isolated environment consisting of PHP-FPM, MySQL and Nginx services using Docker Compose. This structure provides a portable, fast and secure solution for both local development and pre-production testing processes.


🧠 Technical Summary

  • Subject: Creating a Laravel development environment on Ubuntu 22.04 with Docker Compose
  • Purpose: To run Laravel, PHP, Nginx and MySQL components on a container basis
  • Advantage: An isolated and portable development environment with no manual installation required

⚙️ Step 1: Downloading the Sample App

Let's start by downloading the sample Laravel application:

cd ~
curl -L https://github.com/do-community/travellist-laravel-demo/archive/tutorial-1.0.1.zip -o gezilistesi.zip
sudo apt update && sudo apt install unzip -y
unzip gezilistesi.zip
mv travellist-laravel-demo-tutorial-1.0.1 gezilistesi-demo
cd gezilistesi-demo

These operations extract the application files to the gezilistesi-demo folder.


⚙️ Step 2: Configuring the Laravel .env File

Let's make the environment variables suitable for Docker containers.

cp .env.example .env
nano .env

Make the following changes:

APP_NAME=Gezilistesi
APP_ENV=local
APP_URL=http://localhost:8000

DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=gezilistesi
DB_USERNAME=gezilistesi_user
DB_PASSWORD=sifre123

Setting it to DB_HOST=db will allow Laravel to connect to the MySQL service in Docker.


🐳 Step 3: Creating Dockerfile for app Service

The app service hosts PHP-FPM and Composer.

nano Dockerfile

Add content:

FROM php:7.4-fpm
ARG user
ARG uid
RUN apt-get update && apt-get install -y \
git curl libpng-dev libonig-dev libxml2-dev zip unzip \
&& docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
RUN useradd -G www-data,root -u $uid -d /home/$user $user && \
mkdir -p /home/$user/.composer && chown -R $user:$user /home/$user
WORKDIR /var/www
USER $user

This build installs PHP extensions, adds Composer, and sets user permissions for Artisan commands to work properly.


🌐 Step 4: Nginx and MySQL Configurations

Create configuration directory for Nginx:

mkdir -p docker-compose/nginx
nano docker-compose/nginx/gezilistesi.conf

Add the following content:

server {
listen 80;
index index.php index.html;
root /var/www/public;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
gzip_static on;
}
}

Create initial data for MySQL:

mkdir docker-compose/mysql
nano docker-compose/mysql/init_db.sql

Add content:

CREATE TABLE yerler (
id bigint unsigned AUTO_INCREMENT PRIMARY KEY,
isim varchar(255) NOT NULL,
ziyaret_edildi tinyint(1) DEFAULT 0
);
INSERT INTO yerler (isim, ziyaret_edildi)
VALUES ('İstanbul',0),('İzmir',1),('Ankara',0);

This table is automatically created with sample data when the application is opened.


🧩 Step 5: Creating the docker-compose.yml File

Let's define all services in the same network:

nano docker-compose.yml

Add content:

version: "3.7"
services:
app:
build:
context: ./
dockerfile: Dockerfile
args:
user: genixnode-dev
uid: 1000
image: gezilistesi-app
container_name: gezilistesi-app
restart: unless-stopped
working_dir: /var/www/
volumes:
- ./:/var/www
networks:
- gezilistesi-net

db:
image: mysql:8.0
container_name: gezilistesi-db
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_USER: ${DB_USERNAME}
volumes:
- ./docker-compose/mysql:/docker-entrypoint-initdb.d
networks:
- gezilistesi-net

nginx:
image: nginx:alpine
container_name: gezilistesi-nginx
restart: unless-stopped
ports:
- 8000:80
volumes:
- ./:/var/www
- ./docker-compose/nginx:/etc/nginx/conf.d/
networks:
- gezilistesi-net

networks:
gezilistesi-net:
driver: bridge

All three containers are connected to each other on a bridge network called gezilistesi-net.


🧨 Step 6: Launching the App

Create and start the Docker environment:

docker-compose build app
docker-compose up -d

Check the status:

docker-compose ps

Install dependencies:

docker-compose exec app composer install

Generate the application key:

docker-compose exec app php artisan key:generate

Now your Laravel application is ready to run!


🌍 Step 7: Testing the App

Open the following address in the browser:

http://localhost:8000

If the Laravel welcome page appears, the environment is configured successfully. 🎉


🧠 Step 8: Docker Compose Management

Pause services:

docker-compose pause

Resume:

docker-compose unpause

Stop completely:

docker-compose down

This command deletes containers, networks and volumes, but your project files are preserved.


❓ Frequently Asked Questions (FAQ)

1. Why do we use three containers?

Each service runs in its own environment, which provides advantages in terms of security, maintainability and scalability.

2. Why use bind mounts?

Local code changes are immediately reflected in the container; Ideal for live development.

3. What does the docker-compose exec command do?

It allows you to run commands without entering the container (for example composer install, php artisan migrate).

4. What does the -d parameter mean?

Runs services in the background; It does not occupy your terminal.

5. Will database data be deleted?

No, the data files in the docker-compose/mysql folder are preserved as volumes.


🏁 Result

With this guide, you have successfully containerized Laravel application using Docker Compose on Ubuntu 22.04. Now all components (PHP, MySQL, Nginx) run in an isolated and portable environment.

💡 To speed up your development processes and move the same structure to the cloud, you can create your own virtual server on the GenixNode platform and get your Laravel project up and running in minutes! 🌩️