Posted on: July 17, 2025
Chạy WordPress thường yêu cầu cài đặt ngăn xếp LAMP (Linux, Apache, MySQL và PHP) hoặc LEMP (Linux, Nginx, MySQL và PHP), điều này có thể mất nhiều thời gian. Tuy nhiên, bằng cách sử dụng các công cụ như Docker và Docker Compose, bạn có thể đơn giản hóa quá trình thiết lập ngăn xếp ưa thích và cài đặt WordPress. Thay vì cài từng thành phần riêng lẻ, bạn có thể sử dụng các image tiêu chuẩn hóa các thư viện, file cấu hình và biến môi trường. Sau đó, chạy các image này trong các container, là các tiến trình tách biệt chạy trên cùng hệ điều hành chia sẻ. Ngoài ra, bằng Compose, bạn có thể phối hợp nhiều container — ví dụ một ứng dụng và cơ sở dữ liệu — để giao tiếp với nhau.
Trong hướng dẫn này, bạn sẽ xây dựng một cài đặt WordPress đa container. Các container của bạn sẽ bao gồm cơ sở dữ liệu MySQL, máy chủ web Nginx và WordPress. Bạn cũng sẽ bảo mật cài đặt bằng cách lấy chứng chỉ TLS/SSL với Let’s Encrypt cho tên miền bạn muốn liên kết với website. Cuối cùng, bạn sẽ thiết lập một công việc cron để gia hạn chứng chỉ tự động nhằm giữ cho tên miền luôn bảo mật.
Trước khi chạy bất kỳ container nào, bước đầu tiên là định nghĩa cấu hình cho máy chủ web Nginx của bạn. File cấu hình sẽ bao gồm một số khối location đặc thù cho WordPress, cùng với khối location để chuyển yêu cầu xác thực Let’s Encrypt tới client Certbot nhằm tự động gia hạn chứng chỉ.
Đầu tiên, tạo thư mục dự án cho WordPress, ví dụ gọi là wordpress
. Bạn có thể đặt tên khác nếu muốn:
mkdir wordpress
cd wordpress
mkdir nginx-conf
nano nginx-conf/nginx.conf
Trong file này, thêm một server block với các chỉ thị cho tên máy chủ và thư mục gốc, cùng các khối location nhằm xử lý yêu cầu chứng thực của Certbot, PHP và tài nguyên tĩnh.
Nội dung file (thay thế your_domain
bằng tên miền của bạn):
server {
listen 80;
listen [::]:80;
server_name your_domain www.your_domain;
index index.php index.html index.htm;
root /var/www/html;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass wordpress:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location ~ /\.ht {
deny all;
}
location = /favicon.ico {
log_not_found off; access_log off;
}
location = /robots.txt {
log_not_found off; access_log off; allow all;
}
location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
expires max;
log_not_found off;
}
}
Server block này bao gồm:
listen 80
: Nginx lắng nghe cổng 80 cho plugin webroot của Certbot xử lý yêu cầu chứng thực (port 443 chưa được thêm vì bạn sẽ cập nhật sau khi có chứng chỉ SSL).server_name
: tên miền và bản ghi www.index
: ưu tiên file index.php.root
: thư mục gốc /var/www/html
được mount bởi WordPress Dockerfile.Các khối location xử lý:
.well-known/acme-challenge
: thư mục xác thực Let’s Encrypt./
: xử lý các URI bằng cách check file hoặc chuyển tiếp đến WordPress index.php..php
: xử lý PHP và proxy qua container WordPress (dùng php-fpm với FastCGI)..htaccess
: chặn truy cập file .ht.Sau khi chỉnh sửa lưu file.
Container cơ sở dữ liệu và WordPress cần truy cập các biến môi trường chứa dữ liệu nhạy cảm (mật khẩu root MySQL, tài khoản DB WordPress) cũng như thông tin không nhạy cảm (tên DB, host).
Bạn nên đặt các biến nhạy cảm trong file .env
và giới hạn quyền truy cập để tránh bị lộ khi push repo.
Tạo file .env
trong thư mục dự án ~/wordpress
và thêm nội dung:
nano .env
MYSQL_ROOT_PASSWORD=your_root_password
MYSQL_USER=your_wordpress_database_user
MYSQL_PASSWORD=your_wordpress_database_password
Thay your_root_password
, your_wordpress_database_user
và your_wordpress_database_password
bằng thông tin thực tế.
Đảm bảo thêm .env
vào .gitignore
và .dockerignore
để tránh bị commit hoặc copy vào Docker image:
nano .gitignore
Thêm dòng:
Tương tự cho .dockerignore
:
nano .dockerignore
Thêm:
.git
docker-compose.yml
.dockerignore
Tạo file docker-compose.yml
trong thư mục dự án để định nghĩa các service (container).
nano docker-compose.yml
Thêm cấu hình cho service db
:
version: '3'
services:
db:
image: mysql:8.0
container_name: db
restart: unless-stopped
env_file: .env
environment:
- MYSQL_DATABASE=wordpress
volumes:
- dbdata:/var/lib/mysql
command: '--default-authentication-plugin=mysql_native_password'
networks:
- app-network
Giải thích:
mysql:8.0
: version cố định để tránh xung đột.env_file
: lấy biến từ .env
.environment
: định nghĩa tên database.volumes
: mount volume để lưu dữ liệu MySQL.command
: dùng plugin xác thực legacy hỗ trợ php-fpm.networks
: tham gia mạng nội bộ app-network.Thêm service wordpress
:
wordpress:
depends_on:
- db
image: wordpress:5.1.1-fpm-alpine
container_name: wordpress
restart: unless-stopped
env_file: .env
environment:
- WORDPRESS_DB_HOST=db:3306
- WORDPRESS_DB_USER=$MYSQL_USER
- WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
- WORDPRESS_DB_NAME=wordpress
volumes:
- wordpress:/var/www/html
networks:
- app-network
Thêm service webserver
sử dụng Nginx:
webserver:
depends_on:
- wordpress
image: nginx:1.15.12-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
volumes:
- wordpress:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- app-network
Cuối cùng service certbot
để lấy chứng chỉ:
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- wordpress:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain
volumes:
certbot-etc:
wordpress:
dbdata:
networks:
app-network:
driver: bridge
Thay sammy@your_domain
, your_domain
bằng thông tin thực.
Khởi chạy container với:
docker-compose up -d
Kiểm tra trạng thái:
docker-compose ps
Kiểm tra thư mục /etc/letsencrypt/live
trong container webserver:
docker-compose exec webserver ls -la /etc/letsencrypt/live
Nếu chứng chỉ thành công, hãy chỉnh sửa file docker-compose.yml
để xóa flag --staging
và thay bằng --force-renewal
trong service certbot:
command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --force-renewal -d your_domain -d www.your_domain
Sau đó chạy lại certbot:
docker-compose up --force-recreate --no-deps certbot
Chứng chỉ sẽ được gia hạn trên server.
Để kích hoạt SSL trên Nginx, bạn sẽ cấu hình chuyển hướng HTTP sang HTTPS, thêm chứng chỉ SSL, các tham số bảo mật và header.
Dừng webserver:
docker-compose stop webserver
Tải file tham số bảo mật SSL từ Certbot:
curl -sSLo nginx-conf/options-ssl-nginx.conf https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf
Xóa file cấu hình nginx hiện tại:
rm nginx-conf/nginx.conf
Tạo lại file cấu hình với nội dung sau (thay thế your_domain
):
server {
listen 80;
listen [::]:80;
server_name your_domain www.your_domain;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
location / {
rewrite ^ https://$host$request_uri? permanent;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name your_domain www.your_domain;
index index.php index.html index.htm;
root /var/www/html;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;
include /etc/nginx/conf.d/options-ssl-nginx.conf;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass wordpress:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location ~ /\.ht {
deny all;
}
location = /favicon.ico {
log_not_found off; access_log off;
}
location = /robots.txt {
log_not_found off; access_log off; allow all;
}
location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
expires max;
log_not_found off;
}
}
Thêm port 443 vào service webserver
trong docker-compose.yml
:
ports:
- "80:80"
- "443:443"
Khởi động lại webserver:
docker-compose up -d --force-recreate --no-deps webserver
Kiểm tra dịch vụ đang chạy:
docker-compose ps
Truy cập trang web bằng trình duyệt với URL:
https://your_domain
Chọn ngôn ngữ sử dụng, tiếp tục chọn tên trang, tên đăng nhập và mật khẩu, nhập email và thiết lập có cho phép các công cụ tìm kiếm index trang hay không.
Bấm “Install WordPress” và tiến hành đăng nhập.
Bạn sẽ thấy được trang dashboard quản trị WordPress.
Chứng chỉ Let’s Encrypt có hiệu lực 90 ngày, bạn cần thiết lập gia hạn tự động bằng công việc cron
.
Tạo script ssl_renew.sh
:
nano ssl_renew.sh
Nội dung:
#!/bin/bash
COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"
cd /home/sammy/wordpress/
$COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
Thay sammy
bằng username không phải root của bạn.
Cấp quyền thực thi:
chmod +x ssl_renew.sh
Chỉnh sửa crontab cho root:
sudo crontab -e
Thêm dòng chạy script sau mỗi 5 phút (để kiểm tra):
*/5 * * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
Kiểm tra log:
tail -f /var/log/cron.log
Nếu thành công, xem thông báo gia hạn thành công.
Bạn có thể chỉnh lại thời gian chạy theo ngày bằng cách sửa crontab:
0 12 * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
Và nhớ bỏ --dry-run
trong script để gia hạn thực:
$COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
Việc này đảm bảo chứng chỉ của bạn luôn được gia hạn trước khi hết hạn.
Hướng dẫn này đã chỉ bạn cách sử dụng Docker Compose để tạo cài đặt WordPress với Nginx làm webserver, đồng thời lấy và gia hạn chứng chỉ TLS/SSL cho tên miền.
Bạn cũng đã thiết lập script cùng cron job gia hạn tự động chứng chỉ để duy trì bảo mật.
Ngoài ra, bạn có thể tham khảo thêm hướng dẫn tăng tốc phân phối tài nguyên WordPress, sao lưu và lưu trữ tài nguyên trên DigitalOcean Spaces hoặc thử workflow container với Kubernetes và Helm.