Hướng Dẫn Cài Đặt WordPress Với Docker Compose Chi Tiết Nhất 2025

Cài Đặt WordPress Với Docker Compose

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 MySQLPHP. 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 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. 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ởi php-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/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.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 image mysql:8.0 để tránh xung đột phiên bản khi image mysql: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ến MYSQL_DATABASE bằng wordpress để đặ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ệp docker-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ệnh mysqld để bắt đầu MySQL trên container, thiết lập tham số --default-authentication-plugin thành mysql_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ạng app-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 container wordpress khởi động sau container db vì ứng dụng WordPress phụ thuộc vào cơ sở dữ liệu.
  • image: Sử dụng image WordPress 5.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 WORDPRESS_DB_PASSWORD. Đồng thời, định nghĩa WORDPRESS_DB_HOST là máy chủ MySQL đang chạy trên container db ở 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ạng app-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 container webserver khởi động sau container wordpress.
  • image: Sử dụng image Nginx 1.15.12-alpine.
  • ports: Mở cổng 80 để kích hoạt các tùy chọn cấu hình trong tệp nginx.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ạng app-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 container webserver.
  • 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 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 volume certbot-etc, wordpressdbdata. 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 container db, 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, wordpresswebserver ở 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, wordpresswebserver 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-PolicyX-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ị rootindex 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, wordpresswebserver đ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:

tu dien cong dong dataonline 1

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:

tu dien cong dong dataonline 2

Nhấn nút Install WordPress ở cuối trang sẽ đưa bạn đến trang đăng nhập:

Thiet ke chua co ten 5 1

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:

Thiet ke chua co ten 6 1

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.

Kết luận

Trong hướng dẫn này, bạn đã sử dụng Docker Compose để triển khai một môi trường WordPress hoàn chỉnh, bao gồm máy chủ web Nginx và cơ sở dữ liệu MySQL. Bạn cũng đã thiết lập bảo mật cho trang web bằng cách lấy chứng chỉ TLS/SSL từ Let’s Encrypt và liên kết nó với tên miền mong muốn. Để đảm bảo tính liên tục và an toàn, bạn đã cấu hình một cron job tự động gia hạn chứng chỉ, giúp duy trì bảo mật mà không cần can thiệp thủ công. Với những kiến thức đã học, bạn có thể tiếp tục mở rộng và tùy chỉnh môi trường WordPress của mình để đáp ứng các nhu cầu cụ thể.

Để triển khai WordPress với Docker Compose hiệu quả, việc thuê VPS giá rẻ là lựa chọn thông minh. VPS giá rẻ cung cấp tài nguyên mạnh mẽ, hỗ trợ cài đặt nhanh chóng, giúp tiết kiệm chi phí mà vẫn đảm bảo website vận hành ổn định. Tìm hiểu gói VPS phù hợp ngay!

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *