Lewati ke konten utama
πŸš€ nusa.id cloud server linux indonesialihat paket

Cara Install LEMP Menggunakan Docker Compose di Rocky Linux 10

Β· 12 menit membaca

LEMP menggabungkan Nginx, MariaDB, dan PHP-FPM menjadi satu stack web. Dengan Docker Compose di Rocky Linux 10, ketiga service itu berjalan sebagai container dan dijalankan lewat satu perintah. Data MariaDB tetap tersimpan di host melalui bind mount, sementara health check menjaga urutan startup.

Requirements​

  • Rocky Linux 10.
  • Akses root atau sudo.
  • Minimal 2 vCPU, RAM 2 GB, dan disk 10 GB.

Environment​

  • OS: Rocky Linux 10 (x86_64)
  • Runtime: Docker Engine beserta plugin Compose dari repositori resmi Docker
  • Web server: image nginx:1.30.5-alpine
  • PHP: image php:8.4.26-fpm yang ditambah ekstensi pdo_mysql
  • Database: image mariadb:11.8.9
  • Direktori proyek: /root/docker-compose
  • Port HTTP: 8080

Langkah pada panduan ini dijalankan pada server Rocky Linux 10 dengan akses root. Environment seperti itu tersedia sebagai Nusa Cloud VPS.

Install LEMP di Rocky Linux 10 dengan Docker Compose​

1. Memasang Docker Engine​

Repositori Docker menyediakan paket untuk RHEL 10 dan turunannya, termasuk Rocky Linux. Tambahkan repositori tersebut beserta paket pembantu config-manager.

sudo dnf install -y dnf-plugins-core curl
sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo

Pasang Docker Engine dan plugin Compose. Proses ini mengimpor kunci GPG repositori Docker dengan fingerprint 060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35.

sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker

Output:

Installing:
containerd.io-2.3.5-1.el10 docker-buildx-plugin-0.37.1-1.el10
docker-ce-3:29.8.1-1.el10 docker-ce-cli-1:29.8.1-1.el10
docker-compose-plugin-5.5.1-1.el10
Importing GPG key 0x621E9F35:
Fingerprint: 060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35
Key imported successfully
Complete!
Created symlink '/etc/systemd/system/multi-user.target.wants/docker.service' β†’ '/usr/lib/systemd/system/docker.service'.

Jalankan image uji resmi untuk memastikan daemon aktif.

sudo docker run --rm hello-world

Output:

Hello from Docker!
This message shows that your installation appears to be working correctly.

2. Menyiapkan Direktori dan Variabel Environment​

Buat empat direktori: konfigurasi Nginx, build context PHP, aplikasi, dan data MariaDB.

sudo mkdir -p /root/docker-compose/config/nginx \
/root/docker-compose/config/php \
/root/docker-compose/data/app \
/root/docker-compose/data/database

Selanjutnya buat file /root/docker-compose/.env. Password diisi nilai acak dari /dev/urandom, jadi tidak ada kredensial yang ditulis di panduan ini. Mode file 600 membatasi akses hanya untuk root.

sudo install -m 600 /dev/null /root/docker-compose/.env
sudo tee /root/docker-compose/.env > /dev/null <<EOF
DB_HOST=db
MARIADB_DATABASE=lempdb
MARIADB_USER=lempuser
MARIADB_ROOT_PASSWORD=$(head -c 24 /dev/urandom | base64)
MARIADB_PASSWORD=$(head -c 24 /dev/urandom | base64)
HTTP_PORT=8080
EOF
sudo stat -c '%a %n' /root/docker-compose/.env

Output:

600 /root/docker-compose/.env

Untuk mengganti port HTTP, edit /root/docker-compose/.env dengan text editor pilihan Anda, misalnya nano atau vim, lalu ubah nilai HTTP_PORT.

3. Membuat Image PHP-FPM​

Image resmi php tidak memuat driver MySQL. Ekstensi pdo_mysql dipasang lewat Dockerfile kecil di bawah ini. Simpan sebagai /root/docker-compose/config/php/Dockerfile.

sudo tee /root/docker-compose/config/php/Dockerfile > /dev/null <<'EOF'
FROM php:8.4.26-fpm
RUN docker-php-ext-install pdo_mysql
EOF

4. Menyiapkan Konfigurasi Nginx​

Nginx melayani file dari /var/www/html dan meneruskan request .php ke service php pada port 9000. Simpan berkas ini sebagai /root/docker-compose/config/nginx/default.conf.

sudo tee /root/docker-compose/config/nginx/default.conf > /dev/null <<'EOF'
server {
listen 80;
server_name _;
root /var/www/html;
index index.php index.html;

location / {
try_files $uri $uri/ =404;
}

location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass php:9000;
}
}
EOF

5. Menambahkan Aplikasi Uji​

Buat file statis untuk health check Nginx, lalu skrip PHP yang membuka koneksi PDO ke MariaDB.

sudo tee /root/docker-compose/data/app/health.txt > /dev/null <<'EOF'
ok
EOF

Skrip berikut membaca kredensial dari environment container dan menampilkan pesan singkat saat koneksi berhasil. Simpan sebagai /root/docker-compose/data/app/index.php.

sudo tee /root/docker-compose/data/app/index.php > /dev/null <<'PHP'
<?php
declare(strict_types=1);

$dsn = sprintf(
'mysql:host=%s;dbname=%s;charset=utf8mb4',
(string) getenv('DB_HOST'),
(string) getenv('MARIADB_DATABASE')
);

header('Content-Type: text/plain; charset=utf-8');

try {
$pdo = new PDO($dsn, (string) getenv('MARIADB_USER'), (string) getenv('MARIADB_PASSWORD'));
$pdo->query('SELECT 1');
echo 'LEMP berfungsi: PHP ' . PHP_VERSION . ', koneksi MariaDB berhasil.' . PHP_EOL;
} catch (PDOException $e) {
http_response_code(500);
echo 'Koneksi database gagal: ' . $e->getMessage() . PHP_EOL;
}
PHP

6. Menulis Definisi Compose​

Tiga service didefinisikan dalam satu file. Akhiran z pada bind mount memberi label SELinux agar container dapat membaca dan menulis direktori host. Simpan sebagai /root/docker-compose/docker-compose.yml.

sudo tee /root/docker-compose/docker-compose.yml > /dev/null <<'EOF'
name: lemp

services:
web:
image: nginx:1.30.5-alpine
restart: unless-stopped
ports:
- "${HTTP_PORT}:80"
volumes:
- ./config/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro,z
- ./data/app:/var/www/html:ro,z
depends_on:
php:
condition: service_started
healthcheck:
test: ["CMD", "curl", "-fsS", "-o", "/dev/null", "http://127.0.0.1/health.txt"]
interval: 10s
timeout: 5s
retries: 5

php:
build:
context: ./config/php
restart: unless-stopped
env_file:
- .env
volumes:
- ./data/app:/var/www/html:z
depends_on:
db:
condition: service_healthy

db:
image: mariadb:11.8.9
restart: unless-stopped
env_file:
- .env
volumes:
- ./data/database:/var/lib/mysql:z
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
start_period: 20s
interval: 10s
timeout: 5s
retries: 5
EOF

7. Menjalankan Stack​

Validasi definisi Compose lebih dulu. Perintah config --quiet hanya memeriksa sintaks dan tidak menampilkan isi rahasia.

Semua perintah docker compose di bawah ini menunjuk berkas /root/docker-compose/docker-compose.yml secara eksplisit. Direktori proyek dan file .env karena itu tetap pada /root/docker-compose, terlepas dari direktori kerja shell.

sudo docker compose -f /root/docker-compose/docker-compose.yml config --quiet

Tidak adanya output berarti konfigurasi valid. Bangun image PHP lalu jalankan seluruh service. Flag --wait menahan perintah sampai setiap service berjalan dan health check-nya lulus.

sudo docker compose -f /root/docker-compose/docker-compose.yml up -d --build --wait

Output:

Container lemp-db-1 Started
Container lemp-db-1 Waiting
Container lemp-db-1 Healthy
Container lemp-php-1 Started
Container lemp-web-1 Started
Container lemp-php-1 Healthy
Container lemp-db-1 Healthy
Container lemp-web-1 Healthy

Verifikasi Instalasi LEMP di Rocky Linux 10​

Pastikan ketiga container berjalan dan lolos health check.

sudo docker compose -f /root/docker-compose/docker-compose.yml ps

Output:

NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
lemp-db-1 mariadb:11.8.9 "docker-entrypoint.s…" db 42 seconds ago Up 40 seconds (healthy) 3306/tcp
lemp-php-1 lemp-php "docker-php-entrypoi…" php 42 seconds ago Up 24 seconds 9000/tcp
lemp-web-1 nginx:1.30.5-alpine "/docker-entrypoint.…" web 41 seconds ago Up 24 seconds (healthy) 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp

Flag -T pada perintah exec menonaktifkan alokasi TTY agar perintah cocok dijalankan dari skrip.

Cek versi web server dan PHP yang benar-benar berjalan di dalam container.

sudo docker compose -f /root/docker-compose/docker-compose.yml exec -T web nginx -v
sudo docker compose -f /root/docker-compose/docker-compose.yml exec -T php php -r 'echo PHP_VERSION, PHP_EOL;'

Output:

nginx version: nginx/1.30.5
8.4.26

Pastikan ekstensi pdo_mysql termuat di PHP.

sudo docker compose -f /root/docker-compose/docker-compose.yml exec -T php php -m | grep -i pdo_mysql

Output:

pdo_mysql

Terakhir, pastikan MariaDB benar-benar siap menerima koneksi.

sudo docker compose -f /root/docker-compose/docker-compose.yml exec -T db healthcheck.sh --connect --innodb_initialized && echo "db siap"

Output:

db siap

Konfigurasi Dasar​

Variabel di .env​

VariabelNilai defaultFungsi
DB_HOSTdbNama service database yang dipakai skrip PHP. Compose menyediakan resolusi nama ini di jaringan internal.
MARIADB_DATABASElempdbNama database yang dibuat saat inisialisasi pertama.
MARIADB_USERlempuserUser aplikasi yang hanya punya akses ke MARIADB_DATABASE.
MARIADB_PASSWORDacakPassword user aplikasi, dipakai PHP dan MariaDB.
MARIADB_ROOT_PASSWORDacakPassword root MariaDB, hanya untuk administrasi.
HTTP_PORT8080Port di host yang dipetakan ke port 80 container Nginx.

Variabel host memakai nama DB_HOST, bukan MARIADB_HOST. Klien MariaDB di container db membaca MARIADB_HOST sebagai host default, sehingga healthcheck.sh akan menyambung ke IP bridge container dan ditolak.

Nilai acak dibuat sekali saat file .env dibuat. Mengubah password di .env setelah database terinisialisasi tidak mengubah password di dalam data MariaDB, karena password hanya dipakai pada inisialisasi pertama.

Direktif Nginx dan PHP-FPM​

  • root /var/www/html menunjuk ke direktori aplikasi yang di-bind mount dari data/app.
  • fastcgi_pass php:9000 mengarah ke service php, bukan ke alamat IP. Docker Compose menyediakan DNS internal berdasarkan nama service.
  • try_files $uri =404 mencegah request PHP ke berkas yang tidak ada diteruskan ke PHP-FPM.
  • docker-php-ext-install pdo_mysql pada Dockerfile menambahkan driver MySQL. Setiap perubahan Dockerfile perlu dibangun ulang dengan sudo docker compose -f /root/docker-compose/docker-compose.yml up -d --build php.

Pengujian Fungsional​

Uji pertama memastikan rantai Nginx, PHP-FPM, dan MariaDB bekerja lewat satu request HTTP.

curl -fsS --retry 10 --retry-delay 2 --retry-connrefused http://localhost:8080/

Output:

LEMP berfungsi: PHP 8.4.26, koneksi MariaDB berhasil.

Uji kedua memastikan data MariaDB bertahan setelah container database di-restart. Buat tabel dan satu baris data dari dalam container.

sudo docker compose -f /root/docker-compose/docker-compose.yml exec -T db sh -c 'mariadb -u"$MARIADB_USER" -p"$MARIADB_PASSWORD" "$MARIADB_DATABASE" -e "CREATE TABLE IF NOT EXISTS uji_persistensi (id INT PRIMARY KEY); INSERT IGNORE INTO uji_persistensi VALUES (1); SELECT * FROM uji_persistensi;"'

Output:

id
1

Klien mariadb dapat menampilkan peringatan penggunaan password pada command line. Peringatan itu tidak menggagalkan perintah.

Restart container database, tunggu sampai sehat kembali, lalu baca ulang tabel yang sama.

sudo docker compose -f /root/docker-compose/docker-compose.yml restart db
until [ "$(sudo docker inspect -f '{{.State.Health.Status}}' lemp-db-1)" = "healthy" ]; do sleep 2; done
sudo docker compose -f /root/docker-compose/docker-compose.yml ps db
sudo docker compose -f /root/docker-compose/docker-compose.yml exec -T db sh -c 'mariadb -u"$MARIADB_USER" -p"$MARIADB_PASSWORD" "$MARIADB_DATABASE" -e "SELECT * FROM uji_persistensi;"'

Output:

Container lemp-db-1 Restarting
Container lemp-db-1 Started
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
lemp-db-1 mariadb:11.8.9 "docker-entrypoint.s…" db About a minute ago Up 15 seconds (healthy) 3306/tcp
id
1

Baris 1 tetap muncul setelah restart karena data tersimpan di /root/docker-compose/data/database pada host.

Troubleshooting​

Nginx mengembalikan 502 Bad Gateway​

Gejala: curl mengembalikan halaman 502 Bad Gateway.

Penyebab: Container php berhenti atau fastcgi_pass tidak menunjuk ke port yang benar.

Perbaikan: Periksa log PHP-FPM dan status container.

sudo docker compose -f /root/docker-compose/docker-compose.yml logs php
sudo docker compose -f /root/docker-compose/docker-compose.yml ps

Output:

php-1 | NOTICE: fpm is running, pid 1
php-1 | NOTICE: ready to handle connections
php-1 | 172.18.0.4 - 25/Sep/2026:03:43:22 +0000 "GET /index.php" 200

PHP error "could not find driver"​

Gejala: Request HTTP menampilkan Koneksi database gagal: could not find driver.

Penyebab: Ekstensi pdo_mysql tidak ada di image, biasanya karena image dibangun sebelum Dockerfile diperbarui.

Perbaikan: Bangun ulang image PHP tanpa cache lalu nyalakan kembali.

sudo docker compose -f /root/docker-compose/docker-compose.yml build --no-cache php
sudo docker compose -f /root/docker-compose/docker-compose.yml up -d

Container db tidak menjadi healthy​

Gejala: docker compose ps menampilkan status starting atau unhealthy untuk service db.

Penyebab: Inisialisasi data MariaDB pertama memakan waktu lebih lama, atau direktori data tidak dapat ditulis.

Perbaikan: Lihat log database dan beri waktu sampai health check selesai.

sudo docker compose -f /root/docker-compose/docker-compose.yml logs db

Output:

db-1 | mariadbd: ready for connections.

Port 8080 sudah dipakai​

Gejala: docker compose up gagal dengan pesan address already in use.

Penyebab: Ada proses lain yang menempati HTTP_PORT.

Perbaikan: Cari proses pemakai port, atau ubah HTTP_PORT di .env lalu jalankan ulang stack.

sudo ss -ltnp | grep ':8080'

SELinux menolak akses bind mount​

Gejala: Nginx gagal membaca /etc/nginx/conf.d/default.conf, atau MariaDB gagal menulis ke /var/lib/mysql.

Penyebab: Direktori host belum memiliki label SELinux yang sesuai untuk container.

Perbaikan: Pastikan setiap bind mount pada docker-compose.yml memakai akhiran z atau ro,z, lalu jalankan ulang.

Info

Pada sistem dengan SELinux nonaktif, akhiran z tidak berpengaruh dan tidak menimbulkan error.

Verifikasi​

Stack LEMP dinyatakan siap ketika seluruh kondisi berikut terpenuhi.

  • docker compose ps menampilkan lemp-web-1 dan lemp-db-1 berstatus healthy.
  • curl http://localhost:8080/ mengembalikan pesan LEMP berfungsi.
  • Ekstensi pdo_mysql muncul saat php -m dijalankan di container php.
  • Baris uji pada tabel uji_persistensi tetap ada setelah container db di-restart.

Untuk melihat log terpusat saat ada masalah, gunakan perintah berikut.

sudo docker compose -f /root/docker-compose/docker-compose.yml logs --tail=50

Output:

mariadbd: ready for connections.
Version: '11.8.9-MariaDB-ubu2404' ... port: 3306

Untuk menghentikan stack tanpa menghapus data, jalankan perintah berikut.

sudo docker compose -f /root/docker-compose/docker-compose.yml down

Output:

Container lemp-db-1 Removed
Network lemp_default Removed
Berbahaya

Perintah sudo rm -rf /root/docker-compose menghapus seluruh konfigurasi, aplikasi, dan data MariaDB secara permanen. Pastikan Anda sudah punya cadangan sebelum menjalankannya, dan jalankan down lebih dulu.

sudo docker compose -f /root/docker-compose/docker-compose.yml down --rmi local
sudo rm -rf /root/docker-compose

Output:

Image lemp-php:latest Removed
Dangling images Removed