Deploy Laravel 10 Menggunakan Docker Compose di Ubuntu 24.04

Deploy Laravel 10 Menggunakan Docker Compose di Ubuntu 24.04

Deploy Laravel 10 Menggunakan Docker Compose di Ubuntu 24.04

Menjalankan aplikasi Laravel secara langsung di komputer host membutuhkan beberapa dependency seperti PHP, Composer, extension PHP, web server, dan database.

Masalahnya, setiap komputer bisa memiliki versi dan konfigurasi yang berbeda. Akibatnya, aplikasi yang berjalan di satu komputer belum tentu langsung berjalan di komputer lain.

Docker Compose membantu membuat environment aplikasi secara lebih konsisten. Pada artikel ini, kita akan menjalankan Laravel 10 menggunakan:

  • Ubuntu 24.04
  • Docker Engine
  • Docker Compose
  • PHP 8.2
  • Apache
  • MySQL 8.0

Laravel 10 membutuhkan PHP minimal versi 8.1 serta beberapa extension seperti Ctype, cURL, DOM, Fileinfo, Mbstring, OpenSSL, PDO, Tokenizer, dan XML.[1]

Arsitektur Deployment

Pada praktik ini kita akan membuat dua service:

Browser
   |
   | localhost:8000
   v
Laravel App Container
   |
   | Docker Compose Network
   v
MySQL Database Container

Struktur service-nya:

app
└── Laravel 10
    ├── PHP 8.2
    └── Apache

db
└── MySQL 8.0

Service Laravel menggunakan Apache sebagai web server. Pendekatan ini lebih sederhana untuk pembelajaran dibandingkan memisahkan Nginx dan PHP-FPM ke dalam dua container berbeda.

Catatan: Konfigurasi pada artikel ini ditujukan untuk development dan lab. Deployment production membutuhkan konfigurasi tambahan seperti HTTPS, secret management, logging, backup, dan hardening.

Prasyarat

Pastikan Ubuntu 24.04 sudah tersedia. Docker Engine secara resmi mendukung Ubuntu 24.04 LTS dengan codename Noble.[2]

Pastikan Docker Engine, Docker Compose, dan Git sudah terpasang:

docker --version
docker compose version
git --version

Docker Compose modern menggunakan command:

docker compose

Bukan:

docker-compose

Docker mendokumentasikan instalasi Compose Plugin pada Linux melalui package docker-compose-plugin dan verifikasinya menggunakan docker compose version.[3]

Jika Docker belum terpasang, ikuti dokumentasi resmi:

Install Docker Engine on Ubuntu

Menyiapkan Project Laravel

Artikel ini mengasumsikan Anda sudah memiliki project Laravel 10. Project tersebut dapat berasal dari repository Git.

Contoh:

git clone YOUR_REPOSITORY_URL laravel-docker
cd laravel-docker

Jika ingin membuat project Laravel 10 baru menggunakan Composer:

composer create-project "laravel/laravel:^10.0" laravel-docker
cd laravel-docker

Laravel mendokumentasikan penggunaan Composer untuk membuat project Laravel dengan batasan versi ^10.0.[4]

Pastikan isi project Laravel terlihat seperti berikut:

laravel-docker/
├── app/
├── bootstrap/
├── config/
├── database/
├── public/
├── resources/
├── routes/
├── storage/
├── .env.example
├── artisan
├── composer.json
└── composer.lock

Membuat Dockerfile

Buat file bernama Dockerfile di root project:

FROM php:8.2-apache

ENV APACHE_DOCUMENT_ROOT=/var/www/html/public

RUN apt-get update \
    && apt-get install -y \
        git \
        unzip \
        libzip-dev \
        libonig-dev \
    && docker-php-ext-install \
        pdo_mysql \
        mbstring \
        bcmath \
        exif \
        pcntl \
        zip \
    && a2enmod rewrite \
    && rm -rf /var/lib/apt/lists/*

COPY --from=composer:2 /usr/bin/composer /usr/bin/composer

RUN sed -ri \
    -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' \
    /etc/apache2/sites-available/000-default.conf \
    /etc/apache2/apache2.conf

WORKDIR /var/www/html

COPY . .

RUN composer install \
        --no-interaction \
        --prefer-dist \
        --optimize-autoloader \
    && chown -R www-data:www-data \
        storage \
        bootstrap/cache

EXPOSE 80

Penjelasan Dockerfile

FROM php:8.2-apache

Menggunakan image PHP 8.2 dengan Apache. PHP 8.2 dipilih karena masih memenuhi requirement minimal Laravel 10, yaitu PHP 8.1 atau lebih baru.[1]

RUN apt-get install

Memasang package Linux yang diperlukan saat proses build image.

docker-php-ext-install

Image PHP Official menyediakan helper script seperti docker-php-ext-configure, docker-php-ext-install, dan docker-php-ext-enable untuk memasang extension PHP.[5]

Extension yang dipasang pada contoh ini antara lain:

  • pdo_mysql untuk koneksi Laravel ke MySQL
  • mbstring untuk pemrosesan string multibyte
  • bcmath untuk operasi matematika
  • exif untuk metadata gambar
  • pcntl untuk kebutuhan proses tertentu
  • zip untuk dependency Composer
ENV APACHE_DOCUMENT_ROOT=/var/www/html/public

Laravel harus dilayani dari folder public, bukan dari root project. Hal ini mencegah file internal seperti .env ikut terekspos oleh web server.[1]

COPY --from=composer:2 /usr/bin/composer /usr/bin/composer

Menyalin executable Composer dari image Composer ke image aplikasi.

composer install

Memasang dependency Laravel berdasarkan composer.json dan composer.lock.

Untuk deployment production, Laravel merekomendasikan optimasi autoloader dan menghilangkan dependency development menggunakan:

composer install --optimize-autoloader --no-dev

[1]

Pada artikel ini kita menggunakan konfigurasi development/lab agar proses belajar tetap sederhana.

Membuat .dockerignore

Agar file yang tidak diperlukan tidak ikut masuk ke build context, buat file .dockerignore:

.git
.env
vendor
node_modules
storage/logs/*

File .env sengaja tidak dimasukkan ke image karena berisi konfigurasi environment dan dapat berisi credential. Laravel juga menyarankan agar .env tidak disimpan di source control.[4][6]

Membuat File .env

Salin file environment example:

cp .env.example .env

Kemudian edit file .env:

nano .env

Sesuaikan bagian database menjadi:

APP_NAME=Laravel
APP_ENV=local
APP_KEY=***
APP_URL=http://localhost:8000

DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=***

Tambahkan variable password root MySQL untuk kebutuhan Docker Compose:

DB_ROOT_PASSWORD=YOUR_ROOT_PASSWORD

Gunakan password berbeda saat menjalankan aplikasi sebenarnya. Nilai pada contoh ini hanya placeholder.

Mengapa DB_HOST menggunakan db?

Pada file Compose nanti, nama service database adalah:

db:

Docker Compose menyediakan network internal dan resolusi nama berdasarkan nama service. Karena itu Laravel dapat mengakses database melalui hostname:

DB_HOST=db

Jangan menggunakan:

DB_HOST=localhost

Di dalam container Laravel, localhost menunjuk ke container Laravel itu sendiri, bukan ke container MySQL.

Membuat File Compose

Buat file compose.yaml:

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: laravel_app
    ports:
      - "8000:80"
    env_file:
      - .env
    volumes:
      - ./.env:/var/www/html/.env
    depends_on:
      db:
        condition: service_healthy

  db:
    image: mysql:8.0
    container_name: laravel_db
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${DB_DATABASE:-laravel}
      MYSQL_USER: ${DB_USERNAME:-laravel}
      MYSQL_PASSWORD: ${DB_PASSWORD:-YOUR_DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-YOUR_ROOT_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    healthcheck:
      test:
        [
          "CMD",
          "mysqladmin",
          "ping",
          "-h",
          "localhost",
          "-u",
          "root",
          "-p${DB_ROOT_PASSWORD:-YOUR_ROOT_PASSWORD}"
        ]
      interval: 10s
      timeout: 5s
      retries: 10

volumes:
  db_data:

Compose Specification menyediakan format untuk mendefinisikan service, environment, volume, dependency, dan konfigurasi aplikasi multi-container.[7]

Penjelasan file Compose

Service app

app:
  build:
    context: .
    dockerfile: Dockerfile

Compose akan membuat image menggunakan Dockerfile pada directory project saat ini.

ports:
  - "8000:80"

Mapping tersebut berarti:

Port host 8000 → Port container 80

Aplikasi dapat diakses melalui:

http://localhost:8000

Jika port 8000 sudah digunakan, Anda dapat menggantinya:

ports:
  - "8080:80"

Aplikasi kemudian diakses melalui:

http://localhost:8080

Mount file .env

volumes:
  - ./.env:/var/www/html/.env

Mount ini membuat file .env pada host digunakan oleh Laravel di dalam container. Dengan begitu, ketika php artisan key:generate dijalankan, perubahan APP_KEY tersimpan pada file .env di project host.

Service db

image: mysql:8.0

Menggunakan MySQL 8.0 dari Docker Official Image. Image MySQL mendukung konfigurasi database dan credential melalui environment variable.[8]

volumes:
  - db_data:/var/lib/mysql

Named volume digunakan agar data database tetap tersimpan ketika container dihentikan atau dibuat ulang.

Healthcheck

Database tidak selalu langsung siap menerima koneksi ketika container baru saja dijalankan. Karena itu service db diberi healthcheck.

Service app menunggu database berada pada status healthy:

depends_on:
  db:
    condition: service_healthy

depends_on membantu mengatur dependency service, tetapi aplikasi tetap perlu menangani kemungkinan database belum siap pada kondisi tertentu.

Validasi Konfigurasi Compose

Sebelum build, validasi konfigurasi Compose:

docker compose config

Jika tidak ada error, periksa kembali service yang terbaca:

docker compose config --services

Output yang diharapkan:

app
db

Build Image dan Menjalankan Container

Build image aplikasi:

docker compose build

Kemudian jalankan service di background:

docker compose up -d

Option -d menjalankan container secara detached atau background.[9]

Periksa status container:

docker compose ps

Contoh status yang diharapkan:

NAME          SERVICE   STATUS
laravel_app   app       running
laravel_db    db        healthy

Nama dan format output dapat berbeda tergantung versi Docker Compose.

Membuat APP_KEY

Setelah container aplikasi aktif, jalankan:

docker compose exec app php artisan key:generate

Command tersebut menjalankan Artisan di dalam service app.

Periksa file .env:

grep APP_KEY .env

Seharusnya sekarang APP_KEY sudah memiliki nilai.

Jangan membagikan isi APP_KEY atau melakukan commit file .env ke repository publik.

Menjalankan Database Migration

Jalankan migration Laravel:

docker compose exec app php artisan migrate

Jika database belum siap, tunggu beberapa saat lalu ulangi command tersebut:

docker compose exec app php artisan migrate

Periksa konfigurasi database Laravel:

docker compose exec app php artisan about

Laravel menyediakan command Artisan untuk membantu melihat informasi aplikasi dan environment.

Mengakses Aplikasi

Buka browser dan akses:

http://localhost:8000

Jika berhasil, halaman default Laravel akan tampil.

Anda juga dapat memeriksa response HTTP menggunakan curl:

curl -I http://localhost:8000

Contoh response yang diharapkan:

HTTP/1.1 200 OK

Melihat Log Container

Untuk melihat log aplikasi:

docker compose logs -f app

Untuk melihat log database:

docker compose logs -f db

Option -f membuat log terus mengikuti output terbaru.

Tekan Ctrl+C untuk berhenti melihat log. Container tetap berjalan karena yang dihentikan hanya proses monitoring log pada terminal.

Masuk ke Dalam Container

Untuk membuka shell pada container aplikasi:

docker compose exec app bash

Setelah masuk, Anda dapat memeriksa versi PHP:

php -v

Memeriksa extension:

php -m

Memeriksa versi Laravel:

php artisan --version

Keluar dari container:

exit

docker compose exec memang digunakan untuk menjalankan command pada service Compose yang sedang aktif.[5]

Perintah Operasional Dasar

Menghentikan container

docker compose stop

Perintah ini menghentikan container tanpa menghapusnya.

Menjalankan kembali container

docker compose start

Restart service

docker compose restart

Menghentikan dan menghapus container

docker compose down

Perintah ini menghapus container dan network yang dibuat Compose.[10]

Named volume database biasanya tetap ada jika tidak menggunakan option -v.

Menghapus container sekaligus volume

docker compose down -v

Warning: Jangan menggunakan docker compose down -v jika masih membutuhkan data MySQL. Named volume database akan ikut dihapus.

Troubleshooting

1. Port 8000 sudah digunakan

Periksa proses yang menggunakan port:

sudo ss -tulpn | grep :8000

Atau ubah mapping pada compose.yaml:

ports:
  - "8080:80"

Kemudian jalankan ulang:

docker compose up -d

2. Laravel gagal terhubung ke database

Pastikan konfigurasi .env seperti berikut:

DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=***

Jangan gunakan localhost sebagai DB_HOST.

Periksa status database:

docker compose ps

Lihat log database:

docker compose logs db

3. APP_KEY belum tersedia

Jalankan:

docker compose exec app php artisan key:generate

Jika Laravel masih membaca konfigurasi lama:

docker compose exec app php artisan config:clear

Laravel menjelaskan bahwa configuration cache dapat menyebabkan perubahan .env tidak langsung terbaca. config:cache sebaiknya digunakan sebagai bagian dari deployment production, bukan saat konfigurasi development sering berubah.[6]

4. Container aplikasi berhenti

Periksa log:

docker compose logs app

Periksa status semua service:

docker compose ps -a

Jika terdapat perubahan pada Dockerfile, rebuild image:

docker compose build --no-cache
docker compose up -d

5. Error permission pada Laravel

Pastikan folder berikut dapat ditulis oleh web server:

storage/
bootstrap/cache/

Pada Dockerfile, permission awal sudah disiapkan menggunakan:

RUN chown -R www-data:www-data storage bootstrap/cache

Jika permission berubah setelah proses development, periksa owner folder dari dalam container:

docker compose exec app ls -ld storage bootstrap/cache

6. Migration gagal karena database belum siap

Periksa status health database:

docker compose ps

Jika status database belum healthy, lihat log:

docker compose logs -f db

Tunggu sampai MySQL selesai melakukan initialization, lalu jalankan ulang:

docker compose exec app php artisan migrate

Security Considerations

Konfigurasi pada artikel ini digunakan untuk lab. Untuk production, perhatikan hal-hal berikut:

  1. Jangan commit file .env.
  2. Jangan menggunakan password contoh.
  3. Jangan menggunakan APP_DEBUG=true di production.
  4. Jangan expose port MySQL ke internet tanpa alasan yang jelas.
  5. Gunakan secret management yang sesuai.
  6. Gunakan backup database.
  7. Gunakan HTTPS.
  8. Gunakan password database yang kuat.
  9. Jangan membagikan APP_KEY.
  10. Pisahkan konfigurasi development dan production.

Laravel menggunakan .env untuk konfigurasi yang dapat berbeda antar-environment. File tersebut sebaiknya tidak dimasukkan ke source control.[6]

Kesimpulan

Pada artikel ini kita sudah menjalankan Laravel 10 menggunakan Docker Compose dengan dua service:

app → Laravel 10 + PHP 8.2 + Apache
db  → MySQL 8.0

Alur utamanya adalah:

cp .env.example .env
docker compose config
docker compose build
docker compose up -d
docker compose exec app php artisan key:generate
docker compose exec app php artisan migrate

Aplikasi kemudian dapat diakses melalui:

http://localhost:8000

Dengan Docker Compose, dependency Laravel dan database dijalankan dalam container yang terpisah tetapi tetap dapat berkomunikasi melalui network internal Compose.

Langkah lanjutan yang dapat dipelajari:

  • Menggunakan Nginx dan PHP-FPM
  • Menambahkan Redis
  • Menjalankan Laravel queue worker
  • Menambahkan HTTPS
  • Membuat pipeline GitHub Actions
  • Deploy ke VPS
  • Menambahkan backup database otomatis

Sources

[1] Laravel 10 Deployment Documentation

[2] Docker Engine — Install on Ubuntu

[3] Install the Docker Compose Plugin on Linux

[4] Laravel 10 Installation Documentation

[5] Official PHP Docker Image

[6] Laravel 10 Configuration Documentation

[7] Docker Compose File Reference

[8] Official MySQL Docker Image

[9] docker compose up Reference

[10] docker compose down Reference