WordPress là một hệ quản trị nội dung (CMS) mã nguồn mở và miễn phí, được phát triển trên nền tảng MySQL và PHP. Nhờ vào kiến trúc mở với plugin và hệ thống mẫu, hầu hết các tác vụ quản lý có thể thực hiện trực tiếp qua giao diện web, điều này giúp WordPress trở thành một lựa chọn phổ biến để xây dựng nhiều loại website, từ blog cá nhân, trang giới thiệu sản phẩm cho đến các cửa hàng thương mại điện tử.
Thông thường, việc triển khai WordPress yêu cầu cài đặt một stack LAMP (Linux, Apache, MySQL, PHP) hoặc LEMP (Linux, Nginx, MySQL, PHP), quá trình này có thể tốn nhiều thời gian. Tuy nhiên, với các công cụ như Docker và Docker Compose, bạn có thể đơn giản hóa quá trình cài đặt. Thay vì cài đặt từng thành phần riêng lẻ, bạn có thể sử dụng các image Docker chuẩn, giúp đồng bộ hóa các thư viện, cấu hình và biến môi trường, rồi chạy chúng trong các container – các tiến trình tách biệt nhưng chia sẻ cùng hệ điều hành. Bằng cách sử dụng Docker Compose, bạn có thể phối hợp nhiều container, ví dụ như ứng dụng và cơ sở dữ liệu, để chúng có thể giao tiếp hiệu quả.
Bạn muốn xây dựng website WordPress chuyên nghiệp? Hãy bắt đầu bằng cách mua VPS chất lượng cao để đảm bảo hiệu suất và bảo mật. Với VPS, bạn dễ dàng cài đặt Docker Compose, tối ưu hóa WordPress, mang đến trải nghiệm mượt mà cho người dùng. Khám phá các gói VPS ngay hôm nay!
Trong bài hướng dẫn này, bạn sẽ xây dựng một cài đặt WordPress với nhiều container, bao gồm MySQL, Nginx và chính WordPress. Bạn cũng sẽ bảo mật hệ thống bằng cách cài đặt chứng chỉ TLS/SSL từ Let’s Encrypt cho tên miền của mình. Cuối cùng, bạn sẽ cấu hình cron job để tự động gia hạn chứng chỉ, giúp bảo vệ website của bạn luôn được bảo mật.
Yêu Cầu
Nếu bạn đang sử dụng Ubuntu phiên bản 16.04 trở xuống, chúng tôi khuyến nghị bạn nâng cấp lên phiên bản mới nhất vì Ubuntu không còn hỗ trợ những phiên bản cũ này. Bộ sưu tập hướng dẫn này sẽ hỗ trợ bạn trong việc nâng cấp phiên bản Ubuntu.
Để theo dõi hướng dẫn này, bạn cần:
● Một máy chủ chạy Ubuntu, kèm theo một người dùng không phải root có quyền sudo và một firewall đang hoạt động. Để được hướng dẫn thiết lập, vui lòng chọn bản phân phối của bạn trong danh sách và làm theo Hướng Dẫn Thiết Lập Máy Chủ Ban Đầu.
● Docker được cài đặt trên máy chủ, theo các bước 1 và 2 của “Cách Cài Đặt và Sử Dụng Docker trên Ubuntu” 22.04 / 20.04 / 18.04.
● Docker Compose được cài đặt trên máy chủ, theo bước 1 của “Cách Cài Đặt Docker Compose trên Ubuntu” 22.04 / 20.04 / 18.04.
● Một tên miền đã được đăng ký. Hướng dẫn này sẽ sử dụng your_domain như một tên miền mẫu. Bạn có thể đăng ký miễn phí tại Freenom hoặc sử dụng nhà đăng ký tên miền mà bạn thích.
● Cả hai bản ghi DNS sau đã được thiết lập cho máy chủ của bạn. Bạn có thể theo dõi phần giới thiệu về DNS của DataOnline để biết cách thêm chúng vào tài khoản DataOnline:
- Một bản ghi A với
your_domain
trỏ tới địa chỉ IP công cộng của máy chủ. - Một bản ghi A với
www.your_domain
trỏ tới địa chỉ IP công cộng của máy chủ.
Khi bạn đã thiết lập xong mọi thứ, bạn đã sẵn sàng bắt đầu bước đầu tiên.
Bước 1 – Xác định cấu hình máy chủ Web
Trước khi chạy bất kỳ container nào, bước đầu tiên của bạn là xác định cấu hình cho máy chủ web Nginx. Tệp cấu hình của bạn sẽ bao gồm một số khối location đặc trưng cho WordPress, cùng với một khối location để chuyển hướng các yêu cầu xác minh của Let’s Encrypt tới Certbot để gia hạn chứng chỉ tự động.
Đầu tiên, tạo một thư mục dự án cho cài đặt WordPress của bạn. Trong ví dụ này, thư mục được đặt tên là wordpress. Bạn có thể đặt tên khác nếu muốn:
mkdir wordpress
Sau đó, di chuyển vào thư mục:
cd wordpress
Tiếp theo, tạo một thư mục cho tệp cấu hình:
mkdir nginx-conf
Mở tệp cấu hình với nano (hoặc trình soạn thảo ưa thích của bạn):
nano nginx-conf/nginx.conf
Trong tệp này, thêm một khối server với các chỉ thị cho tên máy chủ và thư mục gốc, cùng với các khối location để chuyển hướng yêu cầu của Certbot, xử lý PHP và phục vụ các tài sản tĩnh.
Thêm đoạn mã sau vào tệp. Hãy nhớ thay thế your_domain
bằng tên miền của bạn:
~/wordpress/nginx-conf/nginx.conf 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; } }
Giải Thích:
-
Directives:
- listen: Chỉ thị này báo cho Nginx lắng nghe trên cổng 80, cho phép bạn sử dụng plugin webroot của Certbot cho yêu cầu chứng chỉ. Lưu ý rằng bạn chưa bao gồm cổng 443 – bạn sẽ cập nhật cấu hình để bao gồm SSL sau khi lấy chứng chỉ thành công.
- server_name: Xác định tên máy chủ và khối server sẽ được sử dụng cho các yêu cầu tới máy chủ của bạn. Hãy thay your_domain bằng tên miền của bạn.
- index: Chỉ thị này định nghĩa các tệp sẽ được sử dụng làm chỉ mục khi xử lý các yêu cầu. Bạn đã thay đổi thứ tự ưu tiên mặc định bằng cách đặt index.php lên trước index.html để Nginx ưu tiên các tệp có tên index.php khi có thể.
- root: Chỉ thị này đặt thư mục gốc cho các yêu cầu tới máy chủ của bạn. Thư mục này (/var/www/html) được tạo ra làm điểm mount trong quá trình build theo hướng dẫn trong Dockerfile của WordPress. Các chỉ thị trong Dockerfile cũng đảm bảo rằng các tệp từ bản phát hành WordPress được mount vào volume này.
-
Location Blocks:
location ~ /.well-known/acme-challenge
: Khối này xử lý các yêu cầu tới thư mục.well-known
, nơi Certbot sẽ đặt tệp tạm thời để xác nhận rằng DNS của tên miền trỏ tới máy chủ của bạn. Cấu hình này cho phép bạn sử dụng plugin webroot của Certbot để lấy chứng chỉ cho tên miền.location /
: Khối này sử dụng chỉ thịtry_files
để kiểm tra xem có tệp nào khớp với URI được yêu cầu không. Nếu không, thay vì trả về lỗi 404, yêu cầu sẽ được chuyển tới tệp index.php của WordPress cùng với các tham số.location ~ .php$
: Khối này xử lý việc xử lý PHP và chuyển tiếp các yêu cầu này đến container wordpress. Vì image WordPress của bạn dựa trên imagephp:fpm
, nên bạn cũng sẽ bao gồm các tùy chọn cấu hình cụ thể cho giao thức FastCGI. Nginx yêu cầu một bộ xử lý PHP riêng cho các yêu cầu PHP; trong trường hợp này, các yêu cầu sẽ được xử lý bởiphp-fpm
có sẵn trong image php:fpm. Khối này bao gồm các chỉ thị, biến và tùy chọn riêng cho FastCGI để chuyển tiếp yêu cầu tới ứng dụng WordPress đang chạy trong container wordpress, đặt chỉ mục ưu tiên cho URI đã phân tích và xử lý các yêu cầu URI.location ~ /.ht
: Khối này đảm bảo rằng các tệp .htaccess không được phục vụ bởi Nginx. Chỉ thị deny all đảm bảo rằng các tệp.htaccess
sẽ không bao giờ được phục vụ cho người dùng.location = /favicon.ico, location = /robots.txt:
Các khối này đảm bảo rằng các yêu cầu tới/favicon.ico
và/robots.txt
sẽ không được ghi log.location ~ .(css|gif|ico|jpeg|jpg|js|png)$
:* Khối này tắt ghi log cho các yêu cầu tới tài sản tĩnh và đảm bảo rằng các tài sản này có thể được cache với thời gian cao, vì chúng thường tốn kém để phục vụ.
Để biết thêm thông tin về proxy FastCGI, hãy đọc “Hiểu và Triển khai FastCGI Proxying trong Nginx.”. Để biết thêm về các khối server và location, hãy xem “Understanding Nginx Server and Location Block Selection Algorithms”.
Sau khi hoàn tất chỉnh sửa, lưu và đóng tệp. Nếu bạn dùng nano
, nhấn CTRL+X
, Y
, sau đó ENTER
.
Với cấu hình Nginx đã sẵn sàng, bạn có thể chuyển sang tạo các biến môi trường để truyền vào container ứng dụng và cơ sở dữ liệu tại thời điểm chạy.
Bước 2 – Xác định các biến môi trường
Các container cơ sở dữ liệu và ứng dụng WordPress của bạn sẽ cần truy cập vào một số biến môi trường tại thời điểm chạy để dữ liệu ứng dụng của bạn được lưu trữ và truy cập. Các biến này bao gồm cả thông tin nhạy cảm và không nhạy cảm: giá trị nhạy cảm cho mật khẩu root của MySQL và tên người dùng cùng mật khẩu của cơ sở dữ liệu ứng dụng, và thông tin không nhạy cảm cho tên cơ sở dữ liệu và máy chủ.
Thay vì đặt tất cả các giá trị này trong tệp Docker Compose – tệp chính chứa thông tin về cách các container của bạn sẽ chạy – bạn hãy đặt các giá trị nhạy cảm trong tệp .env
và hạn chế việc lưu hành nó. Điều này sẽ ngăn các giá trị này bị sao chép vào kho lưu trữ dự án và bị lộ ra ngoài.
Trong thư mục dự án chính, ~/wordpress
, mở một tệp có tên .env
:
nano .env
Trong tệp này, bạn sẽ đặt các giá trị bí mật bao gồm mật khẩu cho người dùng root của MySQL, cũng như tên người dùng và mật khẩu mà WordPress sẽ sử dụng để truy cập cơ sở dữ liệu.
Thêm các biến và giá trị sau vào tệp. Hãy nhớ thay thế các giá trị mẫu bằng giá trị thực của bạn:
~/wordpress/.env MYSQL_ROOT_PASSWORD=your_root_password MYSQL_USER=your_wordpress_database_user MYSQL_PASSWORD=your_wordpress_database_password
Ở đây, bạn đã bao gồm mật khẩu cho tài khoản quản trị root, cùng với tên người dùng và mật khẩu ưa thích cho cơ sở dữ liệu ứng dụng của bạn.
Lưu và đóng tệp khi bạn đã hoàn tất chỉnh sửa.
Vì tệp .env
chứa thông tin nhạy cảm, bạn cần đảm bảo rằng nó được thêm vào các tệp .gitignore
và .dockerignore
của dự án. Điều này sẽ báo cho Git và Docker biết những tệp nào không được sao chép vào kho lưu trữ Git và image Docker.
Nếu bạn dự định sử dụng Git cho việc kiểm soát phiên bản, hãy khởi tạo thư mục làm việc hiện tại của bạn như một repository với:
git init
Sau đó tạo và mở tệp .gitignore
:
nano .gitignore
Thêm dòng sau vào tệp:
~/wordpress/.gitignore .env
Lưu và đóng tệp sau khi chỉnh sửa.
Tương tự, bạn nên thêm .env
vào tệp .dockerignore
để đảm bảo nó không bị đưa lên container khi sử dụng thư mục này làm build context.
Mở tệp:
nano .dockerignore
Thêm dòng sau vào tệp:
~/wordpress/.dockerignore .env
Ngoài ra, bạn có thể thêm các tệp và thư mục liên quan đến phát triển ứng dụng của bạn vào:
~/wordpress/.dockerignore .env .git docker-compose.yml .dockerignore
Lưu và đóng tệp khi bạn đã hoàn tất.
Với thông tin nhạy cảm đã được thiết lập, bạn có thể chuyển sang xác định các dịch vụ trong tệp docker-compose.yml.
Bước 3 – Xác định các dịch vụ với Docker Compose
Tệp docker-compose.yml
của bạn sẽ chứa các định nghĩa dịch vụ cho cài đặt này. Một dịch vụ trong Compose là một container đang chạy, và định nghĩa dịch vụ xác định thông tin về cách mỗi container sẽ chạy.
Sử dụng Compose, bạn có thể định nghĩa các dịch vụ khác nhau để chạy ứng dụng đa container, vì Compose cho phép bạn liên kết các dịch vụ này với nhau thông qua mạng và volume chia sẻ. Điều này rất hữu ích trong cài đặt hiện tại, vì bạn sẽ tạo các container riêng biệt cho cơ sở dữ liệu, ứng dụng WordPress và máy chủ web. Bạn cũng sẽ tạo một container để chạy Certbot nhằm lấy chứng chỉ cho máy chủ web.
Đầu tiên, tạo và mở tệp docker-compose.yml
:
nano docker-compose.yml
Thêm đoạn mã sau để định nghĩa phiên bản Compose và dịch vụ cơ sở dữ liệu (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 về dịch vụ db:
image
: Chỉ định image nào sẽ được kéo về để tạo container. Ở đây, bạn cố định imagemysql:8.0
để tránh xung đột phiên bản khi imagemysql:latest
tiếp tục được cập nhật. (Xem thêm về việc cố định phiên bản và tránh xung đột phụ thuộc tại tài liệu Dockerfile Best Practices.)container_name
: Xác định tên cho container.restart
: Xác định chính sách khởi động lại container. Mặc định là không, nhưng bạn đã đặt container khởi động lại trừ khi bị dừng thủ công.env_file
: Tùy chọn này cho biết Compose sẽ lấy các biến môi trường từ tệp.env
nằm trong build context hiện tại.environment
: Cho phép thêm các biến môi trường bổ sung, ngoài những biến đã được định nghĩa trong tệp.env
. Bạn đặt biếnMYSQL_DATABASE
bằngwordpress
để đặt tên cho cơ sở dữ liệu ứng dụng. Vì đây là thông tin không nhạy cảm, bạn có thể đưa trực tiếp vào tệpdocker-compose.yml
.volumes
: Mount một volume được đặt tên làdbdata
vào thư mục/var/lib/mysql
trên container – thư mục dữ liệu chuẩn của MySQL.command
: Ghi đè lệnh CMD mặc định của image. Ở đây, bạn thêm một tham số cho lệnhmysqld
để bắt đầu MySQL trên container, thiết lập tham số--default-authentication-plugin
thànhmysql_native_password
nhằm chỉ định cơ chế xác thực cho các yêu cầu xác thực mới. Vì PHP (và do đó image WordPress) của bạn không hỗ trợ cơ chế xác thực mới của MySQL, nên bạn cần điều chỉnh này để xác thực người dùng cơ sở dữ liệu ứng dụng.networks
: Cho biết dịch vụ sẽ tham gia vào mạngapp-network
, mà bạn sẽ định nghĩa ở cuối tệp.
Tiếp theo, ngay dưới định nghĩa dịch vụ db
, thêm định nghĩa cho dịch vụ ứng dụng 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
Giải Thích về dịch vụ wordpress:
depends_on
: Đảm bảo containerwordpress
khởi động sau containerdb
vì ứng dụng WordPress phụ thuộc vào cơ sở dữ liệu.image
: Sử dụng image WordPress5.1.1-fpm-alpine
. Image này đảm bảo ứng dụng có bộ xử lýphp-fpm
cần thiết cho Nginx xử lý PHP. Đây cũng là image alpine, được xây dựng trên Alpine Linux, giúp giảm kích thước tổng thể của image.env_file
: Lấy các biến từ tệp.env
chứa thông tin người dùng và mật khẩu cơ sở dữ liệu.environment
: Gán các giá trị từ.env
cho các biến mà image WordPress mong đợi:WORDPRESS_DB_USER
vàWORDPRESS_DB_PASSWORD
. Đồng thời, định nghĩaWORDPRESS_DB_HOST
là máy chủ MySQL đang chạy trên containerdb
ở cổng 3306, vàWORDPRESS_DB_NAME
là tên cơ sở dữ liệu đã định nghĩa làwordpress
.volumes
: Mount một volume được đặt tên làwordpress
vào thư mục/var/www/html
– điểm mount được tạo bởi image WordPress.networks
: Thêm container vào mạngapp-network
.
Sau đó, ngay dưới định nghĩa dịch vụ wordpress, thêm định nghĩa cho 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
Giải Thích về dịch vụ webserver:
depends_on
: Đảm bảo containerwebserver
khởi động sau containerwordpress
.image
: Sử dụng image Nginx1.15.12-alpine
.ports
: Mở cổng80
để kích hoạt các tùy chọn cấu hình trong tệpnginx.conf
đã định nghĩa ở Bước 1.volumes
: Kết hợp giữa volume được đặt tên và bind mount:wordpress:/var/www/html:
Mount mã nguồn WordPress vào thư mục gốc đã thiết lập trong khối server của Nginx../nginx-conf:/etc/nginx/conf.d
: Bind mount thư mục cấu hình Nginx từ host vào container, giúp mọi thay đổi trên host được phản ánh ngay.certbot-etc:/etc/letsencrypt
: Mount các chứng chỉ và khóa của Let’s Encrypt vào thư mục thích hợp trên container.
networks
: Thêm container vào mạngapp-network
.
Cuối cùng, ngay dưới định nghĩa dịch vụ webserver
, thêm định nghĩa cho dịch vụ certbot
:
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
Giải Thích về dịch vụ certbot:
Dịch vụ này kéo image certbot/certbot
từ Docker Hub và sử dụng các volume để chia sẻ tài nguyên với container Nginx, bao gồm chứng chỉ và khóa (volume certbot-etc
) và mã ứng dụng WordPress (volume wordpress
).
depends_on
: Đảm bảo container certbot khởi động sau containerwebserver
.command
: Lệnh này ghi đè lệnh mặc định của certbot. Tham sốcertonly
sẽ lấy chứng chỉ với các tùy chọn sau:--webroot
: Sử dụng plugin webroot để đặt tệp xác thực vào thư mục gốc.- –webroot-path: Đường dẫn đến thư mục gốc.
--email
: Địa chỉ email của bạn.--agree-tos
: Đồng ý với Điều Khoản của ACME.--no-eff-email
: Không chia sẻ email với EFF.--staging
: Sử dụng môi trường thử nghiệm của Let’s Encrypt để lấy chứng chỉ test.-d
: Chỉ định tên miền áp dụng, ở đây làyour_domain
vàwww.your_domain
(hãy thay bằng tên miền của bạn).
Tiếp theo, bên dưới định nghĩa dịch vụ, thêm phần định nghĩa cho network và volumes:
... volumes: certbot-etc: wordpress: dbdata: networks: app-network: driver: bridge
Giải Thích:
- Phần
volumes
cấp định nghĩa cho các volumecertbot-etc
,wordpress
vàdbdata
. Khi Docker tạo volume, nội dung của volume được lưu trữ tại thư mục trên host, và được mount vào bất kỳ container nào sử dụng volume đó, giúp chia sẻ mã nguồn và dữ liệu giữa các container. - Mạng
app-network
kiểu bridge cho phép các container giao tiếp với nhau mà không cần mở cổng ra bên ngoài. Nhờ đó, các containerdb
, wordpress vàwebserver
có thể giao tiếp nội bộ, chỉ cần mở cổng 80 để truy cập từ bên ngoài.
Dưới đây là tệp docker-compose.yml
hoàn chỉnh:
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 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 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 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
Lưu và đóng tệp khi đã chỉnh sửa xong.
Với các định nghĩa dịch vụ đã sẵn sàng, bạn đã sẵn sàng khởi động các container và kiểm tra yêu cầu chứng chỉ.
Bước 4 – Lấy chứng chỉ SSL và thông tin xác thực
Khởi chạy các container bằng lệnh docker-compose up
, lệnh này sẽ tạo và chạy các container theo thứ tự bạn đã chỉ định. Bằng cách thêm tham số -d
, lệnh sẽ chạy các container db, wordpress và webserver ở chế độ nền:
docker-compose up -d
Đầu ra dưới đây xác nhận rằng các dịch vụ của bạn đã được tạo:
Output Creating db ... done Creating wordpress ... done Creating webserver ... done Creating certbot ... done
Sử dụng lệnh docker-compose ps
để kiểm tra trạng thái của các dịch vụ:
docker-compose ps
Khi hoàn tất, các dịch vụ db
, wordpress và webserver
của bạn sẽ ở trạng thái Up và container certbot
sẽ thoát với thông báo trạng thái 0:
Output Name Command State Ports ------------------------------------------------------------------------- certbot certbot certonly --webroot ... Exit 0 db docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp wordpress docker-entrypoint.sh php-fpm Up 9000/tcp
Bất kỳ trạng thái nào khác ngoài Up trong cột State của các dịch vụ db, wordpress hoặc webserver, hoặc mã thoát khác ngoài 0 đối với container certbot có nghĩa là bạn có thể cần kiểm tra nhật ký của dịch vụ bằng lệnh docker-compose logs
:
docker-compose logs service_name
Bạn có thể kiểm tra rằng chứng chỉ của bạn đã được mount vào container webserver bằng lệnh docker-compose exec
:
docker-compose exec webserver ls -la /etc/letsencrypt/live
Khi các yêu cầu chứng chỉ của bạn thành công, đầu ra sẽ như sau:
Output total 16 drwx------ 3 root root 4096 May 10 15:45 . drwxr-xr-x 9 root root 4096 May 10 15:45 .. -rw-r--r-- 1 root root 740 May 10 15:45 README drwxr-xr-x 2 root root 4096 May 10 15:45 your_domain
Giờ bạn đã biết yêu cầu của mình sẽ thành công, bạn có thể chỉnh sửa định nghĩa dịch vụ certbot để loại bỏ tham số --staging
.
Mở file docker-compose.yml
:
nano docker-compose.yml
Tìm phần trong file có định nghĩa dịch vụ certbot, và thay thế tham số --staging
trong tùy chọn command bằng tham số --force-renewal
, lệnh này sẽ báo cho Certbot rằng bạn muốn yêu cầu một chứng chỉ mới với cùng các tên miền như chứng chỉ đã có. Dưới đây là định nghĩa dịch vụ certbot với tham số đã được cập nhật:
... certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - certbot-var:/var/lib/letsencrypt - wordpress:/var/www/html 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 ...
Bây giờ, bạn có thể chạy lệnh docker-compose up
để tạo lại container certbot
. Bạn cũng sẽ thêm tham số --no-deps
để báo cho Compose rằng có thể bỏ qua việc khởi động dịch vụ webserver
, vì nó đã đang chạy:
docker-compose up --force-recreate --no-deps certbot
Đầu ra dưới đây cho biết rằng yêu cầu chứng chỉ của bạn đã thành công:
Output Recreating certbot ... done Attaching to certbot certbot | Saving debug log to /var/log/letsencrypt/letsencrypt.log certbot | Plugins selected: Authenticator webroot, Installer None certbot | Renewing an existing certificate certbot | Performing the following challenges: certbot | http-01 challenge for your_domain certbot | http-01 challenge for www.your_domain certbot | Using the webroot path /var/www/html for all unmatched domains. certbot | Waiting for verification... certbot | Cleaning up challenges certbot | IMPORTANT NOTES: certbot | - Congratulations! Your certificate and chain have been saved at: certbot | /etc/letsencrypt/live/your_domain/fullchain.pem certbot | Your key file has been saved at: certbot | /etc/letsencrypt/live/your_domain/privkey.pem certbot | Your cert will expire on 2019-08-08. To obtain a new or tweaked certbot | version of this certificate in the future, simply run certbot certbot | again. To non-interactively renew *all* of your certificates, run certbot | "certbot renew" certbot | - Your account credentials have been saved in your Certbot certbot | configuration directory at /etc/letsencrypt. You should make a certbot | secure backup of this folder now. This configuration directory will certbot | also contain certificates and private keys obtained by Certbot so certbot | making regular backups of this folder is ideal. certbot | - If you like Certbot, please consider supporting our work by: certbot | certbot | Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate certbot | Donating to EFF: https://eff.org/donate-le certbot | certbot exited with code 0
Với chứng chỉ đã được thiết lập, bạn có thể chuyển sang chỉnh sửa cấu hình Nginx để thêm SSL.
Bước 5 – Chỉnh sửa cấu hình máy chủ Web và định nghĩa dịch vụ
Việc kích hoạt SSL trong cấu hình Nginx sẽ bao gồm việc thêm chuyển hướng HTTP sang HTTPS, chỉ định vị trí của chứng chỉ SSL và khóa, cũng như thêm các tham số bảo mật và header.
Vì bạn sẽ tạo lại dịch vụ webserver để bao gồm những bổ sung này, bạn có thể dừng dịch vụ hiện tại:
docker-compose stop webserver
Trước khi chỉnh sửa file cấu hình, hãy lấy các tham số bảo mật Nginx được khuyến nghị từ Certbot bằng lệnh curl:
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
Lệnh này sẽ lưu các tham số vào file options-ssl-nginx.conf
, nằm trong thư mục nginx-conf
.
Tiếp theo, hãy xóa file cấu hình Nginx mà bạn đã tạo trước đó:
rm nginx-conf/nginx.conf
Tạo và mở một phiên bản khác của file:
nano nginx-conf/nginx.conf
Thêm đoạn mã sau vào file để chuyển hướng HTTP sang HTTPS và thêm các thông tin SSL (vị trí chứng chỉ, khóa, các tham số và header bảo mật). Nhớ thay your_domain
bằng tên miền của bạn:
~/wordpress/nginx-conf/nginx.conf 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; # enable strict transport security only if you understand the implications 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 máy chủ HTTP (HTTP server block) chỉ định webroot cho các yêu cầu gia hạn của Certbot đến thư mục .well-known/acme-challenge
. Nó cũng bao gồm chỉ thị rewrite để chuyển hướng các yêu cầu HTTP đến HTTPS.
Khối này cũng bao gồm vị trí của chứng chỉ SSL và khóa, cùng với các tham số bảo mật được Certbot khuyến nghị mà bạn đã lưu ở file nginx-conf/options-ssl-nginx.conf
.
Ngoài ra, nó còn bao gồm một số header bảo mật giúp bạn đạt xếp hạng A trên các trang kiểm tra như SSL Labs và Security Headers. Các header này bao gồm: X-Frame-Options, X-Content-Type-Options, Referrer Policy, Content-Security-Policy và X-XSS-Protection. Header HTTP Strict Transport Security (HSTS) được chú thích – chỉ kích hoạt nếu bạn hiểu rõ các tác động và đã đánh giá tính năng “preload” của nó.
Các chỉ thị root
và index
cũng nằm trong khối này, cùng với các khối định vị (location block) dành riêng cho WordPress được đề cập trong Bước 1.
Sau khi hoàn tất chỉnh sửa, lưu lại và đóng file.
Trước khi tạo lại dịch vụ webserver
, bạn cần thêm ánh xạ cổng 443 vào định nghĩa dịch vụ webserver
.
Mở file docker-compose.yml
:
nano docker-compose.yml
Trong định nghĩa dịch vụ webserver
, thêm ánh xạ cổng sau:
... webserver: depends_on: - wordpress image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" - "443:443" volumes: - wordpress:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network
Dưới đây là file docker-compose.yml
đầy đủ sau các chỉnh sửa:
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 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 webserver: depends_on: - wordpress image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" - "443:443" volumes: - wordpress:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network 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 --force-renewal -d your_domain -d www.your_domain volumes: certbot-etc: wordpress: dbdata: networks: app-network: driver: bridge
Lưu và đóng file khi đã hoàn tất chỉnh sửa.
Tạo lại dịch vụ webserver:
docker-compose up -d --force-recreate --no-deps webserver
Kiểm tra các dịch vụ bằng lệnh docker-compose ps
:
docker-compose ps
Đầu ra nên hiển thị rằng các dịch vụ db, wordpress và webserver đang chạy:
Output Name Command State Ports ---------------------------------------------------------------------------------------------- certbot certbot certonly --webroot ... Exit 0 db docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp wordpress docker-entrypoint.sh php-fpm Up 9000/tcp
Với các container đã chạy, bạn có thể hoàn tất cài đặt WordPress thông qua giao diện web.
Bước 6 – Hoàn tất cài đặt qua giao diện Web
Với các container đang chạy, tiến hành hoàn tất cài đặt thông qua giao diện WordPress trên web.
Trong trình duyệt, hãy truy cập vào tên miền máy chủ của bạn. Nhớ thay your_domain
bằng tên miền của riêng bạn:
https://your_domain
Chọn ngôn ngữ mà bạn muốn sử dụng:
Sau khi nhấn Continue, bạn sẽ đến trang cài đặt chính, nơi bạn cần đặt tên cho trang web và đặt tên người dùng. Nên chọn tên người dùng dễ nhớ (không phải “admin”) và mật khẩu mạnh. Bạn có thể sử dụng mật khẩu WordPress tự động tạo hoặc tạo mật khẩu của riêng mình.
Cuối cùng, bạn cần nhập địa chỉ email và quyết định có cho phép công cụ tìm kiếm lập chỉ mục cho trang web của bạn hay không:
Nhấn nút Install WordPress ở cuối trang sẽ đưa bạn đến trang đăng nhập:
Khi đã đăng nhập, bạn sẽ có quyền truy cập vào bảng điều khiển quản trị WordPress:
Với cài đặt WordPress hoàn tất, bạn có thể thực hiện các bước tiếp theo để đảm bảo rằng chứng chỉ SSL của bạn sẽ được gia hạn tự động.
Bước 7 – Gia hạn chứng chỉ
Chứng chỉ Let’s Encrypt có giá trị 90 ngày. Bạn có thể thiết lập một quy trình gia hạn tự động để đảm bảo chúng không hết hạn. Một cách làm là tạo một công việc với tiện ích lập lịch cron. Trong ví dụ sau, bạn sẽ tạo một cron job để chạy định kỳ một script nhằm gia hạn chứng chỉ và tải lại cấu hình Nginx.
Đầu tiên, mở file script có tên ssl_renew.sh
:
nano ssl_renew.sh
Thêm đoạn mã sau vào script để gia hạn chứng chỉ và tải lại cấu hình máy chủ web. Nhớ thay thế tên người dùng không phải root (trong ví dụ là sammy
) bằng tên người dùng của bạn:
#!/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
Script này đầu tiên gán binary của docker-compose cho biến COMPOSE
, với tùy chọn --no-ansi
để chạy lệnh mà không có ký tự điều khiển ANSI. Sau đó, nó làm tương tự với binary của docker. Cuối cùng, nó chuyển đến thư mục dự án ~/wordpress
và chạy các lệnh docker-compose như sau:
-
docker-compose run: Lệnh này sẽ khởi động container certbot và ghi đè lệnh được cung cấp trong định nghĩa dịch vụ certbot. Thay vì sử dụng lệnh
certonly
, tham sốrenew
được sử dụng để gia hạn chứng chỉ sắp hết hạn. Tham số--dry-run
được thêm vào để kiểm tra script. -
docker-compose kill: Lệnh này sẽ gửi tín hiệu SIGHUP đến container webserver để tải lại cấu hình Nginx.
Sau đó, nó chạy lệnh docker system prune
để xóa tất cả các container và image không sử dụng.
Đóng file khi đã hoàn tất chỉnh sửa. Hãy làm cho file này có thể thực thi bằng lệnh sau:
chmod +x ssl_renew.sh
Tiếp theo, mở file crontab của root để chạy script gia hạn theo khoảng thời gian xác định:
sudo crontab -e
Nếu đây là lần đầu tiên bạn chỉnh sửa file này, bạn sẽ được yêu cầu chọn một trình soạn thảo:
Output no crontab for root - using an empty one Select an editor. To change later, run 'select-editor'. 1. /bin/nano <---- easiest 2. /usr/bin/vim.basic 3. /usr/bin/vim.tiny 4. /bin/ed Choose 1-4 [1]: ...
Ở cuối file crontab, thêm dòng sau:
crontab ... */5 * * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
Dòng này sẽ thiết lập cron job chạy mỗi 5 phút, giúp bạn kiểm tra xem yêu cầu gia hạn có hoạt động như mong đợi không. Một file log có tên cron.log
sẽ được tạo để ghi lại các thông tin đầu ra liên quan đến job.
Sau 5 phút, kiểm tra file cron.log
để xác nhận yêu cầu gia hạn đã thành công hay chưa:
tail -f /var/log/cron.log
Đầu ra dưới đây xác nhận việc gia hạn thành công:
Output - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates below have not been saved.) Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/your_domain/fullchain.pem (success) ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates above have not been saved.) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Thoát bằng cách nhấn CTRL+C
trong terminal.
Bạn có thể chỉnh sửa file crontab
để thiết lập chạy hàng ngày. Ví dụ, để chạy script vào lúc 12 giờ trưa hàng ngày, bạn có thể sửa dòng cuối file như sau:
crontab ... 0 12 * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
Bạn cũng nên loại bỏ tham số --dry-run
khỏi script ssl_renew.sh
:
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose --no-ansi" DOCKER="/usr/bin/docker" cd /home/sammy/wordpress/ $COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af
Cron job của bạn sẽ đảm bảo rằng chứng chỉ Let’s Encrypt không bị hết hạn bằng cách gia hạn chúng khi đủ điều kiện. Bạn cũng có thể thiết lập log rotation bằng tiện ích Logrotate trên Ubuntu 22.04 / 20.04 để nén và xoay vòng các file log của bạn.