Site icon Cung cấp dịch vụ Cloud VPS, Server, Hosting Việt Nam & Thế giới

Hướng dẫn Cài đặt WordPress với Docker Compose trên Ubuntu

Hướng dẫn Cài đặt WordPress với Docker Compose trên Ubuntu

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 MySQL và xử lý bằng PHP. Nhờ khả năng mở rộng qua hệ thống plugin và template, WordPress cho phép quản trị viên dễ dàng quản lý nội dung thông qua giao diện web trực quan. Đây chính là lý do WordPress trở thành nền tảng phổ biến để xây dựng nhiều loại trang web, từ blog cá nhân, trang doanh nghiệp đến thương mại điện tử.

Thông thường, để chạy WordPress, bạn cần thiết lập một stack LAMP (Linux, Apache, MySQL, PHP) hoặc LEMP (Linux, Nginx, MySQL, PHP), nhưng việc này có thể mất nhiều thời gian. Nhờ có Docker và Docker Compose, quá trình triển khai WordPress trở nên nhanh chóng và đơn giản hơn. Thay vì cài đặt từng thành phần thủ công, bạn có thể sử dụng các image tiêu chuẩn, giúp đồng nhất thư viện, tệp cấu hình và biến môi trường. Sau đó, các thành phần này sẽ chạy trong container – các tiến trình độc lập nhưng có thể tương tác trên cùng một hệ điều hành. Với Docker Compose, bạn có thể dễ dàng quản lý nhiều container cùng lúc, chẳng hạn như WordPress và cơ sở dữ liệu.

Sau đây DataOnline sẽ hướng dẫn bạn triển khai WordPress trên Docker với Nginx làm máy chủ web và MySQL làm cơ sở dữ liệu. Bên cạnh đó, bạn sẽ bảo mật website bằng chứng chỉ TLS/SSL miễn phí từ Let’s Encrypt, đảm bảo dữ liệu được mã hóa an toàn. Cuối cùng, bạn sẽ thiết lập cron job để tự động gia hạn chứng chỉ, giúp website luôn bảo mật và hoạt động ổn định.

Yêu cầu

Nếu bạn đang sử dụng Ubuntu phiên bản 16.04 hoặc thấp hơn, chúng tôi khuyến nghị bạn nâng cấp lên phiên bản mới hơn vì Ubuntu hiện không còn hỗ trợ các phiên bản này. Bộ sưu tập các hướng dẫn này sẽ giúp bạn nâng cấp phiên bản Ubuntu.

Để làm theo hướng dẫn này, bạn cần có:

Khi đã thiết lập xong tất cả, bạn đã sẵn sàng bắt đầu bước đầu tiên.

Bước 1 – Định nghĩa cấu hình máy chủ Web

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 hướng các yêu cầu xác minh của Let’s Encrypt đến Certbot để gia hạn chứng chỉ tự động.

Tạo thư mục dự án cho cài đặt WordPress. 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

Di chuyển vào thư mục dự án:

cd wordpress

Tạo thư mục cho file cấu hình Nginx:

mkdir nginx-conf

Mở file cấu hình Nginx với nano hoặc trình soạn thảo ưa thích:

nano nginx-conf/nginx.conf

Thêm vào file nội dung khối cấu hình sau (đừng quên 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 các phần chính trong khối cấu hình:

Directives:

listen: Chỉ thị này báo cho Nginx biết cần lắng nghe trên cổng 80, cho phép bạn sử dụng plugin webroot của Certbot cho các 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 để tích hợp SSL sau khi lấy được chứng chỉ thành công.

server_name: Chỉ thị này xác định tên máy chủ của bạn và khối server sẽ được sử dụng để xử lý các yêu cầu gửi đến server. Hãy chắc chắn thay thế your_domain trong dòng này bằng tên miền của riêng bạn.

index: Chỉ thị này định nghĩa các tập tin sẽ được sử dụng làm file chỉ mục khi xử lý các yêu cầu gửi đến server. Bạn đã thay đổi thứ tự ưu tiên mặc định ở đây, đặt index.php lên trước index.html để Nginx ưu tiên sử dụng các tập tin có tên index.php khi có thể.

root: Chỉ thị này đặt tên cho thư mục gốc chứa các yêu cầu gửi đến server của bạn. Thư mục này, /var/www/html, được tạo ra như một điểm mount trong quá trình build theo các chỉ dẫn trong Dockerfile của WordPress. Các chỉ dẫn trong Dockerfile cũng đảm bảo rằng các tập tin từ bản phát hành của WordPress được mount vào volume này.

Location Blocks

location ~ /.well-known/acme-challenge: Khối location này sẽ xử lý các yêu cầu đến thư mục .well-known, nơi Certbot sẽ đặt một file tạm thời để xác minh rằng DNS của tên miền của bạn đã trỏ về server. Với cấu hình này, bạn sẽ có thể sử dụng plugin webroot của Certbot để lấy chứng chỉ cho tên miền của mình.

location /: Trong khối location này, chỉ thị try_files được sử dụng để kiểm tra sự tồn tại của các tập tin phù hợp với từng yêu cầu URI. Thay vì trả về trạng thái 404 Not Found theo mặc định, yêu cầu sẽ được chuyển tiếp sang file index.php của WordPress kèm theo các tham số yêu cầu.

location ~ .php$: Khối location này sẽ xử lý việc xử lý các file PHP và chuyển tiếp các yêu cầu này đến container wordpress của bạn. Vì image WordPress của bạn được xây dựng dựa trên image php: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 trong khối này. Nginx yêu cầu một bộ xử lý PHP độc lập 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ởi bộ xử lý php-fpm đi kèm với image php:fpm. Ngoài ra, khối location này còn bao gồm các chỉ thị, biến và tùy chọn riêng cho FastCGI để chuyển tiếp các yêu cầu đến ứng dụng WordPress đang chạy trong container wordpress, thiết lập file chỉ mục ưu tiên cho URI được phân tích và xử lý các yêu cầu URI.

location ~ /.ht: Khối này sẽ xử lý các file .htaccess vì Nginx không phục vụ chúng. Chỉ thị deny_all đảm bảo rằng các file .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 đến /favicon.ico/robots.txt sẽ không được ghi log.

location ~ .(css|gif|ico|jpeg|jpg|js|png)$:* Khối này tắt việc ghi log cho các yêu cầu đến các tài nguyên tĩnh và đảm bảo rằng các tài nguyên này có thể được cache cao, vì chúng thường có chi phí phục vụ lớn.

Để biết thêm thông tin về việc chuyển tiếp FastCGI, hãy đọc bài “Hiểu biết và triển khai FastCGI Proxying trong Nginx“. Đối với thông tin về các khối server và location, hãy tham khảo “Hiểu về thuật toán lựa chọn Server Và Location Block trong Nginx“.

Lưu và đóng file khi bạn đã hoàn tất chỉnh sửa. Nếu bạn sử dụng nano, hãy nhấn CTRL+X, sau đó nhấn YENTER để lưu các thay đổi.

Với cấu hình Nginx đã được thiết lập, bạn có thể chuyển sang tạo các biến môi trường để truyền cho các container ứng dụng và cơ sở dữ liệu khi chạy.

Bước 2 – Định nghĩa 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 một số biến môi trường khi chạy để dữ liệu của ứng dụng được lưu trữ và có thể truy cập được. Các biến này bao gồm cả thông tin nhạy cảm và không nhạy cảm: những giá trị nhạy cảm cho mật khẩu root của MySQL cũng như tên người dùng và mật khẩu của cơ sở dữ liệu ứng dụng, và những thông tin không nhạy cảm cho tên cơ sở dữ liệu và host.

Thay vì đặt tất cả các giá trị này trực tiếp trong file Docker Compose – file chính chứa thông tin về cách các container của bạn sẽ chạy – hãy đặt các giá trị nhạy cảm vào một file .env và hạn chế việc phân phối nó. Điều này sẽ ngăn các giá trị này bị sao chép vào các repository của dự án và bị lộ ra công khai.

Trong thư mục dự án chính của bạn, ~/wordpress, hãy mở một file có tên .env:

Mở file .env trong thư mục dự án của bạn:

nano .env

Các giá trị nhạy cảm mà bạn thiết lập trong file này bao gồm mật khẩu cho tài khoản root của MySQL, cùng với 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 tên biến và giá trị sau vào file. Hãy nhớ thay thế các giá trị mẫu bằng giá trị thực của bạn cho từng biến:

~/wordpress/.env
MYSQL_ROOT_PASSWORD=your_root_password
MYSQL_USER=your_wordpress_database_user
MYSQL_PASSWORD=your_wordpress_database_password

Bao gồm trong đó là mật khẩu cho tài khoản quản trị root, cũng như tên người dùng và mật khẩu ưa thích của bạn cho cơ sở dữ liệu ứng dụng.

Lưu và đóng file khi bạn đã hoàn tất chỉnh sửa.

Vì file .env của bạn 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 file .gitignore.dockerignore của dự án. Điều này sẽ thông báo cho Git và Docker biết những file nào không nên sao chép vào repository Git và image Docker.

Nếu bạn dự định sử dụng Git để quản lý 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 thành một repository bằng lệnh:

Tạo và mở file .gitignore:

git init

Thêm dòng sau:

nano .gitignore

Lưu và đóng file.

~/wordpress/.gitignore
.env

Thêm dòng sau:

nano .dockerignore

Lưu và đóng file.

~/wordpress/.dockerignore
.env

Phía dưới, bạn có thể tùy chọn thêm các file và thư mục liên quan đến quá trình phát triển của ứng dụng của bạn:

~/wordpress/.dockerignore
.env
.git
docker-compose.yml
.dockerignore

Lưu và đóng file khi bạn đã hoàn tất chỉnh sửa.

Với các thông tin nhạy cảm đã được thiết lập, giờ bạn có thể chuyển sang định nghĩa các dịch vụ của mình trong file docker-compose.yml.

Bước 3 – Định nghĩa các dịch vụ với Docker Compose

File docker-compose.yml của bạn sẽ chứa các định nghĩa dịch vụ cho setup của bạn. Một dịch vụ trong Docker Compose chính là một container đang chạy, và các định nghĩa dịch vụ chỉ định thông tin về cách mỗi container sẽ hoạt động.

Nhờ 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 liên kết các dịch vụ này với nhau qua các mạng và volume chung. Điều này sẽ rất hữu ích cho setup hiện tại của bạn vì bạn sẽ tạo ra 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 để lấy chứng chỉ cho máy chủ web của bạn.

Để bắt đầu, hãy tạo và mở file docker-compose.yml:

nano docker-compose.yml

Thêm vào file nội dung định nghĩa phiên bản Compose và dịch vụ db (cơ sở dữ liệu):

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

Định nghĩa dịch vụ db chứa các tùy chọn sau:

Thêm định nghĩa dịch vụ cho 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

Trong định nghĩa này, bạn đặt tên cho container và làm cho nó phụ thuộc vào container wordpress trong thứ tự khởi động. Bạn cũng đang sử dụng image alpine – cụ thể là image Nginx phiên bản 1.15.12-alpine.

Định nghĩa dịch vụ này cũng bao gồm các tùy chọn sau:

Bạn cũng đã thêm container này vào mạng app-network.

Cuối cùng, bên dưới định nghĩa dịch vụ webserver, hãy thêm định nghĩa dịch vụ cuối cùng cho container certbot. Hãy nhớ thay thế địa chỉ email và tên miền được liệt kê trong cấu hình này bằng thông tin của riêng bạn.

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

Định nghĩa này báo cho Compose kéo image certbot/certbot từ Docker Hub. Nó cũng sử dụng các volume có tên để chia sẻ tài nguyên với container Nginx, bao gồm chứng chỉ và key cho tên miền trong volume certbot-etc cũng như code ứng dụng trong volume wordpress.

Một lần nữa, bạn đã sử dụng depends_on để chỉ định rằng container certbot sẽ được khởi động sau khi dịch vụ webserver đang chạy.

Bạn cũng đã bao gồm tùy chọn command để chỉ định subcommand chạy với lệnh mặc định của certbot. Subcommand certonly sẽ lấy chứng chỉ với các tùy chọn sau:

Cuối cùng, bên dưới định nghĩa dịch vụ webserver, hãy thêm định nghĩa dịch vụ cuối cùng cho container certbot. Hãy nhớ thay thế địa chỉ email và tên miền được liệt kê trong cấu hình này bằng thông tin của riêng bạn.

...
volumes:
  certbot-etc:
  wordpress:
  dbdata:

networks:
  app-network:
    driver: bridge

Khóa volumes cấp trên định nghĩa các volume certbot-etc, wordpress, và dbdata. Khi Docker tạo các volume, nội dung của volume được lưu trữ trong một thư mục trên hệ thống file của host, /var/lib/docker/volumes/, được Docker quản lý. Nội dung của mỗi volume sau đó sẽ được mount từ thư mục này vào bất kỳ container nào sử dụng volume đó. Nhờ vậy, có thể chia sẻ code và dữ liệu giữa các container.

Mạng cầu nối do người dùng định nghĩa app-network cho phép các container giao tiếp với nhau vì chúng cùng chạy trên một Docker daemon host. Điều này giúp tối ưu hóa lưu lượng và giao tiếp trong ứng dụng, khi mở tất cả các cổng giữa các container trên cùng một mạng cầu nối mà không cần mở cổng ra bên ngoài. Do đó, các container db, wordpress, và webserver của bạn có thể giao tiếp với nhau, và bạn chỉ cần mở cổng 80 cho truy cập giao diện người dùng.

Dưới đây là file docker-compose.yml đầy đủ:

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 file khi bạn đã hoàn tất chỉnh sửa.

Với các định nghĩa dịch vụ đã được thiết lập, bạn đã sẵn sàng khởi động các container và kiểm tra các yêu cầu chứng chỉ của bạn.

Bước 4 – Lấy chứng chỉ SSL và thông tin đăng nhập

Khởi động các container với lệnh docker-compose up:

Chạy lệnh docker-compose up để tạo và chạy các container theo thứ tự đã được định nghĩa. Khi thêm tùy chọn -d, lệnh này sẽ chạy các container db, wordpress, và webserver ở chế độ nền:

docker-compose up -d

Khi quá trình hoàn tất, bạn sẽ thấy thông báo xác nhận rằng các dịch vụ đã được tạo:

Output
Creating db ... done
Creating wordpress ... done
Creating webserver ... done
Creating certbot   ... done

Sử dụng lệnh sau để kiểm tra trạng thái của các container:

docker-compose ps

Nếu quá trình hoàn tất thành công, các dịch vụ db, wordpress, và webserver sẽ có trạng thái Up, trong khi container certbot sẽ thoát với mã 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

Nếu bất kỳ dịch vụ nào có trạng thái khác Up, hoặc container certbot có mã thoát khác 0, bạn cần kiểm tra nhật ký dịch vụ bằng lệnh sau:

docker-compose logs service_name

Xác nhận rằng chứng chỉ SSL đã được gắn vào container webserver bằng lệnh:

docker-compose exec webserver ls -la /etc/letsencrypt/live

Nếu yêu cầu chứng chỉ thành công, bạn sẽ nhận được kết quả 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

Loại bỏ --staging và yêu cầu chứng chỉ SSL thực

Sau khi xác nhận rằng yêu cầu chứng chỉ sẽ thành công, bạn cần chỉnh sửa cấu hình certbot để loại bỏ cờ --staging. Mở tệp docker-compose.yml:

nano docker-compose.yml

Tìm phần định nghĩa dịch vụ certbot và thay thế --staging bằng --force-renewal để yêu cầu chứng chỉ mới:

Sau đó, chạy lệnh sau để tạo lại container certbot, sử dụng –no-deps để tránh khởi động lại container webserver:

docker-compose up --force-recreate --no-deps certbot

Nếu quá trình cấp chứng chỉ thành công, bạn sẽ thấy thông báo sau:

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

Cấu hình Nginx để sử dụng SSL

Sau khi chứng chỉ đã được cấp, bạn có thể tiến hành chỉnh sửa cấu hình Nginx để kích hoạt SSL trên website của mình.

Bước 5 – Chỉnh sửa cấu hình máy chủ Web và định nghĩa dịch vụ

Để kích hoạt SSL trong cấu hình Nginx, bạn cần thêm phần chuyển hướng HTTP sang HTTPS, chỉ định vị trí chứng chỉ và key, cũng như thêm các tham số bảo mật và header. Vì bạn sẽ tái tạo lại dịch vụ webserver để bao gồm các thay đổi này, hãy tạm dừng container webserver:

docker-compose stop webserver

Tải 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 trong thư mục nginx-conf.

Xóa file cấu hình Nginx cũ:

rm nginx-conf/nginx.conf

Tạo và mở file cấu hình Nginx mới:

nano nginx-conf/nginx.conf

Thêm đoạn mã sau vào file (đừng quên 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;

        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 server HTTP xác định webroot cho các yêu cầu gia hạn chứng chỉ của Certbot đến thư mục .well-known/acme-challenge. Nó cũng bao gồm một chỉ thị rewrite để chuyển hướng tất cả các yêu cầu HTTP đến thư mục gốc sang HTTPS.

Khối server HTTPS kích hoạt SSLHTTP/2. Để tìm hiểu thêm về cách HTTP/2 cải tiến so với các giao thức HTTP trước đây và lợi ích của nó đối với hiệu suất website, hãy đọc bài giới thiệu Cách thiết lập Nginx hỗ trợ HTTP/2 trên Ubuntu 18.04.

Khối này cũng bao gồm đường dẫn đến chứng chỉ SSL và key, cùng với các tham số bảo mật được Certbot đề xuất mà bạn đã lưu trong nginx-conf/options-ssl-nginx.conf.

Ngoài ra, cấu hình này 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 công cụ kiểm tra bảo mật 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, X-XSS-Protection

Header HTTSTS) P Strict Transport Security (Hiện đang được ghi chú (commented out). Bạn chỉ nên kích hoạt nó nếu hiểu rõ tác động và đã đánh giá chức năng preload của nó.

Chỉ thị rootindex cũng nằm trong khối này, cùng với các khối location dành riêng cho WordPress đã được thảo luận ở Bước 1.

Sau khi hoàn tất chỉnh sửa, lưu và đóng file.

Trước khi khởi 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, hãy thêm ánh xạ cổng sau vào phần ports:

...
  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 hoàn chỉnh sau khi 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

Sau khi chỉnh sửa xong, lưu và đóng file. Tiếp theo, bạn có thể khởi động lại dịch vụ webserver để áp dụng cấu hình SSL mới.

Tạo lại dịch vụ webserver:

docker-compose up -d --force-recreate --no-deps webserver

Kiểm tra trạng thái các dịch vụ:

docker-compose ps

Output đầu ra nên hiển thị rằng các dịch vụ db, wordpress, và webserver đang chạy đúng cách:

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

Khi các container của bạn đã chạy ổn định, bạn có thể hoàn tất quá trình 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 đã chạy, hãy mở trình duyệt và truy cập tên miền của server (thay your_domain bằng tên miền của bạn):

https://your_domain

Chọn ngôn ngữ bạn muốn sử dụng:

Sau khi nhấn Tiếp tục, bạn sẽ được chuyển đến trang thiết lập chính, nơi bạn cần đặt tên cho trang web của mình và tạo một tên người dùng.

Nên chọn một tên người dùng dễ nhớ (tránh sử dụng “admin”) và một mật khẩu mạnh. Bạn có thể sử dụng mật khẩu do WordPress tạo tự động hoặc nhập mật khẩu của riêng bạn.

Cuối cùng, hãy nhập địa chỉ email của bạn và quyết định xem có muốn chặn công cụ tìm kiếm lập chỉ mục trang web hay không (tùy chọn này hữu ích nếu bạn chưa muốn trang web hiển thị trên Google và các công cụ tìm kiếm khác).

Nhấp vào Cài đặt WordPress ở cuối trang sẽ đưa bạn đến màn hình đăng nhập:

Sau 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.

Sau khi hoàn tất cài đặt WordPress, bạn có thể thực hiện các bước để đảm bảo rằng chứng chỉ SSL sẽ được gia hạn tự động

Bước 7 – Gia hạn chứng chỉ

Chứng chỉ Let’s Encrypt có thời hạn 90 ngày. Để đảm bảo chúng không bị hết hạn, bạn có thể thiết lập một quy trình tự động gia hạn bằng cách sử dụng cron job. Trong hướng dẫn này, bạn sẽ tạo một cron job để chạy định kỳ một script, giúp gia hạn chứng chỉ và tải lại cấu hình Nginx.

Trước tiên, mở một file script có tên ssl_renew.sh bằng lệnh sau:

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. Hãy nhớ thay thế tên người dùng mẫu bằng tên người dùng không phải root 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 trước tiên gán đường dẫn đến docker-compose vào một biến có tên COMPOSE, đồng thời chỉ định tùy chọn --no-ansi để chạy các lệnh docker-compose mà không có ký tự điều khiển ANSI. Sau đó, nó cũng làm tương tự với docker bằng cách gán đường dẫn vào biến DOCKER.

Cuối cùng, script sẽ chuyển đến thư mục dự án ~/wordpress và chạy các lệnh docker-compose sau:

Sau khi chỉnh sửa xong, lưu và đóng file.

Tiếp theo, cấp quyền thực thi cho script bằng lệnh sau:

chmod +x ssl_renew.sh

Tiếp theo, mở file crontab của root để thiết lập lịch chạy script gia hạn chứng chỉ theo khoảng thời gian định sẵn:

sudo crontab -e

Nếu đây là lần đầu tiên bạn chỉnh sửa file này, hệ thống sẽ yêu cầu bạn 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, thêm dòng sau:

crontab
...
*/5 * * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1

Dòng lệnh này sẽ đặt khoảng thời gian chạy script mỗi 5 phút, giúp bạn kiểm tra xem yêu cầu gia hạn chứng chỉ có hoạt động đúng không. Một file log cron.log sẽ được tạo để ghi lại các thông tin liên quan từ quá trình thực thi.

Sau 5 phút, kiểm tra log bằng lệnh sau để xác nhận xem yêu cầu gia hạn có thành công không:

tail -f /var/log/cron.log

Output sau xác nhận rằng quá trình gia hạn chứng chỉ đã 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.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Nhấn CTRL+C trong terminal để thoát khỏi chế độ xem log.

Bạn có thể chỉnh sửa file crontab để đặt lịch chạy script hàng ngày. Ví dụ, để chạy script mỗi ngày vào lúc 12:00 trưa, hãy thay dòng cuối của file bằng:

crontab
...
0 12 * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1

Bạn cũng cần xóa tùy chọn --dry-run khỏi script ssl_renew.sh để quá trình gia hạn chứng chỉ diễn ra thực sự.

#!/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 tự động gia hạn khi đủ điều kiện.

Bạn cũng có thể thiết lập log rotation bằng công cụ Logrotate trên Ubuntu 22.04 / 20.04 để xoay vòng và nén file log, giúp tránh việc log chiếm quá nhiều dung lượng ổ đĩa.

Kết luận

Trong hướng dẫn này, bạn đã triển khai WordPress bằng Docker Compose, sử dụng Nginx làm máy chủ web. Trong quá trình này, bạn cũng đã cấu hình chứng chỉ TLS/SSL cho tên miền của trang WordPress bằng Let’s Encrypt, giúp bảo mật kết nối. Ngoài ra, để đảm bảo chứng chỉ luôn hợp lệ, bạn đã thiết lập cron job để tự động gia hạn khi cần thiết, giúp website duy trì tính bảo mật và hoạt động ổn định.

Để cải thiện hiệu suất và độ tin cậy của trang web, bạn có thể tham khảo thêm bài viết Cách Cài Đặt WordPress với MySQL trên Kubernetes Sử Dụng Helm.

Exit mobile version