介绍

WordPress是一个免费的开源内容管理系统 (CMS),它构建在MySQL数据库上,并使用PHP处理。由于其可扩展的插件架构和模板系统,以及其大部分管理可以通过 Web 界面完成的事实,WordPress 是创建不同类型网站(从博客到产品页面再到电子商务网站)的流行选择。

运行 WordPress 通常需要安装LAMP(Linux、Apache、MySQL 和 PHP)或LEMP(Linux、Nginx、MySQL 和 PHP)堆栈,这可能非常耗时。但是,通过使用DockerDocker Compose等工具,您可以简化设置首选堆栈和安装 WordPress 的过程。您可以使用_图像_,而不是手动安装单个组件,它将库、配置文件和环境变量等标准化,并在_容器中_运行这些图像,在共享操作系统上运行的隔离进程。此外,通过使用 Compose,您可以协调多个容器(例如应用程序和数据库)以相互通信。

在本教程中,您将构建一个多容器 WordPress 安装。您的容器将包括一个 MySQL 数据库、一个 Nginx Web 服务器和 WordPress 本身。您还将通过使用Let’s Encrypt为要与您的站点关联的域获取 TLS/SSL 证书来保护您的安装。最后,您将设置一个cron工作来更新您的证书,以便您的域保持安全。

先决条件

要学习本教程,您需要:

步骤 1 — 定义 Web 服务器配置

在运行任何容器之前,我们的第一步是定义 Nginx Web 服务器的配置。我们的配置文件将包含一些 WordPress 特定的位置块,以及一个位置块,用于将 Let’s Encrypt 验证请求定向到 Certbot 客户端以进行自动证书续订。

首先,为您的 WordPress 设置创建一个名为的项目目录wordpress并导航到它:

1
mkdir wordpress && cd wordpress

接下来,为配置文件创建一个目录:

1
mkdir nginx-conf

使用nano或您喜欢的编辑器打开文件:

1
nano nginx-conf/nginx.conf

在此文件中,我们将添加一个带有服务器名称和文档根指令的服务器块,以及用于引导 Certbot 客户端对证书、PHP 处理和静态资产请求的请求的位置块。

将以下代码粘贴到文件中。请务必替换example.com为您自己的域名:

~/wordpress/nginx-conf/nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
server {
listen 80;
listen [::]:80;

server_name example.com www.example.com;

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:这定义了您的服务器名称和应该用于向您的服务器发出请求的服务器块。请务必example.com将这一行替换为您自己的域名。
  • index:该index指令定义了在处理对服务器的请求时将用作索引的文件。我们在这里修改了默认的优先级顺序,移到index.php了前面,index.html以便 Nginxindex.php在可能的情况下优先考虑调用的文件。
  • root:我们的root指令命名了对我们服务器的请求的根目录。这个目录/var/www/html是在构建时根据我们的WordPress Dockerfile 中的指令创建的挂载点。这些 Dockerfile 指令还确保来自 WordPress 版本的文件安装到此卷。

位置块:

  • location ~ /.well-known/acme-challenge:此位置块将处理对.well-known目录的请求,Certbot 将在其中放置一个临时文件以验证我们域的 DNS 是否解析到我们的服务器。有了这个配置,我们将能够使用 Certbot 的 webroot 插件为我们的域获取证书。
  • location /:在这个位置块中,我们将使用一个try_files指令来检查与单个 URI 请求匹配的文件。Not Found然而,我们将index.php使用请求参数将控制权传递给 WordPress 的文件,而不是返回 404状态作为默认状态。
  • 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.icolocation = /robots.txt:这些块确保请求/favicon.ico/robots.txt不会被记录。
  • location ~* \.(css|gif|ico|jpeg|jpg|js|png)$:此块关闭静态资产请求的日志记录,并确保这些资产具有高度可缓存性,因为它们的服务成本通常很高。

有关 FastCGI 代理的更多信息,请参阅在 Nginx 中了解和实现 FastCGI 代理。有关服务器和位置块的信息,请参阅了解 Nginx 服务器和位置块选择算法

完成编辑后保存并关闭文件。如果您使用过nano,请按CTRL+XY, 然后ENTER

设置好 Nginx 配置后,您可以继续创建环境变量以在运行时传递给您的应用程序和数据库容器。

步骤 2 — 定义环境变量

您的数据库和 WordPress 应用程序容器将需要在运行时访问某些环境变量,以便您的应用程序数据持久保存并可供您的应用程序访问。这些变量包括敏感和非敏感信息:您的 MySQL密码和应用程序数据库用户名和密码的敏感值,以及您的应用程序数据库名称和主机的非敏感信息。

与其在我们的 Docker Compose 文件(包含有关容器如何运行的信息的主文件)中设置所有这些值,不如在文件中设置敏感值.env并限制其流通。这将防止这些值到我们的项目存储库并公开公开。

在您的主项目目录中,打开一个名为 的文件:~/wordpress``.env

1
nano .env

我们将在此文件中设置的机密值包括我们的 MySQL用户的密码,以及 WordPress 将用于访问数据库的用户名和密码。

将以下变量名称和值添加到文件中。请记住在此处为每个变量提供您自己的值

~/wordpress/.env

1
2
3
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

1
git init

然后打开一个.gitignore文件:

1
nano .gitignore

添加.env到文件中:

~/wordpress/.gitignore

1
.env

完成编辑后保存并关闭文件。

同样,添加.env.dockerignore文件是一个很好的预防措施,这样当您将此目录用作构建上下文时,它不会最终出现在您的容器中。

打开文件:

1
nano .dockerignore

添加.env到文件中:

~/wordpress/.dockerignore

1
.env

在此之下,您可以选择添加与应用程序开发相关的文件和目录:

~/wordpress/.dockerignore

1
2
3
4
.env
.git
docker-compose.yml
.dockerignore

完成后保存并关闭文件。

准备好敏感信息后,您现在可以继续在docker-compose.yml文件中定义您的服务。

第 3 步 - 使用 Docker Compose 定义服务

您的docker-compose.yml文件将包含您的设置的服务定义。一个_服务_的撰写是一个正在运行的容器,服务定义指定每个集装箱将如何运行的信息。

使用 Compose,您可以定义不同的服务以运行多容器应用程序,因为 Compose 允许您将这些服务与共享网络和卷链接在一起。这对我们当前的设置很有帮助,因为我们将为我们的数据库、WordPress 应用程序和 Web 服务器创建不同的容器。我们还将创建一个容器来运行Certbot 客户端,以便为我们的网络服务器获取证书。

首先,打开docker-compose.yml文件:

1
nano docker-compose.yml

添加以下代码以定义您的 Compose 文件版本和db数据库服务:

~/wordpress/docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

db服务定义包含以下选项:

  • image:这告诉 Compose 要拉取什么图像来创建容器。我们将图像固定在此处以避免未来随着图像的不断更新而发生冲突。有关版本固定和避免依赖冲突的更多信息,请参阅有关Dockerfile 最佳实践的 Docker 文档。mysql:8.0mysql: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/docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
...
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

在这个服务定义中,我们命名我们的容器并定义一个重启策略,就像我们对db服务所做的那样。我们还添加了一些特定于此容器的选项:

  • depends_on:此选项确保我们的容器将按依赖顺序wordpress启动,db容器在容器之后启动。我们的 WordPress 应用程序依赖于我们的应用程序数据库和用户的存在,因此表达这种依赖顺序将使我们的应用程序能够正常启动。
  • image:对于此设置,我们使用5.1.1-fpm-alpineWordPress 图像。如第 1 步中所述,使用此图像可确保我们的应用程序具有php-fpmNginx 处理 PHP 处理所需的处理器。这也是一个alpine源自Alpine Linux 项目的映像,它将有助于减小我们的整体映像大小。有关使用alpine图像的优缺点以及这对您的应用程序是否有意义的更多信息,请参阅Docker Hub WordPress 图像页面图像变体部分下的完整讨论。
  • env_file:再次,我们指定我们要从我们的.env文件中提取值,因为这是我们定义应用程序数据库用户和密码的地方。
  • environment:这里,我们使用我们在.env文件中定义的值,但我们将它们分配给 WordPress 图像所需的变量名称:WORDPRESS_DB_USERWORDPRESS_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应用程序服务定义下方,为您的webserverNginx 服务添加以下定义:

~/wordpress/docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
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

同样,我们正在命名我们的容器并使其wordpress按照启动顺序依赖于容器。我们还使用了一个alpine图像1.15.12-alpine——Nginx 图像

此服务定义还包括以下选项:

  • ports:这会公开端口80以启用我们nginx.conf第 1 步中的文件中定义的配置选项。
  • volumes:在这里,我们定义了命名卷和绑定安装的组合:

wordpress:/var/www/html:这会将我们的 WordPress 应用程序代码挂载到/var/www/html我们root在 Nginx 服务器块中设置的目录。

./nginx-conf:/etc/nginx/conf.d:这会将挂载主机上的 Nginx 配置目录绑定到容器上的相关目录,确保我们对主机上的文件所做的任何更改都会反映在容器中。

certbot-etc:/etc/letsencrypt:这会将我们域的相关 Let’s Encrypt 证书和密钥安装到容器上的相应目录中。

同样,我们已将此容器添加到app-network网络中。

最后,在您的webserver定义下方,为该服务添加最后一个服务定义certbot。请务必将此处列出的电子邮件地址和域名替换为您自己的信息:

~/wordpress/docker-compose.yml

1
2
3
4
5
6
7
8
9
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@example.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com

这个定义告诉 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:这允许您指定要应用于您的请求的域名。在这种情况下,我们已经包括example.com和。请务必将这些替换为您自己的域。www.example.com

certbot服务定义下方,添加您的网络和卷定义:

~/wordpress/docker-compose.yml

1
2
3
4
5
6
7
8
9
...
volumes:
certbot-etc:
wordpress:
dbdata:

networks:
app-network:
driver: bridge

我们的顶级volumes键定义卷certbot-etcwordpressdbdata。当 Docker 创建卷时,卷的内容存储在主机文件系统上的目录中,该目录/var/lib/docker/volumes/由 Docker 管理。然后每个卷的内容从此目录安装到使用该卷的任何容器。通过这种方式,可以在容器之间共享代码和数据。

用户定义的桥接网络app-network支持我们的容器之间的通信,因为它们位于同一个 Docker 守护进程主机上。这简化了应用程序内的流量和通信,因为它在同一桥接网络上打开容器之间的所有端口,而不会将任何端口暴露给外部世界。这样,我们的dbwordpress, 和webserver容器就可以相互通信了,我们只需要暴露端口就可以让80前端访问应用程序。

完成的docker-compose.yml文件将如下所示:

~/wordpress/docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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@example.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com

volumes:
certbot-etc:
wordpress:
dbdata:

networks:
app-network:
driver: bridge

完成编辑后保存并关闭文件。

服务定义到位后,您就可以启动容器并测试您的证书请求。

第 4 步 - 获取 SSL 证书和凭据

我们可以使用docker-compose up命令启动我们的容器,该命令将按照我们指定的顺序创建和运行我们的容器。如果我们的域请求成功,我们将在输出中看到正确的退出状态以及安装在容器/etc/letsencrypt/live文件夹中的正确证书webserver

创建容器docker-compose up-d标志,将运行dbwordpress以及webserver在后台容器:

1
docker-compose up -d

您将看到确认您的服务已创建的输出:

1
2
3
4
OutputCreating db ... done
Creating wordpress ... done
Creating webserver ... done
Creating certbot ... done

使用docker-compose ps,检查您的服务的状态:

1
docker-compose ps

如果一切都成功,您的db,wordpresswebserverservices 将是Up,并且certbot容器将退出并显示0 状态消息:

1
2
3
4
5
6
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

如果你看到以外的任何其他UpState列的dbwordpresswebserver服务,或以外的退出状态0certbot容器,一定要检查与服务日志docker-compose logs命令:

1
docker-compose logs service_name

您现在可以使用以下命令检查您的证书是否已安装到webserver容器中docker-compose exec

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

如果您的证书请求成功,您将看到如下输出:

1
2
3
4
5
Outputtotal 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 example.com

现在您知道您的请求会成功,您可以编辑certbot服务定义以删除该--staging标志。

打开docker-compose.yml:

1
nano docker-compose.yml

找到具有certbot服务定义的文件部分,并将选项中的标志替换为--staging标志,这将告诉 Certbot 您要请求与现有证书具有相同域的新证书。该服务定义现在这个样子:command``--force-renewal``certbot

~/wordpress/docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
...
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@example.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com
...

您现在可以运行docker-compose up以重新创建certbot容器。我们还将包括--no-deps告诉 Compose 它可以跳过启动webserver服务的选项,因为它已经在运行:

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

您将看到表明您的证书请求成功的输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
OutputRecreating 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 example.com
certbot | http-01 challenge for www.example.com
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/example.com/fullchain.pem
certbot | Your key file has been saved at:
certbot | /etc/letsencrypt/live/example.com/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 将涉及添加到 HTTPS 的 HTTP 重定向、指定我们的 SSL 证书和密钥位置,以及添加安全参数和标头。

由于您要重新创建webserver服务以包含这些添加项,您现在可以停止它:

1
docker-compose stop webserver

在我们修改配置文件本身之前,让我们首先使用以下命令从 Certbot获取推荐的 Nginx 安全参数curl

1
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

此命令将这些参数保存在options-ssl-nginx.conf位于nginx-conf目录中的名为 的文件中。

接下来,删除您之前创建的 Nginx 配置文件:

1
rm nginx-conf/nginx.conf

打开另一个版本的文件:

1
nano nginx-conf/nginx.conf

将以下代码添加到文件以将 HTTP 重定向到 HTTPS 并添加 SSL 凭据、协议和安全标头。请记住example.com用您自己的域替换:

~/wordpress/nginx-conf/nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
server {
listen 80;
listen [::]:80;

server_name example.com www.example.com;

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 example.com www.example.com;

index index.php index.html index.htm;

root /var/www/html;

server_tokens off;

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/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;
}
}

HTTP 服务器块指定 Certbot 续订请求到.well-known/acme-challenge目录的 webroot 。它还包括一个重写指令,将 HTTP 请求定向到根目录到 HTTPS。

HTTPS 服务器块启用sslhttp2. 要了解有关 HTTP/2 如何迭代 HTTP 协议及其对网站性能的好处的更多信息,请参阅如何在 Ubuntu 18.04 上设置支持 HTTP/2 的 Nginx的介绍。

此块还包括我们的 SSL 证书和密钥位置,以及我们保存到的推荐 Certbot 安全参数nginx-conf/options-ssl-nginx.conf

此外,我们还包含了一些安全标头,使我们能够在SSL 实验室安全标头服务器测试站点等方面获得A评级。这些头文件包括,,,,和。该HTTP(HSTS)头部被注释掉了-启用此只有当你了解了影响,并评估其“预加载”功能X-Frame-OptionsX-Content-Type-OptionsReferrer PolicyContent-Security-PolicyX-XSS-ProtectionStrict Transport Security

我们的rootindex指令也位于此块中,与步骤 1 中讨论的 WordPress 特定位置块的其余部分一样。

完成编辑后,保存并关闭文件。

在重新创建webserver服务之前,您需要将443端口映射添加到您的webserver服务定义中。

打开你的docker-compose.yml文件:

1
nano docker-compose.yml

webserver服务定义中,添加以下端口映射:

~/wordpress/docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
...
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

docker-compose.yml文件看起来像这样完成后:

~/wordpress/docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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@example.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com

volumes:
certbot-etc:
wordpress:
dbdata:

networks:
app-network:
driver: bridge

完成编辑后保存并关闭文件。

重新创建webserver服务:

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

检查您的服务docker-compose ps

1
docker-compose ps

您应该看到输出,表明你的dbwordpresswebserver服务正在运行:

1
2
3
4
5
6
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

随着容器的运行,您现在可以通过 Web 界面完成 WordPress 安装。

步骤 6 — 通过 Web 界面完成安装

随着我们的容器运行,我们可以通过 WordPress Web 界面完成安装。

在您的 Web 浏览器中,导航到您的服务器域。记得example.com用你自己的域名替换这里:

1
https://example.com

选择您要使用的语言:

WordPress 语言选择器

单击Continue 后,您将进入主设置页面,您需要在其中为您的站点选择一个名称和一个用户名。在这里选择一个好记的用户名(而不是“admin”)和强密码是个好主意。您可以使用 WordPress 自动生成的密码或创建自己的密码。

最后,您需要输入您的电子邮件地址并决定是否要阻止搜索引擎将您的网站编入索引:

WordPress 主设置页面

单击页面底部的安装 WordPress将带您进入登录提示:

WordPress 登录屏幕

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

WordPress 主管理仪表板

完成 WordPress 安装后,您现在可以采取措施确保您的 SSL 证书自动续订。

步骤 7 — 更新证书

Let’s Encrypt 证书的有效期为 90 天,因此您需要设置自动续订流程以确保它们不会失效。一种方法是使用cron调度实用程序创建作业。在这种情况下,我们将创建一个cron作业来定期运行一个脚本,该脚本将更新我们的证书并重新加载我们的 Nginx 配置。

首先,打开一个名为 的脚本ssl_renew.sh

1
nano ssl_renew.sh

将以下代码添加到脚本中以更新您的证书并重新加载您的 Web 服务器配置。请记住将此处的示例用户名替换为您自己的非 root 用户名:

~/wordpress/ssl_renew.sh

1
2
3
4
5
6
7
8
#!/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

此脚本首先将docker-compose二进制文件分配给名为 的变量COMPOSE,并指定--no-ansi选项,该选项将运行docker-compose没有ANSI 控制字符的命令。然后它对docker二进制文件执行相同的操作。最后,它切换到~/wordpress项目目录并运行以下docker-compose命令:

  • docker-compose run:这将启动一个certbot容器并覆盖command我们certbot服务定义中提供的。certonly我们在renew这里不使用子命令,而是使用子命令,它将更新即将到期的证书。我们在--dry-run此处包含了测试脚本的选项。
  • docker-compose kill:这将一个发送SIGHUP信号webserver容器重新加载Nginx的配置。有关使用此过程重新加载 Nginx 配置的更多信息,请参阅有关使用Docker 部署官方 Nginx 映像的这篇 Docker 博客文章

然后运行docker system prune以删除所有未使用的容器和图像。

完成编辑后关闭文件。使其可执行:

1
chmod +x ssl_renew.sh

接下来,打开 crontab文件以指定的时间间隔运行续订脚本:

1
sudo crontab -e

如果这是您第一次编辑此文件,系统会要求您选择一个编辑器:

1
2
3
4
5
6
7
8
9
10
Outputno 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]:
...

在文件底部,添加以下行:

定时任务表

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

这会将作业间隔设置为每五分钟,因此您可以测试您的续订请求是否按预期工作。我们还创建了一个日志文件cron.log,用于记录作业的相关输出。

五分钟后,查看cron.log续订请求是否成功:

1
tail -f /var/log/cron.log

您应该会看到确认续订成功的输出:

1
2
3
4
5
6
7
8
9
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/example.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

您现在可以修改crontab文件以设置每日间隔。例如,要每天中午运行该脚本,您可以将文件的最后一行修改为如下所示:

定时任务表

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

您还需要--dry-runssl_renew.sh脚本中删除该选项:

~/wordpress/ssl_renew.sh

1
2
3
4
5
6
7
8
#!/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工作将确保您的 Let’s Encrypt 证书在符合条件时续订不会失效。您还可以使用 Logrotate 实用程序设置日志轮换,以轮换和压缩日志文件。

结论

在本教程中,您使用 Docker Compose 创建了一个带有 Nginx Web 服务器的 WordPress 安装。作为此工作流程的一部分,您为要与 WordPress 站点关联的域获取了 TLS/SSL 证书。此外,您还创建了一个cron作业来在必要时更新这些证书。

作为提高站点性能和冗余的额外步骤,您可以参考以下有关交付和备份 WordPress 资产的文章:

如果您有兴趣探索使用 Kubernetes 的容器化工作流程,您还可以查看:

转载: https://www.digitalocean.com/community/tutorials/how-to-install-wordpress-with-docker-compose