如何使用 Docker Compose 安装 WordPress

简介
WordPress 是一个免费、开源的内容管理系统(CMS),它基于 MySQL 数据库和 PHP 处理。得益于其可扩展的插件架构和模板系统,大部分管理都可以通过网络界面完成。这也是 WordPress 成为创建从博客、产品页面到电子商务网站等不同类型网站的热门选择的原因。
运行 WordPress 通常需要安装 LAMP(Linux、Apache、MySQL 和 PHP)或 LEMP(Linux、Nginx、MySQL 和 PHP)堆栈,这可能会很耗时。不过,通过使用 Docker 和 Docker Compose 等工具,您可以简化设置首选堆栈和安装 WordPress 的过程。您可以使用 镜像,将库、配置文件和环境变量等标准化,而无需手动安装各个组件。然后,在容器中运行这些镜像,这些容器是在共享操作系统上运行的隔离进程。此外,通过使用 Compose,您可以协调多个容器(例如,应用程序和数据库)相互通信。
在本教程中,您将构建一个多容器 WordPress 安装。您的容器将包括 MySQL 数据库、Nginx Web 服务器和 WordPress 本身。您还将使用 Let’s Encrypt 为您希望与网站相关联的域获取 TLS/SSL 证书,从而确保安装的安全性。最后,您将设置一个 cron 作业来更新证书,以确保您的域名安全。
准备
- 一台云服务器
如果没有,可以前往 雨云- 新一代云服务提供商 进行注册,新用户有五折优惠。
全产品线路优化:
- 香港CN2三网直连,延迟低至35ms;
- 美国(CMI+9929),延迟低至140ms;
- 日本东京三网直连,延迟低至60ms;
更有国内:浙江宁波、广东深圳、广东广州、湖北襄阳、江苏宿迁、重庆电信 地区服务器,价格平民,质量优质,CPU强劲。

拥有:云应用、云服务器、游戏云、显卡云、对象存储、裸金属物理机、域名服务、SSL证书、虚拟主机、雨盾CDN 产品!

新用户更有五折券优惠,支持一元试用!点击进行注册
前提条件
要学习本教程,您需要:
- 一台运行 Ubuntu 的服务器、一个具有
sudo权限的非 root 用户和一个活动防火墙。 - 按照教程的步骤 1 和 2,在服务器上安装 Docker。
- 按照教程的步骤 1,在服务器上安装 Docker Compose。
- 一个注册好的域名。本教程将始终使用 your_domain 作为示例。
- 为您的服务器设置以下两个 DNS 记录:
- 一个指向服务器公共 IP 地址的 A 记录 (
your_domain)。 - 一个
www.your_domain指向服务器公共 IP 地址的 A 记录。
- 一个指向服务器公共 IP 地址的 A 记录 (
一切准备就绪后,就可以开始第一步了。
步骤 1 — 定义 Web 服务器配置
在运行任何容器之前,第一步是定义 Nginx Web 服务器的配置。配置文件将包括一些 WordPress 特定的位置块,以及一个将 Let’s Encrypt 验证请求导向 Certbot 客户端的位置块,以便自动更新证书。
首先,为 WordPress 设置创建一个项目目录。在本例中,该目录名为 wordpress。如果你愿意,也可以给这个目录起不同的名字:
mkdir wordpress
然后导航到该目录:
cd wordpress
接下来,为配置文件创建一个目录:
mkdir nginx-conf
用 nano 或你喜欢的编辑器打开一个名为 nginx.conf 的文件:
nano nginx-conf/nginx.conf
在该文件中,添加一个服务器块,其中包含服务器名称和文档根目录指令,以及用于引导 Certbot 客户端请求证书、PHP 处理和静态资产请求的位置块。
在文件中添加以下代码。请务必将 your_domain 替换为您自己的域名:
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;}
}
我们的服务器块包括以下信息:
指令:
listen:告诉 Nginx 监听端口80,这将允许你使用 Certbot 的 webroot 插件来处理证书请求。请注意,尚未包含端口443- 一旦成功获得证书,您将更新配置以包含 SSL。server_name:此处定义了您的服务器名称以及向服务器发出请求时应使用的服务器块。请务必将此行中的your_domain替换为您自己的域名。index:该指令定义了在处理对服务器的请求时用作索引的文件。在此修改默认的优先级顺序,将index.php移到index.html前面,这样 Nginx 就会尽可能优先处理名为index.php的文件。root:该指令命名向服务器请求的 root 目录。该目录(/var/www/html)将在构建时根据 WordPress Dockerfile 中的说明创建为挂载点。这些 Dockerfile 指令还可确保 WordPress 发行版中的文件挂载到该卷中。
位置块 (Location Blocks):
location ~ /.well-known/acme-challenge:该位置块将处理对.well-known目录的请求,Certbot 将在该目录中放置一个临时文件,以验证域名的 DNS 是否解析到了您的服务器。配置完成后,您就可以使用 Certbot 的 webroot 插件为您的域名获取证书。location /:在该位置块中,使用try_files指令检查是否有文件与个别 URI 请求相匹配。不过,您将通过请求参数把控制权传递给 WordPress 的index.php文件,而不是默认返回 404 Not Found 状态。location ~ \\.php$:该位置块将处理 PHP 请求,并将这些请求代理到您的wordpress容器。由于您的 WordPress Docker 镜像将基于php:fpm镜像,您还将在此块中包含特定于 FastCGI 协议的配置选项。Nginx 需要一个独立的 PHP 处理器来处理 PHP 请求。在这种情况下,这些请求将由php-fpm处理器处理,该处理器包含在php:fpm镜像中。此外,该位置块还包含特定于 FastCGI 的指令、变量和选项,这些指令、变量和选项将把请求代理到运行在wordpress容器中的 WordPress 应用程序,为解析后的请求 URI 设置首选索引,并解析 URI 请求。location ~ /\\.ht:该代码块将处理.htaccess文件,因为 Nginx 不会处理这些文件。deny all指令确保.htaccess文件永远不会提供给用户。location = /favicon.ico,location = /robots.txt: 这些块确保对/favicon.ico和/robots.txt的请求不会被记录。location ~* \\.(css|gif|ico|jpeg|jpg|js|png)$:该代码块关闭了静态资产请求的日志记录,并确保这些资产是高度可缓存的,因为它们的服务成本通常很高。
完成编辑后,保存并关闭文件。如果使用 nano,请按 CTRL+X、Y,然后按 ENTER。
完成 Nginx 配置后,就可以继续创建环境变量,以便在运行时传递给应用程序和数据库容器。
步骤 2 — 定义环境变量
您的数据库和 WordPress 应用程序容器需要在运行时访问特定的环境变量,以便应用程序数据能够持久化并被应用程序访问。这些变量包括敏感和非敏感信息:MySQL root 密码和应用程序数据库用户及密码的敏感值,以及应用程序数据库名称和主机的非敏感信息。
与其在 Docker Compose 文件(包含容器运行信息的主文件)中设置所有这些值,不如在 .env 文件中设置敏感值,并限制其流通。这将防止这些值复制到项目存储库并公开暴露。
在您的主项目目录 ~/wordpress 中,打开一个名为 .env 的文件:
nano .env
您在此文件中设置的机密值包括 MySQL root 用户的密码,以及 WordPress 用于访问数据库的用户名和密码。
将以下变量名称和值添加到文件中。请记住为每个变量提供您自己的值:
MYSQL_ROOT_PASSWORD=your_root_password
MYSQL_USER=your_wordpress_database_user
MYSQL_PASSWORD=your_wordpress_database_password
这里包括了 root 管理员账户的密码,以及您为应用程序数据库设定的首选用户名和密码。
完成编辑后保存并关闭文件。
因为您的 .env 文件包含敏感信息,所以您需要确保它被包含在项目的 .gitignore 和 .dockerignore 文件中。这分别告诉 Git 和 Docker 哪些文件不应复制到您的 Git 仓库和 Docker 镜像中。
如果您计划使用 Git 进行版本控制,请使用 git init 将当前工作目录初始化为仓库:
git init
然后创建并打开一个 .gitignore 文件:
nano .gitignore
将 .env 添加到文件中:
.env
完成编辑后保存并关闭文件。
同样,将 .env 添加到 .dockerignore 文件中也是一个很好的预防措施,这样当您使用此目录作为构建上下文时,它就不会最终出现在您的容器上。
打开文件:
nano .dockerignore
将 .env 添加到文件中:
.env
在此之下,您可以选择性地添加与应用程序开发相关的其他文件和目录:
.env
.git
docker-compose.yml
.dockerignore
完成后保存并关闭文件。
敏感信息配置好后,您现在可以继续在 docker-compose.yml 文件中定义您的服务了。
步骤 3 — 使用 Docker Compose 定义服务
您的 docker-compose.yml 文件将包含您设置的服务定义。在 Compose 中,服务是一个正在运行的容器,而服务定义则指定了每个容器将如何运行的信息。
使用 Compose,您可以定义不同的服务来运行多容器应用程序,因为 Compose 允许您通过共享网络和卷将这些服务链接在一起。这对您当前的设置很有帮助,因为您将为数据库、WordPress 应用程序和 Web 服务器创建不同的容器。您还将创建一个容器来运行 Certbot 客户端以获取 Web 服务器的证书。
首先,创建并打开 docker-compose.yml 文件:
nano docker-compose.yml
添加以下代码来定义您的 Compose 文件版本和 db 数据库服务:
version: '3'services:db:image: mysql:8.0container_name: dbrestart: unless-stoppedenv_file: .envenvironment:- MYSQL_DATABASE=wordpressvolumes:- dbdata:/var/lib/mysqlcommand: '--default-authentication-plugin=mysql_native_password'networks:- app-network
db 服务定义包含以下选项:
image: 这告诉 Compose 应该拉取哪个镜像来创建容器。您在这里固定了mysql:8.0镜像,以避免未来mysql:latest镜像更新时可能出现的冲突。container_name: 为容器指定一个名称。restart: 定义容器的重启策略。默认为no,但您已将其设置为除非手动停止,否则容器将重新启动。env_file: 此选项告诉 Compose 您希望从位于构建上下文中的名为.env的文件中添加环境变量。在这种情况下,构建上下文是您的当前目录。environment: 此选项允许您在.env文件中定义的环境变量之外添加其他环境变量。您将MYSQL_DATABASE变量设置为wordpress,为您的应用程序数据库提供一个名称。因为这是非敏感信息,所以您可以直接在docker-compose.yml文件中包含它。volumes: 在这里,您将一个名为dbdata的命名卷挂载到容器上的/var/lib/mysql目录。这是大多数发行版中 MySQL 的标准数据目录。command: 此选项指定一个命令来覆盖镜像的默认CMD指令。在这种特殊情况下,您将向 Docker 镜像的标准mysqld命令添加一个选项,该命令在容器上启动 MySQL 服务器。这个选项-default-authentication-plugin=mysql_native_password将-default-authentication-plugin系统变量设置为mysql_native_password,指定了应该管理对服务器的新认证请求的认证机制。由于 PHP 以及您的 WordPress 镜像不支持 MySQL 新的认证默认设置,您必须进行此调整才能验证您的应用程序数据库用户。networks: 指定您的应用程序服务将加入app-network网络,您将在文件底部定义该网络。
接下来,在您的 db 服务定义下方,添加您的 wordpress 应用程序服务的定义:
...wordpress:depends_on:- dbimage: wordpress:latest-fpm-alpinecontainer_name: wordpressrestart: unless-stoppedenv_file: .envenvironment:- WORDPRESS_DB_HOST=db:3306- WORDPRESS_DB_USER=$MYSQL_USER- WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD- WORDPRESS_DB_NAME=wordpressvolumes:- wordpress:/var/www/htmlnetworks:- app-network
在这个服务定义中,您像对 db 服务一样命名您的容器并定义了重启策略。您还添加了一些特定于此容器的选项:
depends_on: 此选项确保您的容器将按依赖顺序启动,wordpress容器将在db容器之后启动。您的 WordPress 应用程序依赖于您的应用程序数据库和用户的存在,因此表达这种依赖顺序将使您的应用程序能够正确启动。image: 对于此设置,您使用的是wordpress:latest-fpm-alpine镜像。如步骤1中所述,使用此镜像可确保您的应用程序具有 Nginx 需要处理 PHP 的php-fpm处理器。这也是一个alpine镜像,源自 Alpine Linux 项目,这将有助于减小您的整体镜像大小。env_file: 同样,您指定希望从.env文件中提取值,因为这是您定义应用程序数据库用户和密码的地方。environment: 在这里,您正在使用您在.env文件中定义的值,但将它们分配给 WordPress 镜像期望的变量名:WORDPRESS_DB_USER和WORDPRESS_DB_PASSWORD。您还定义了一个WORDPRESS_DB_HOST,它将是在db容器上运行的 MySQL 服务器,可通过 MySQL 的默认端口3306访问。您的WORDPRESS_DB_NAME将与您在 MySQL 服务定义中为MYSQL_DATABASE指定的值相同:wordpress。volumes: 您将一个名为wordpress的命名卷挂载到由 WordPress 镜像创建的/var/www/html挂载点。以这种方式使用命名卷将允许您与其他容器共享您的应用程序代码。networks: 您还正在将wordpress容器添加到app-network网络中。
接下来,在 wordpress 应用程序服务定义下方,添加您的 webserver Nginx 服务的以下定义:
...webserver:depends_on:- wordpressimage: nginx:latest-alpinecontainer_name: webserverrestart: unless-stoppedports:- "80:80"volumes:- wordpress:/var/www/html- ./nginx-conf:/etc/nginx/conf.d- certbot-etc:/etc/letsencryptnetworks:- app-network
在这里,您正在命名您的容器,并使其在启动顺序上依赖于 wordpress 容器。您还使用了 alpine 镜像 — nginx:latest-alpine 镜像。
此服务定义还包括以下选项:
ports: 这会暴露端口80,以启用您在步骤1的nginx.conf文件中定义的配置选项。volumes: 在这里,您定义了命名卷和绑定挂载的组合:wordpress:/var/www/html: 这将把您的 WordPress 应用程序代码挂载到/var/www/html目录,即您在 Nginx 服务器块中设置为root的目录。./nginx-conf:/etc/nginx/conf.d: 这将把主机上的 Nginx 配置目录绑定挂载到容器上的相关目录,确保您对主机上文件所做的任何更改都将反映在容器中。certbot-etc:/etc/letsencrypt: 这会将您域名的相关 Let’s Encrypt 证书和密钥挂载到容器上的适当目录。
您还已将此容器添加到 app-network 网络中。
最后,在您的 webserver 定义下方,添加您的 certbot 服务的最后一个服务定义。请务必将此处列出的电子邮件地址和域名替换为您自己的信息:
...certbot:depends_on:- webserverimage: certbot/certbotcontainer_name: certbotvolumes:- certbot-etc:/etc/letsencrypt- wordpress:/var/www/htmlcommand: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain
此定义告诉 Compose 从 Docker Hub 拉取 certbot/certbot 镜像。它还使用命名卷与 Nginx 容器共享资源,包括 certbot-etc 中的域名证书和密钥以及 wordpress 中的应用程序代码。
同样,您已使用 depends_on 来指定 certbot 容器应在 webserver 服务运行后启动。
您还包括了一个 command 选项,该选项指定了与容器默认 certbot 命令一起运行的子命令。certonly 子命令将使用以下选项获取证书:
-webroot: 这告诉 Certbot 使用 webroot 插件在 webroot 文件夹中放置文件进行身份验证。此插件依赖于 HTTP-01 验证方法,该方法使用 HTTP 请求来证明 Certbot 可以从响应给定域名的服务器访问资源。-webroot-path: 这指定了 webroot 目录的路径。-email: 您首选的注册和恢复电子邮件。-agree-tos: 这指定您同意 ACME 的订户协议。-no-eff-email: 这告诉 Certbot 您不希望与电子前沿基金会(EFF)共享您的电子邮件。如果您愿意,可以省略此项。-staging: 这告诉 Certbot 您想使用 Let’s Encrypt 的暂存环境来获取测试证书。使用此选项可以让您测试配置选项并避免可能的域名请求限制。有关这些限制的更多信息,请阅读 Let’s Encrypt 的速率限制文档。d: 这允许您指定要应用于请求的域名。在这种情况下,您已包括your_domain和www.your_domain。请务必用您自己的域名替换这些。
在 certbot 服务定义下方,添加您的网络和卷定义:
...
volumes:certbot-etc:wordpress:dbdata:networks:app-network:driver: bridge
您的顶层 volumes 键定义了 certbot-etc、wordpress 和 dbdata 卷。当 Docker 创建卷时,卷的内容存储在主机文件系统的一个由 Docker 管理的目录中,即 /var/lib/docker/volumes/。然后,每个卷的内容从该目录挂载到使用该卷的任何容器。通过这种方式,可以在容器之间共享代码和数据。
用户定义的桥接网络 app-network 使得您的容器之间能够通信,因为它们位于同一个 Docker 守护进程主机上。这简化了应用程序内部的流量和通信,因为它在同一桥接网络上的容器之间打开了所有端口,而无需向外界暴露任何端口。因此,您的 db、wordpress 和 webserver 容器可以相互通信,而您只需为应用程序的前端访问暴露端口 80。
以下是完整的 docker-compose.yml 文件:
version: '3'services:db:image: mysql:8.0container_name: dbrestart: unless-stoppedenv_file: .envenvironment:- MYSQL_DATABASE=wordpressvolumes:- dbdata:/var/lib/mysqlcommand: '--default-authentication-plugin=mysql_native_password'networks:- app-networkwordpress:depends_on:- dbimage: wordpress:latest-fpm-alpinecontainer_name: wordpressrestart: unless-stoppedenv_file: .envenvironment:- WORDPRESS_DB_HOST=db:3306- WORDPRESS_DB_USER=$MYSQL_USER- WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD- WORDPRESS_DB_NAME=wordpressvolumes:- wordpress:/var/www/htmlnetworks:- app-networkwebserver:depends_on:- wordpressimage: nginx:latest-alpinecontainer_name: webserverrestart: unless-stoppedports:- "80:80"volumes:- wordpress:/var/www/html- ./nginx-conf:/etc/nginx/conf.d- certbot-etc:/etc/letsencryptnetworks:- app-networkcertbot:depends_on:- webserverimage: certbot/certbotcontainer_name: certbotvolumes:- certbot-etc:/etc/letsencrypt- wordpress:/var/www/htmlcommand: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domainvolumes:certbot-etc:wordpress:dbdata:networks:app-network:driver: bridge
完成编辑后保存并关闭文件。
服务定义就绪后,您就可以启动容器并测试您的证书请求了。
步骤 4 — 获取 SSL 证书
使用 docker-compose up 命令启动您的容器,这将按照您指定的顺序创建并运行您的容器。通过添加 -d 标志,该命令将在后台运行 db、wordpress 和 webserver 容器:
docker-compose up -d
以下输出确认您的服务已创建:
Output
Creating db ... done
Creating wordpress ... done
Creating webserver ... done
Creating certbot ... done
使用 docker-compose ps 检查您的服务状态:
docker-compose ps
完成后,您的 db、wordpress 和 webserver 服务的状态将为 Up,而 certbot 容器将以 0 状态消息退出:
OutputName 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
如果 db、wordpress 或 webserver 服务的 State 列中不是 Up,或者 certbot 容器的退出状态不是 0,则您可能需要使用 docker-compose logs 命令检查服务日志:
docker-compose logs service_name
您现在可以使用 docker-compose exec 检查您的证书是否已挂载到 webserver 容器中:
docker-compose exec webserver ls -la /etc/letsencrypt/live
一旦您的证书请求成功,输出如下:
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
既然您知道您的请求将会成功,您可以编辑 certbot 服务定义以移除 --staging 标志。
打开 docker-compose.yml:
nano docker-compose.yml
找到文件中 certbot 服务定义的部分,并将 command 选项中的 --staging 标志替换为 --force-renewal 标志,这将告诉 Certbot 您希望用与现有证书相同的域名请求一个新证书。以下是带有更新标志的 certbot 服务定义:
...certbot:depends_on:- webserverimage: certbot/certbotcontainer_name: certbotvolumes:- certbot-etc:/etc/letsencrypt- wordpress:/var/www/htmlcommand: 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
...
您现在可以运行 docker-compose up 来重新创建 certbot 容器。您还将包括 --no-deps 选项,以告诉 Compose 它可以跳过启动 webserver 服务,因为它已经在运行:
docker-compose up --force-recreate --no-deps certbot
以下输出表明您的证书请求已成功:
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
证书就位后,就可以继续修改 Nginx 配置,将 SSL 包括在内。
步骤 5 — 修改 Web 服务器配置和服务定义
在 Nginx 配置中启用 SSL 需要添加 HTTP 重定向到 HTTPS,指定 SSL 证书和密钥位置,以及添加安全参数和标头。
由于您将重新创建 webserver 服务以添加这些内容,因此现在可以停止该服务:
docker-compose stop webserver
在修改配置文件之前,使用 curl 从 Certbot 获取推荐的 Nginx 安全参数:
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>
该命令将把这些参数保存在 nginx-conf 目录下名为 options-ssl-nginx.conf 的文件中。
接下来,删除之前创建的 Nginx 配置文件:
rm nginx-conf/nginx.conf
创建并打开另一个版本的文件:
nano nginx-conf/nginx.conf
在文件中添加以下代码,将 HTTP 重定向到 HTTPS,并添加 SSL 凭据、协议和安全标头。记住将 your_domain 替换为您自己的域名:
server {listen 80;listen [::]:80;server_name your_domain www.your_domain;location ~ /.well-known/acme-challenge {allow all;root /var/www/html;}location / {rewrite ^ https://$host$request_uri? permanent;}
}server {listen 443 ssl http2;listen [::]:443 ssl http2;server_name your_domain www.your_domain;index index.php index.html index.htm;root /var/www/html;server_tokens off;ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem;ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;include /etc/nginx/conf.d/options-ssl-nginx.conf;add_header X-Frame-Options "SAMEORIGIN" always;add_header X-XSS-Protection "1; mode=block" always;add_header X-Content-Type-Options "nosniff" always;add_header Referrer-Policy "no-referrer-when-downgrade" always;add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;# enable strict transport security only if you understand the implicationslocation / {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;}
}
HTTP 服务器块指定了 Certbot 向 .well-known/acme-challenge 目录更新请求的 webroot。它还包括一个 rewrite 指令,将指向根目录的 HTTP 请求导向 HTTPS。
HTTPS 服务器块启用了 ssl 和 http2。
该块还包括 SSL 证书和密钥位置,以及保存到 nginx-conf/options-ssl-nginx.conf 的 Certbot 安全参数建议。
此外,还包含了一些安全标头,可帮助您在 SSL Labs 和 Security Headers 服务器测试网站上获得 A 评级。这些标头包括 X-Frame-Options、X-Content-Type-Options、Referrer Policy、Content-Security-Policy 和 X-XSS-Protection。HTTP Strict Transport Security (HSTS) 标头已注释–只有在您了解其影响并评估其 "预加载 "功能后才可启用。
您的 root 和 index 指令也位于此块中,在步骤 1 中讨论的其他 WordPress 特定位置块也是如此。
编辑完成后,保存并关闭文件。
在重新创建 webserver 服务之前,你需要在 webserver 服务定义中添加 443 端口映射。
打开你的 docker-compose.yml 文件:
nano docker-compose.yml
在 webserver 服务定义中,添加以下端口映射:
...webserver:depends_on:- wordpressimage: nginx:latest-alpinecontainer_name: webserverrestart: unless-stoppedports:- "80:80"- "443:443"volumes:- wordpress:/var/www/html- ./nginx-conf:/etc/nginx/conf.d- certbot-etc:/etc/letsencryptnetworks:- app-network
以下是编辑后的完整 docker-compose.yml 文件:
version: '3'services:db:image: mysql:8.0container_name: dbrestart: unless-stoppedenv_file: .envenvironment:- MYSQL_DATABASE=wordpressvolumes:- dbdata:/var/lib/mysqlcommand: '--default-authentication-plugin=mysql_native_password'networks:- app-networkwordpress:depends_on:- dbimage: wordpress:latest-fpm-alpinecontainer_name: wordpressrestart: unless-stoppedenv_file: .envenvironment:- WORDPRESS_DB_HOST=db:3306- WORDPRESS_DB_USER=$MYSQL_USER- WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD- WORDPRESS_DB_NAME=wordpressvolumes:- wordpress:/var/www/htmlnetworks:- app-networkwebserver:depends_on:- wordpressimage: nginx:latest-alpinecontainer_name: webserverrestart: unless-stoppedports:- "80:80"- "443:443"volumes:- wordpress:/var/www/html- ./nginx-conf:/etc/nginx/conf.d- certbot-etc:/etc/letsencryptnetworks:- app-networkcertbot:depends_on:- webserverimage: certbot/certbotcontainer_name: certbotvolumes:- certbot-etc:/etc/letsencrypt- wordpress:/var/www/htmlcommand: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --force-renewal -d your_domain -d www.your_domainvolumes:certbot-etc:wordpress:dbdata:networks:app-network:driver: bridge
完成编辑后,保存并关闭文件。
重新创建 webserver 服务:
docker-compose up -d --force-recreate --no-deps webserver
使用 docker-compose ps 检查您的服务:
docker-compose ps
输出应该显示你的 db, wordpress, 和 webserver 服务正在运行:
OutputName 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
容器运行后,您就可以通过网络界面完成 WordPress 的安装了。
步骤 6 — 通过 Web 界面完成安装
容器运行后,通过 WordPress 网页界面完成安装。
在网络浏览器中,导航到服务器的域名。记得用您自己的域名代替 your_domain:
https://your_domain
选择您想使用的语言:

单击继续后,您将进入主设置页面,在这里您需要为您的网站选择一个名称和一个用户名。最好在这里选择一个好记的用户名(而不是 “admin”)和一个强大的密码。您可以使用 WordPress 自动生成的密码,也可以创建自己的密码。
最后,您需要输入您的电子邮件地址,并决定是否要阻止搜索引擎索引您的网站:

点击页面底部的安装 WordPress,会出现登录提示:

登录后,您就可以访问 WordPress 管理仪表板:

WordPress 安装完成后,您可以采取措施确保 SSL 证书自动更新。
步骤 7 — 更新证书
Let’s Encrypt 证书的有效期为 90 天。你可以设置一个自动更新流程,以确保它们不会失效。一种方法是使用 cron 计划工具创建一个作业。在下面的示例中,你将创建一个 cron 作业,定期运行一个脚本,更新证书并重新加载 Nginx 配置。
首先,打开一个名为 ssl_renew.sh 的脚本:
nano ssl_renew.sh
在脚本中添加以下代码,更新证书并重新加载网络服务器配置。记住将此处的示例用户名 sammy 替换为您自己的非 root 用户名:
#!/bin/bashCOMPOSE="/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
该脚本首先将 docker-compose 二进制文件分配给一个名为 COMPOSE 的变量,并指定 --no-ansi 选项,该选项将在运行 docker-compose 命令时不使用 ANSI 控制字符。然后,它会对 docker 二进制文件执行同样的操作。最后,它切换到 ~/wordpress 项目目录,并运行以下 docker-compose 命令:
docker-compose run:这将启动一个certbot容器,并覆盖certbot服务定义中提供的命令。不使用certonly子命令,而是使用renew子命令,它将更新即将过期的证书。此外,还包括用于测试脚本的-dry-run选项。docker-compose kill:这将向webserver容器发送SIGHUP信号,以重新加载 Nginx 配置。
然后运行 docker system prune 删除所有未使用的容器和映像。
编辑完成后关闭文件。使用以下命令使其可执行:
chmod +x ssl_renew.sh
接下来,打开 root 的 crontab 文件,按指定间隔运行更新脚本:
sudo crontab -e
如果这是您第一次编辑该文件,系统会要求您选择一个编辑器:
Output
no crontab for root - using an empty oneSelect an editor. To change later, run 'select-editor'.1. /bin/nano <---- easiest2. /usr/bin/vim.basic3. /usr/bin/vim.tiny4. /bin/edChoose 1-4 [1]:
...
在该文件的最底部,添加以下一行:
...
*/5 * * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
这将把工作间隔设为每五分钟一次,这样你就可以测试你的续订请求是否按预期运行。将创建一个日志文件 cron.log 来记录作业的相关输出。
五分钟后,检查 cron.log 以确认续订请求是否成功:
tail -f /var/log/cron.log
下面的输出结果确认更新成功:
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.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
在终端中输入 CTRL+C 退出。
您可以修改 crontab 文件以设置每天的间隔时间。例如,要在每天中午运行脚本,可以像下面这样修改文件的最后一行:
...
0 12 * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
您还需要删除 ssl_renew.sh 脚本中的 --dry-run 选项:
#!/bin/bashCOMPOSE="/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 工作将确保你的 Let’s Encrypt 证书不会失效,在它们符合条件时进行更新。
常见问题
1. 为什么要为 WordPress 使用 Docker Compose?
使用 Docker Compose 简化了 WordPress 的安装过程。无需手动安装 LAMP(Linux、Apache、MySQL、PHP)或 LEMP(Linux、Nginx、MySQL、PHP)堆栈,您可以在一个 docker-compose.yml 文件中定义整个多容器环境。该文件将协调应用程序所需的所有服务;在本例中,将协调 MySQL 数据库、WordPress 应用程序和 Nginx Web 服务器。这种方法耗时较少,而且可以使用预置镜像进行标准化设置。
2. 如何连接 Nginx 网络服务器和 WordPress 应用程序?
Nginx webserver 容器和 wordpress 容器是通过 Compose 文件中定义的自定义桥接网络(名为 app-network)连接的。该网络允许容器进行安全通信。Nginx 配置(nginx.conf)通过代理请求来处理 PHP。具体来说,任何匹配 \\.php$ 的请求都会通过 fastcgi_pass wordpress:9000; 指令传递给 wordpress 容器。这是因为 wordpress 容器运行的是包含 Nginx 需要的 php-fpm 处理器的镜像。
3. 该设置如何处理数据库密码等敏感信息?
该设置通过将敏感信息从主配置中分离出来,对其进行安全管理。所有凭证,如 MYSQL_ROOT_PASSWORD、MYSQL_USER 和 MYSQL_PASSWORD,都存储在 .env 文件中。然后,docker-compose.yml 文件中的 db 和 wordpress 服务将使用 env_file: .env 指令引用该文件。这样可以防止敏感数据被硬编码、公开暴露或意外提交到 Git 仓库。为了进一步做到这一点,教程建议将 .env 添加到 .gitignore 和 .dockerignore 文件中。
4. 获取 SSL 证书的过程是怎样的?
该设置使用专用的 certbot 容器从 Let’s Encrypt 获取证书。
- 初始测试: 首先,运行
docker-compose up -d。docker-compose.yml文件中的certbot服务最初包含-staging标志。这样,Certbot 就会向 Let’s Encrypt 的暂存环境请求测试证书,这有助于避免速率限制,同时确保配置正确无误。 - 验证: 通过检查
webserver容器的/etc/letsencrypt/live目录,验证测试证书是否已创建。 - 启用证书: 确认测试成功后,修改
docker-compose.yml文件中的certbot服务命令。删除-staging标记并添加-force-renewal。 - 最终请求: 然后,运行
docker-compose up --force-recreate --no-deps certbot停止旧的certbot容器,用新命令重新创建它,并请求实时、生产就绪的证书。
5. 如何自动更新 SSL 证书?
在主机上创建一个 shell 脚本 ssl_renew.sh,以自动完成更新过程。该脚本:
- 更改项目目录(
~/wordpress)。 - 运行
$COMPOSE run certbot renew检查证书是否即将到期,并在必要时进行更新。 - 运行
$COMPOSE kill -s SIGHUP webserver向 Nginx 容器发送SIGHUP信号,Nginx 容器会从容地重新加载配置并开始使用新证书。 - 然后,通过将该脚本添加到 root
crontab文件,将其设置为在规定的时间间隔(如每天)自动运行。
6. 如果停止容器,会丢失数据库和 WordPress 文件吗?
不会,该设置是为使用命名卷进行数据持久化而设计的。
dbdata卷挂载到db容器中的/var/lib/mysql中,用于存储所有 MySQL 数据库文件。wordpress卷被挂载到wordpress和webserver容器中的/var/www/html中,用于存储 WordPress 核心文件、主题、插件和上传文件。certbot-etc卷存储你的 SSL 证书。
这些卷由主机文件系统上的 Docker 管理,与容器的生命周期无关。这意味着你可以停止、删除或重新创建容器,而不会丢失任何数据。
7. db 服务定义中的 command 有什么作用?
db 服务使用 mysql:8.0 映像,该映像具有较新的默认身份验证方法。而依赖于 PHP 的 WordPress 映像不支持这种新方法。
为了解决这个兼容性问题,我们在 db 服务定义中添加了 command: '--default-authentication-plugin=mysql_native_password' 指令。这将覆盖映像的默认命令,并告诉 MySQL 服务器使用较早的、兼容的 mysql_native_password 身份验证插件,从而允许 WordPress 成功连接到数据库。
8. Nginx 容器如何从 Certbot 容器获取 SSL 证书?
webserver(Nginx)和 certbot 容器共享一个名为 certbot-etc 的命名卷。
- 在
certbot服务中,该卷被挂载到/etc/letsencrypt。Certbot 获取证书时,会将其写入该目录。 - 在
webserver服务中,同一卷也被挂载到/etc/letsencrypt。
由于两个容器都挂载同一卷,因此 webserver 容器可以立即访问 certbot 容器编写的证书文件(fullchain.pem 和 privkey.pem)。然后,Nginx 配置(nginx.conf)可以直接指向这些文件以启用 SSL。
结论
在本教程中,您使用 Docker Compose 创建了一个带有 Nginx Web 服务器的 WordPress 安装。作为该工作流程的一部分,您为希望与 WordPress 网站关联的域获取了 TLS/SSL 证书。此外,您还创建了一个 cron 作业,以便在必要时更新这些证书。
