❤️ AZDIGI chính thức cập nhật hệ thống blog mới hoàn chỉnh. Tuy nhiên có thể một số bài viết bị sai lệch hình ảnh, hãy ấn nút Báo cáo bài viết ở cuối bài để AZDIGI cập nhật trong thời gian nhanh nhất. Chân thành cám ơn.

Bài 7, bạn đã deploy thành công WordPress + MySQL + phpMyAdmin bằng Docker Compose, một stack hoàn chỉnh với database, web app, và công cụ quản lý. Bạn đã thấy cách các container giao tiếp qua Docker network, cách dùng volumes để giữ dữ liệu, và cách environment variables giúp cấu hình mọi thứ mà không cần sửa file config bên trong container.

LEMP Stack Docker
Minh họa: LEMP Stack với Docker

Nhưng WordPress stack dùng image có sẵn, mọi thứ đã được đóng gói. Trong thực tế, bạn sẽ thường cần build một stack tuỳ chỉnh hơn: chọn phiên bản PHP, cài thêm extension, viết config Nginx riêng, deploy code PHP của chính mình. Đó là lúc bạn cần LEMP Stack.

Trong bài này, mình sẽ hướng dẫn bạn dựng một LEMP Stack hoàn chỉnh bằng Docker Compose: Nginx + PHP-FPM + MariaDB: với custom Dockerfile, custom config, sẵn sàng để deploy bất kỳ project PHP nào.

LEMP Stack là gì?

LEMP là viết tắt của 4 thành phần:

  • Linux: hệ điều hành (trong Docker, đó là Alpine Linux bên trong container)
  • Engine-X (Nginx): web server, reverse proxy
  • MariaDB (hoặc MySQL): hệ quản trị cơ sở dữ liệu
  • PHP: ngôn ngữ lập trình server-side

Đây là stack phổ biến nhất để chạy các ứng dụng PHP: từ Laravel, CodeIgniter, đến các CMS như WordPress, Joomla, Drupal. Nếu bạn làm web với PHP, gần như chắc chắn bạn sẽ cần LEMP (hoặc LAMP).

LAMP vs LEMP – Khác nhau chỗ nào?

Bạn có thể đã nghe đến LAMP (Linux + Apache + MySQL + PHP). Sự khác biệt chính nằm ở web server:

┌────────────┬──────────────────────┬──────────────────────┐
│            │       LAMP           │       LEMP           │
├────────────┼──────────────────────┼──────────────────────┤
│ Web Server │ Apache               │ Nginx                │
│ PHP xử lý │ mod_php (module)     │ PHP-FPM (FastCGI)    │
│ Cấu hình   │ .htaccess + httpd   │ nginx.conf           │
│ Hiệu năng  │ Tốt, dùng nhiều RAM │ Nhẹ hơn, nhanh hơn  │
│ Static file│ Chậm hơn            │ Rất nhanh            │
│ Phổ biến   │ Hosting truyền thống│ VPS, cloud, Docker   │
└────────────┴──────────────────────┴──────────────────────┘

Tại sao chọn LEMP? Nginx nhẹ hơn Apache đáng kể, xử lý static files cực nhanh, và kiến trúc event-driven giúp nó handle được nhiều concurrent connections hơn với ít tài nguyên hơn. Trong môi trường Docker và VPS, Nginx gần như là lựa chọn mặc định.

Sơ đồ hoạt động của LEMP Stack trong Docker:

┌──────────────────────────────────────────────────────┐
│                   Docker Network                      │
│                   (lemp-network)                      │
│                                                       │
│   Browser Request                                     │
│        ↓                                              │
│   ┌──────────┐    FastCGI     ┌──────────┐           │
│   │  Nginx   │───────────────→│ PHP-FPM  │           │
│   │  :80     │  (.php files)  │  :9000   │           │
│   │          │                │          │           │
│   │ (static  │                │  ↓ SQL   │           │
│   │  files)  │                │          │           │
│   └──────────┘                └──────────┘           │
│        ↑                           ↓                  │
│   Shared Volume              ┌──────────┐            │
│   (./src:/var/www/html)      │ MariaDB  │            │
│        ↑                     │  :3306   │            │
│        └─────────────────────┘          │            │
│          PHP & Nginx cùng               │            │
│          mount source code              │            │
│                              └──────────┘            │
└──────────────────────────────────────────────────────┘

Điểm quan trọng: Nginx và PHP-FPM là 2 container riêng biệt. Nginx nhận request, nếu là file .php thì chuyển sang PHP-FPM qua giao thức FastCGI (port 9000). Cả hai cùng mount chung thư mục source code để Nginx serve static files và PHP-FPM xử lý code PHP.

Tạo cấu trúc project

Tạo thư mục project và các file cần thiết:

mkdir -p ~/lemp-docker/{nginx,php,src}
cd ~/lemp-docker

Cấu trúc project khi hoàn thành sẽ như sau:

lemp-docker/
├── docker-compose.yml      # File chính, định nghĩa 3 services
├── .env                    # Biến môi trường (secrets)
├── nginx/
│   └── default.conf        # Config Nginx cho PHP-FPM
├── php/
│   ├── Dockerfile          # Custom PHP image + extensions
│   └── php.ini             # Tuỳ chỉnh PHP settings
└── src/
    └── index.php           # Source code PHP của bạn

Mỗi thư mục có vai trò riêng:

  • nginx/: chứa config Nginx, mount vào container Nginx
  • php/: chứa Dockerfile và php.ini để build custom PHP image
  • src/: chứa source code PHP, được mount vào cả Nginx và PHP-FPM

Viết file .env cho secrets

Trước khi viết docker-compose.yml, hãy tạo file .env để chứa các thông tin nhạy cảm. Tách secrets ra file riêng giúp bạn dễ quản lý và tránh commit password lên Git.

nano .env

Nội dung file .env:

# MariaDB
MYSQL_ROOT_PASSWORD=rootpass_secret_2024
MYSQL_DATABASE=lemp_db
MYSQL_USER=lemp_user
MYSQL_PASSWORD=lemp_pass_secret_2024
# Nginx
NGINX_PORT=8080

Lưu ý: Trong production, hãy đổi password thành giá trị mạnh hơn. Và luôn thêm .env vào .gitignore để không push secrets lên repository.

echo ".env" >> .gitignore

Custom PHP Dockerfile

Image php:8.3-fpm-alpine trên Docker Hub rất nhẹ nhưng thiếu nhiều extensions cần thiết. Bạn cần tự build image với các extensions phù hợp cho dự án.

nano php/Dockerfile
FROM php:8.3-fpm-alpine

# Cài các package hệ thống cần thiết cho PHP extensions RUN apk add --no-cache \ freetype-dev \ libjpeg-turbo-dev \ libpng-dev \ libzip-dev \ icu-dev \ oniguruma-dev

# Cấu hình và cài PHP extensions RUN docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-install -j$(nproc) \ pdo_mysql \ mysqli \ gd \ zip \ intl \ mbstring \ opcache

# Copy file php.ini tuỳ chỉnh COPY php.ini /usr/local/etc/php/conf.d/custom.ini

# Set working directory WORKDIR /var/www/html

# Expose port 9000 (PHP-FPM default) EXPOSE 9000

Giải thích từng phần:

  • FROM php:8.3-fpm-alpine: base image PHP 8.3 với FPM (FastCGI Process Manager), dựa trên Alpine Linux (siêu nhẹ, chỉ ~50MB)
  • apk add: cài các thư viện C cần thiết để compile PHP extensions (freetype cho font trong GD, libjpeg/libpng cho xử lý ảnh, libzip cho ZIP, icu cho internationalization)
  • docker-php-ext-configure gd: cấu hình extension GD với hỗ trợ FreeType và JPEG trước khi cài
  • docker-php-ext-install: script có sẵn trong PHP Docker image, giúp cài extensions dễ dàng. Flag -j$(nproc) dùng tất cả CPU cores để compile nhanh hơn
  • COPY php.ini: copy file cấu hình PHP tuỳ chỉnh vào container

Các extensions đã cài:

┌──────────────┬──────────────────────────────────────────┐
│  Extension   │  Dùng để làm gì                          │
├──────────────┼──────────────────────────────────────────┤
│ pdo_mysql    │ Kết nối MySQL/MariaDB qua PDO (chuẩn)   │
│ mysqli       │ Kết nối MySQL/MariaDB (legacy, WP cần)  │
│ gd           │ Xử lý ảnh (resize, crop, watermark)     │
│ zip          │ Đọc/tạo file ZIP                         │
│ intl         │ Internationalization (đa ngôn ngữ)       │
│ mbstring     │ Xử lý chuỗi multibyte (UTF-8)           │
│ opcache      │ Cache PHP bytecode, tăng tốc đáng kể    │
└──────────────┴──────────────────────────────────────────┘

Custom php.ini

Tạo file php.ini để tuỳ chỉnh các settings PHP mặc định:

nano php/php.ini
; === Upload & POST ===
upload_max_filesize = 64M
post_max_size = 64M

; === Memory === memory_limit = 256M

; === Execution === max_execution_time = 300 max_input_time = 300 max_input_vars = 3000

; === Error Handling === display_errors = Off log_errors = On error_log = /var/log/php/error.log

; === OPcache === opcache.enable = 1 opcache.memory_consumption = 128 opcache.max_accelerated_files = 10000 opcache.revalidate_freq = 60

; === Timezone === date.timezone = Asia/Ho_Chi_Minh

Một số settings quan trọng:

  • upload_max_filesize & post_max_size: mặc định PHP chỉ cho upload 2MB, tăng lên 64MB cho thoải mái
  • memory_limit: RAM tối đa cho mỗi PHP process, 256M đủ cho hầu hết ứng dụng
  • opcache: cache bytecode giúp PHP không cần compile lại code mỗi request, tăng tốc 2-3 lần
  • display_errors = Off: tắt hiển thị lỗi trên web (bảo mật), chỉ ghi vào log

Custom Nginx config

Nginx cần được cấu hình để chuyển request .php sang PHP-FPM. Tạo file config:

nano nginx/default.conf
server {
    listen 80;
    server_name localhost;

root /var/www/html; index index.php index.html index.htm;

# Logging access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log;

# Xử lý request chính location / { try_files $uri $uri/ /index.php?$query_string; }

# Chuyển file .php sang PHP-FPM location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$;

# "php" là tên service trong docker-compose.yml fastcgi_pass php:9000; fastcgi_index index.php;

include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info;

# Timeout cho các script chạy lâu fastcgi_read_timeout 300; }

# Cache static files location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ { expires 30d; add_header Cache-Control "public, immutable"; access_log off; }

# Chặn truy cập file ẩn (.env, .git, .htaccess) location ~ /\. { deny all; access_log off; log_not_found off; } }

Giải thích các phần quan trọng:

try_files – Xử lý URL

try_files $uri $uri/ /index.php?$query_string;

Dòng này nói với Nginx: “Thử tìm file theo URL → nếu không có, thử thư mục → nếu vẫn không có, chuyển tất cả về index.php“. Đây là cách hoạt động của hầu hết PHP framework (Laravel, WordPress, CodeIgniter), mọi request đều đi qua một file entry point duy nhất.

fastcgi_pass – Kết nối PHP-FPM

fastcgi_pass php:9000;

Đây là dòng quan trọng nhất, nó chuyển request PHP sang container PHP-FPM. php ở đây chính là tên service trong docker-compose.yml, Docker network tự động resolve tên này thành IP của container. Port 9000 là port mặc định của PHP-FPM.

Static file caching

location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
    access_log off;
}

Block này cấu hình cache cho static files (ảnh, CSS, JS, fonts). Browser sẽ cache các file này trong 30 ngày, giảm request đến server đáng kể. access_log off tắt log cho static files để giảm I/O.

Chặn file ẩn

location ~ /\. {
    deny all;
}

Block bảo mật, chặn truy cập vào tất cả file bắt đầu bằng dấu chấm: .env, .git, .htaccess. Nếu không có dòng này, ai cũng có thể đọc file .env chứa password database của bạn qua trình duyệt.

Viết docker-compose.yml

Bây giờ đến phần chính, file docker-compose.yml kết nối tất cả lại với nhau:

nano docker-compose.yml
services:
  # === Nginx Web Server ===
  nginx:
    image: nginx:alpine
    container_name: lemp-nginx
    ports:
      - "${NGINX_PORT:-8080}:80"
    volumes:
      - ./src:/var/www/html                    # Source code
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf  # Nginx config
    depends_on:
      - php
    restart: unless-stopped
    networks:
      - lemp-network

# === PHP-FPM === php: build: context: ./php dockerfile: Dockerfile container_name: lemp-php volumes: - ./src:/var/www/html # Cùng source code với Nginx depends_on: - mariadb restart: unless-stopped networks: - lemp-network

# === MariaDB Database === mariadb: image: mariadb:11 container_name: lemp-mariadb environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: ${MYSQL_DATABASE} MYSQL_USER: ${MYSQL_USER} MYSQL_PASSWORD: ${MYSQL_PASSWORD} volumes: - mariadb_data:/var/lib/mysql # Persistent data restart: unless-stopped networks: - lemp-network

# === Volumes === volumes: mariadb_data:

# === Network === networks: lemp-network: driver: bridge

Phân tích từng service:

Service nginx

  • image: nginx:alpine: dùng image Nginx nhẹ nhất (~40MB)
  • ports: map port 8080 trên host vào port 80 trong container. Giá trị lấy từ file .env, mặc định 8080 nếu không set
  • volumes: mount 2 thứ: source code (shared với PHP) và config Nginx
  • depends_on: php: đảm bảo PHP-FPM khởi động trước Nginx

Service php

  • build: build image từ Dockerfile trong thư mục php/, không dùng image có sẵn
  • volumes: mount cùng thư mục src/ với Nginx. Đây là điểm mấu chốt: Nginx serve static files, PHP-FPM xử lý file .php, cả hai cùng đọc từ một thư mục
  • depends_on: mariadb: đảm bảo database sẵn sàng trước khi PHP chạy
  • Không expose port: PHP-FPM chỉ giao tiếp nội bộ qua port 9000 trong Docker network, không cần expose ra ngoài

Service mariadb

  • image: mariadb:11: MariaDB phiên bản 11, tương thích hoàn toàn với MySQL
  • environment: tất cả giá trị lấy từ file .env qua cú pháp ${VARIABLE}
  • volumes: mariadb_data: named volume, giữ dữ liệu database khi container restart hoặc recreate
  • Không expose port: tương tự PHP, database chỉ truy cập nội bộ. Nếu cần kết nối từ host (dùng MySQL Workbench chẳng hạn), thêm ports: - "3306:3306"

Deploy và test

Mọi thứ đã sẵn sàng. Bắt đầu deploy!

Bước 1: Tạo file test

Tạo file index.php đơn giản trong thư mục src/:

cat > src/index.php << 'EOF'
<!DOCTYPE html>
<html>
<head>
    <title>LEMP Stack Docker</title>
    <style>
        body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; }
        .success { color: #27ae60; }
        .error { color: #e74c3c; }
        code { background: #f4f4f4; padding: 2px 8px; border-radius: 4px; }
    </style>
</head>
<body>
    <h1>🚀 LEMP Stack đang chạy!</h1>
    <p>PHP Version: <strong><?php echo PHP_VERSION; ?></strong></p>
    <p>Server: <strong><?php echo $_SERVER['SERVER_SOFTWARE'] ?? 'Nginx + PHP-FPM'; ?></strong></p>

<h2>Test kết nối MariaDB</h2> <?php $host = 'mariadb'; // Tên service trong docker-compose $db = getenv('MYSQL_DATABASE') ?: 'lemp_db'; $user = getenv('MYSQL_USER') ?: 'lemp_user'; $pass = getenv('MYSQL_PASSWORD') ?: 'lemp_pass_secret_2024';

try { $pdo = new PDO("mysql:host=$host;dbname=$db", $user, $pass); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$version = $pdo->query('SELECT VERSION()')->fetchColumn(); echo "<p class='success'>✅ Kết nối thành công! MariaDB version: <strong>$version</strong></p>"; } catch (PDOException $e) { echo "<p class='error'>❌ Lỗi kết nối: " . $e->getMessage() . "</p>"; } ?>

<h2>PHP Extensions đã cài</h2> <ul> <?php $check = ['pdo_mysql', 'mysqli', 'gd', 'zip', 'intl', 'mbstring', 'Zend OPcache']; foreach ($check as $ext) { $loaded = extension_loaded($ext) ? '✅' : '❌'; echo "<li>$loaded $ext</li>"; } ?> </ul> </body> </html> EOF

Bước 2: Build và khởi động

# Build PHP image và khởi động tất cả services
docker compose up -d --build

Lần đầu chạy sẽ mất vài phút vì Docker cần build PHP image (compile extensions). Output sẽ trông như thế này:

[+] Building 45.2s (8/8) FINISHED
 => [php internal] load build definition from Dockerfile
 => [php 2/4] RUN apk add --no-cache freetype-dev libjpeg-turbo-dev ...
 => [php 3/4] RUN docker-php-ext-configure gd --with-freetype --with-jpeg ...
 => [php 4/4] COPY php.ini /usr/local/etc/php/conf.d/custom.ini
 => exporting to image
[+] Running 4/4
 ✔ Network lemp-docker_lemp-network  Created
 ✔ Container lemp-mariadb            Started
 ✔ Container lemp-php                Started
 ✔ Container lemp-nginx              Started

Bước 3: Kiểm tra trạng thái

docker compose ps

Kết quả mong đợi, cả 3 container đều Up:

NAME            IMAGE                  STATUS          PORTS
lemp-mariadb    mariadb:11             Up 30 seconds   3306/tcp
lemp-nginx      nginx:alpine           Up 29 seconds   0.0.0.0:8080->80/tcp
lemp-php        lemp-docker-php        Up 30 seconds   9000/tcp

Bước 4: Test trên trình duyệt

Mở trình duyệt và truy cập:

http://your-server-ip:8080

Bạn sẽ thấy trang test hiển thị:

  • PHP version: 8.3.x
  • Kết nối MariaDB thành công với version number
  • Tất cả extensions đều có dấu ✅

Nếu muốn xem đầy đủ thông tin PHP, tạo thêm file phpinfo():

echo "<?php phpinfo();" > src/info.php

Truy cập http://your-server-ip:8080/info.php để xem toàn bộ cấu hình PHP. Nhớ xoá file này sau khi test xong: phpinfo tiết lộ rất nhiều thông tin nhạy cảm về server.

# Xoá sau khi test xong
rm src/info.php

Bước 5: Test kết nối database từ CLI

Ngoài test qua web, bạn có thể exec vào container MariaDB để kiểm tra trực tiếp:

# Exec vào container MariaDB
docker exec -it lemp-mariadb mariadb -u lemp_user -p
# Nhập password: lemp_pass_secret_2024
# Sau khi vào MySQL prompt:
SHOW DATABASES;
USE lemp_db;
SHOW TABLES;

Nếu thấy database lemp_db trong danh sách, mọi thứ đã hoạt động đúng.

Quản lý và tuỳ chỉnh LEMP Stack

LEMP Stack bằng Docker Compose linh hoạt hơn cài trực tiếp trên server rất nhiều. Dưới đây là các tuỳ chỉnh phổ biến:

Thêm PHP extension

Cần thêm extension Redis chẳng hạn? Sửa file php/Dockerfile:

# Thêm PECL extension (Redis, Xdebug, etc.)
RUN apk add --no-cache $PHPIZE_DEPS \
    && pecl install redis \
    && docker-php-ext-enable redis

Sau đó rebuild image:

docker compose up -d --build php

Docker sẽ rebuild chỉ service PHP, các service khác giữ nguyên. Cực kỳ tiện so với việc phải cài extension trên server thật rồi restart PHP-FPM.

Đổi phiên bản PHP

Muốn chuyển từ PHP 8.3 sang 8.2 (hoặc 8.1)? Chỉ cần sửa dòng đầu tiên trong php/Dockerfile:

# Đổi từ PHP 8.3 sang 8.2
FROM php:8.2-fpm-alpine

Rồi rebuild:

docker compose up -d --build php

Chỉ mất 1 phút, không cần uninstall PHP cũ, không sợ conflict version. Đây là một trong những lợi thế lớn nhất của Docker, chuyển đổi version cực kỳ dễ dàng.

Thêm virtual host cho nhiều domain

Muốn chạy nhiều website trên cùng một LEMP Stack? Tạo thêm file config Nginx cho từng domain:

mkdir -p nginx/conf.d

Tạo file nginx/conf.d/site1.conf:

server {
    listen 80;
    server_name site1.example.com;

root /var/www/site1; index index.php index.html;

location / { try_files $uri $uri/ /index.php?$query_string; }

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

Cập nhật docker-compose.yml để mount thêm thư mục config và source code:

  nginx:
    volumes:
      - ./src:/var/www/html
      - ./sites/site1:/var/www/site1          # Source code site 1
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
      - ./nginx/conf.d:/etc/nginx/conf.d/extra  # Thêm config files
php:
    volumes:
      - ./src:/var/www/html
      - ./sites/site1:/var/www/site1          # PHP cũng cần mount

Nhớ mount source code vào cả Nginx và PHP-FPM. Nếu thiếu một bên, bạn sẽ gặp lỗi “File not found” hoặc Nginx trả về 404.

Các lệnh quản lý thường dùng

# Xem logs của từng service
docker compose logs nginx
docker compose logs php
docker compose logs mariadb

# Xem logs realtime docker compose logs -f

# Restart một service (sau khi sửa config) docker compose restart nginx

# Vào shell container PHP (để debug, test) docker exec -it lemp-php sh

# Kiểm tra PHP extensions đã cài docker exec lemp-php php -m

# Backup database docker exec lemp-mariadb mariadb-dump -u root -p lemp_db > backup.sql

# Restore database docker exec -i lemp-mariadb mariadb -u root -p lemp_db < backup.sql

# Dừng toàn bộ stack docker compose down

# Dừng và xoá cả database volume (CẨN THẬN!) docker compose down -v

📚 Serie Docker từ A đến Z

  1. Bài 1: Docker là gì? Tại sao nên dùng Docker trên VPS
  2. Bài 2: Cài đặt Docker và Docker Compose trên VPS Ubuntu
  3. Bài 3: Làm quen với Docker – Các lệnh cơ bản cần biết
  4. Bài 4: Docker Image & Dockerfile – Tự tạo Image riêng
  5. Bài 5: Docker Volume & Network – Quản lý dữ liệu và mạng
  6. Bài 6: Docker Compose là gì? Cài đặt và cú pháp cơ bản
  7. Bài 7: Deploy WordPress + MySQL + phpMyAdmin bằng Docker Compose
  8. Bài 8: Deploy LEMP Stack (Nginx + PHP-FPM + MariaDB) bằng Docker Compose (đang đọc)
  9. Bài 9: Biến môi trường & file .env trong Docker Compose
  10. Bài 10: Reverse Proxy với Nginx Proxy Manager + SSL tự động
  11. Bài 11: Deploy ứng dụng Node.js / Python với Docker Compose
  12. Bài 12: Backup & Restore dữ liệu Docker Volume
  13. Bài 13: Monitoring Docker với Portainer, Uptime Kuma và cAdvisor
  14. Bài 14: Docker Logging – Quản lý log hiệu quả
  15. Bài 15: Bảo mật Docker trên VPS
  16. Bài 16: CI/CD đơn giản – Auto deploy với Webhook + Docker Compose
  17. Bài 17: Docker Compose trong thực tế – Tổng hợp project mẫu

Tổng kết

Trong bài này, bạn đã:

  • Hiểu LEMP Stack là gì và tại sao nó phổ biến hơn LAMP trong môi trường Docker/VPS
  • Viết custom Dockerfile cho PHP-FPM với các extensions cần thiết (pdo_mysql, gd, zip, opcache...)
  • Cấu hình Nginx để proxy request PHP qua FastCGI, cache static files, và bảo vệ file nhạy cảm
  • Dùng file .env để quản lý secrets tách biệt khỏi docker-compose.yml
  • Deploy và test thành công: PHP hoạt động, database kết nối OK, extensions đầy đủ
  • Biết cách tuỳ chỉnh: thêm extension, đổi PHP version, thêm virtual host cho nhiều domain

So với Bài 7 (WordPress stack dùng image có sẵn), bài này đã nâng cấp đáng kể: bạn tự build image, tự viết config, kiểm soát hoàn toàn từng thành phần. Đây mới là cách dùng Docker trong production thực tế.

Bạn có thể nhận ra rằng trong suốt bài này, mình đã hardcode nhiều giá trị trong file .env và truyền vào container qua environment. Nhưng khi project phức tạp hơn : nhiều environment (dev/staging/production), nhiều service, nhiều secrets , cách quản lý environment variables sẽ cần bài bản hơn.

Trong Bài 9, mình sẽ đi sâu vào Environment Variables & .env trong Docker: các cách truyền biến môi trường, thứ tự ưu tiên, quản lý secrets an toàn, và pattern cho multi-environment deployment. Hẹn gặp bạn ở bài tiếp theo! 🚀

👈 Bài trước: Deploy WordPress + MySQL + phpMyAdmin bằng Docker Compose

👉 Bài tiếp: Biến môi trường & file .env trong Docker Compose

Chia sẻ:
Bài viết đã được kiểm duyệt bởi AZDIGI Team

Về tác giả

Thạch Phạm

Thạch Phạm

Đồng sáng lập và Giám đốc điều hành của AZDIGI. Có hơn 15 năm kinh nghiệm trong phổ biến kiến thức liên quan đến WordPress tại thachpham.com, phát triển website và phát triển hệ thống.

Hơn 10 năm phục vụ 80.000+ khách hàng

Bắt đầu dự án web của bạn với AZDIGI