WordPress là một hệ quản trị nội dung (CMS) miễn phí và mã nguồn mở, được xây dựng trên cơ sở dữ liệu MySQL cùng xử lý PHP. Nhờ kiến trúc plugin có thể mở rộng và hệ thống mẫu, hầu hết việc quản trị có thể thực hiện qua giao diện web. Đây là lý do WordPress được ưa chuộng khi tạo các loại website khác nhau, từ blog đến trang sản phẩm và các trang thương mại điện tử.
Thường khi chạy WordPress, bạn cần cài đặt một ngăn xếp LAMP (Linux, Apache, MySQL và PHP) hoặc LEMP (Linux, Nginx, MySQL và PHP), có thể tốn 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 ưu tiên và cài đặt WordPress. Thay vì tự tay cài từng thành phần riêng lẻ, bạn có thể sử dụng các images, chuẩn hóa các thư viện, tệp cấu hình và biến môi trường, sau đó chạy trong các containers - các tiến trình riêng biệt trên hệ điều hành dùng chung. Ngoài ra với Docker Compose, bạn có thể phối hợp nhiều containers như ứ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 bộ cài WordPress đa container gồm cơ sở dữ liệu MySQL, máy chủ web Nginx và chính WordPress. Bạn cũng sẽ bảo mật cài đặt bằng việc lấy chứng chỉ TLS/SSL từ Let's Encrypt cho domain bạn chọn. Cuối cùng, bạn sẽ lên lịch tác vụ cron để tự động gia hạn chứng chỉ nhằm giữ cho domain của bạn luôn an toàn.
Nếu bạn đang dùng Ubuntu phiên bản 16.04 hoặc thấp hơn, nên nâng cấp lên phiên bản mới hơn vì Ubuntu không còn hỗ trợ các phiên bản này. Bộ hướng dẫn nâng cấp Ubuntu sẽ giúp bạn thực hiện việc này.
Để theo dõi hướng dẫn, bạn cần:
Sau khi chuẩn bị xong, bạn có thể bắt đầu bước đầu tiên.
Trước khi chạy container, bước đầu tiên của bạn là tạo cấu hình cho máy chủ web Nginx. Tệp cấu hình sẽ bao gồm các khối vị trí dành riêng cho WordPress, cùng với khối vị trí dẫn các yêu cầu xác minh Let’s Encrypt tới client Certbot để tự động gia hạn chứng chỉ.
Tạo thư mục dự án cho cài đặt WordPress, ví dụ đặt tên wordpress (bạn có thể đặt tên khác):
$ mkdir wordpress
Di chuyển vào thư mục:
$ cd wordpress
Tạo thư mục chứa tệp cấu hình:
$ mkdir nginx-conf
Mở tệp cấu hình để chỉnh sửa:
$ nano nginx-conf/nginx.conf
Trong tệp này, thêm một khối server với chỉ dẫn tên máy chủ và thư mục gốc, cùng các khối vị trí xử lý xác minh chứng chỉ Certbot, xử lý PHP và các yêu cầu tài nguyên tĩnh.
Thêm đoạn mã sau vào tệp, thay thế your_domain bằng tên miền thực tế 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;
}
}
Khối server bao gồm:
Các khối vị trí xử lý:
location ~ /.well-known/acme-challenge
: Xử lý xác minh chứng chỉ của Certbot.location /
: Kiểm tra tệp theo URI và chuyển sang WordPress khi không tìm thấy.location ~ \.php$
: Xử lý các yêu cầu PHP thông qua FastCGI tới container wordpress.location ~ /\.ht
: Từ chối phục vụ các tệp .htaccess.location = /favicon.ico
, location = /robots.txt
: Tắt ghi log các yêu cầu đến.location ~* \.(css|gif|ico|jpeg|jpg|js|png)$
: Tắt log và enable cache cho tài nguyên tĩnh.Lưu và đóng tệp.
Tiếp theo, bạn sẽ định nghĩa biến môi trường cho container ứng dụng và cơ sở dữ liệu.
Container cơ sở dữ liệu và ứng dụng WordPress cần truy cập các biến môi trường khi runtime để lưu trữ và sử dụng dữ liệu ứng dụng. Bao gồm cả thông tin nhạy cảm như mật khẩu root MySQL và tài khoản người dùng cơ sở dữ liệu cùng mật khẩu, cũng như thông tin không nhạy cảm như tên database và host.
Thay vì đặt tất cả biến trong tệp docker-compose.yml, biến nhạy cảm bạn nên đặt trong tệp .env và hạn chế chia sẻ để tránh lộ thông tin.
Tạo và mở file .env trong thư mục dự án wordpress:
$ nano .env
Thêm các biến sau (thay thế bằng giá trị của bạn):
MYSQL_ROOT_PASSWORD=your_root_password
MYSQL_USER=your_wordpress_database_user
MYSQL_PASSWORD=your_wordpress_database_password
Lưu và đóng.
Chắc chắn rằng file .env nằm trong .gitignore và .dockerignore để tránh bị đưa lên kho Git hoặc vào image Docker.
Tạo các file này nếu chưa có:
$ nano .gitignore
Thêm vào:
.env
$ nano .dockerignore
Thêm vào:
.env
.git
docker-compose.yml
.dockerignore
Lưu và đóng.
Bây giờ bạn đã sẵn sàng định nghĩa các dịch vụ trong docker-compose.yml.
Mở tệp docker-compose.yml trong thư mục wordpress:
$ nano docker-compose.yml
Thêm cấu hình phiên bản và dịch vụ database:
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:
Tiếp tục thêm dịch vụ 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
Chú ý:
Thêm dịch vụ máy chủ web 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
Dịch vụ 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
Trong đó cần thay sammy@your_domain và your_domain bằng email và domain của bạn. Lệnh certonly sử dụng plugin webroot để lấy chứng chỉ.
Phần cuối file khai báo volumes và networks:
volumes:
certbot-etc:
wordpress:
dbdata:
networks:
app-network:
driver: bridge
Lưu và đóng tệp.
Bạn sẽ dùng docker-compose up để khởi tạo và chạy các container.
Chạy lệnh sau để tạo và chạy các container:
$ docker-compose up -d
Kiểm tra trạng thái dịch vụ:
$ docker-compose ps
Nếu thành công, db, wordpress, webserver hiện trạng thái Up, certbot trạng thái Exit 0 (do chạy xong lệnh certonly).
Kiểm tra thư mục chứng chỉ:
$ docker-compose exec webserver ls -la /etc/letsencrypt/live
Nếu đã có thư mục domain, có nghĩa là chứng chỉ đã được tạo.
Bây giờ sửa lại docker-compose.yml, thay --staging thành --force-renewal trong lệnh certbot để lấy chứng chỉ thật:
Tiếp theo chạy lại:
$ docker-compose up --force-recreate --no-deps certbot
Kiểm tra thông báo thành công lấy chứng chỉ.
Dừng container webserver:
$ docker-compose stop webserver
Tải các tham số bảo mật SSL của Nginx 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 cũ:
$ rm nginx-conf/nginx.conf
Tạo lại nginx.conf mới có hỗ trợ redirect HTTP sang HTTPS và SSL (thay your_domain bằng domain của bạn):
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;
}
}
Cập nhật docker-compose.yml, thêm port 443 cho webserver:
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ụ chạy:
$ docker-compose ps
Mở trình duyệt truy cập https://your_domain (đổi thành domain của bạn)
Chọn ngôn ngữ, sau đó tạo tên site, chọn username (không nên dùng admin), mật khẩu mạnh, nhập email và cài đặt SEO theo ý muốn.
Cài đặt xong, đăng nhập vào dashboard WordPress và quản trị website.
Chứng chỉ Let's Encrypt có hiệu lực 90 ngày, cần tự động gia hạn để không bị hết hạn.
Tạo script gia hạn ssl_renew.sh trong thư mục wordpress:
#!/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 thành tên người dùng không phải root của bạn.
Đặt quyền thực thi:
$ chmod +x ssl_renew.sh
Thêm tác vụ cron để chạy script này định kỳ:
$ sudo crontab -e
Thêm dòng (chạy mỗi 5 phút để test):
*/5 * * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
Kiểm tra nhật ký sau 5 phút để đảm bảo việc gia hạn thực hiện thành công:
$ tail -f /var/log/cron.log
Sau khi test thành công, bạn có thể đặt chạy 1 lần mỗi ngày (ví dụ chạy lúc 12h trưa):
0 12 * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
Đồng thời xóa tùy chọn --dry-run trong script ssl_renew.sh để thực hiện gia hạn thật.
Bạn cũng nên cấu hình logrotate để quản lý nhật ký cron.
Trong hướng dẫn này, bạn đã sử dụng Docker Compose để tạo bộ cài WordPress với máy chủ Nginx, lấy chứng chỉ TLS/SSL cho domain, và thiết lập cron để tự động gia hạn chứng chỉ.
Bạn có thể tham khảo thêm các bài viết để cải thiện hiệu năng và sao lưu tài nguyên WordPress, hoặc thử tìm hiểu cách cài đặt WordPress trên Kubernetes bằng Helm để khám phá quy trình container hóa nâng cao.