如何使用 Docker Compose 安装 Drupal

作者选择了 联合国基金会作为 写给捐赠计划的一部分接受捐赠。

_本教程的原始 WordPress 版本Kathleen Juell撰写。

介绍

Drupal是一个以 PHP编写的内容管理系统(CMS),并在开源 GNU General Public License下分发。世界各地的人和组织使用Drupal来支持政府网站,个人博客,企业等等。

Drupal 需要安装 LAMP(Linux,Apache,MySQL,PHP)或 LEMP(Linux, Nginx,MySQL,PHP)堆栈,但安装单个组件是一项耗时的任务。我们可以使用工具,如 DockerDocker Compose来简化安装 Drupal 的过程。本教程将使用 Docker 图像来安装 Docker 容器中的单个组件。

在本教程中,我们将使用 Docker Compose 安装 Drupal,以便我们能够利用集装箱化并在服务器上部署我们的 Drupal 网站. 我们将为 MySQL 数据库, Nginx 网页服务器和 Drupal 运行容器. 我们还将通过获得 TLS/SSL 证书与 Let’s Encrypt 用于我们希望与我们的网站相关联的域名来确保我们的安装。

前提条件

要遵循这个教程,我们将需要:

  • 运行 Ubuntu 18.04 的服务器,以及拥有 " sudo " 权限和主动防火墙的非端用户。 关于这些设置的指导,请参见此[初始服务器设置指南] (https://andsky.com/tech/tutorials/initial-server-setup-with-ubuntu-18-04).
  • Docker 安装在您的服务器上,遵循 [Ubuntu 18.04上如何安装和使用 Docker (https://andsky.com/tech/tutorials/how-to-install-and-use-docker-on-ubuntu-18-04) 第 1 和 2 步. 此教程已在19.03.8版测试._.
  • 在您的服务器上安装了 Docker Compose, 遵循 [如何在 Ubuntu 18.04 上安装 Docker Compose (https://andsky.com/tech/tutorials/how-to-install-docker-compose-on-ubuntu-18-04) 第 1 步. 此教程已在1.21.2._版本测试过.
  • A已注册域名. 此教程将始终使用 您的域 。 您可以在 [Freenom] (http://www.freenom.com/en/index.html) 免费获得一个, 或者使用您选择的域注册员.
  • 两种为您的服务器设置的 DNS 记录 。 您可以遵循DigitalOcean DNS的介绍,了解如何将它们添加到DigitalOcean账户中的细节,如果这是您正在使用的: — 一个记录, 上面写着 您的域名 , 指向您的服务器的公开IP地址。 — 一个记录, 上面写着 www. your_domain , 指向您的服务器的公开IP地址。

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

在运行任何容器之前,我们需要为我们的 Nginx Web 服务器定义配置,我们的配置文件将包含一些 Drupal 特定的位置块,以及一个位置块,以便将 Let’s Encrypt 验证请求直接发送到 Certbot 客户端进行自动证书更新。

首先,让我们为我们的Drupal设置创建一个名为drupal的项目目录:

1mkdir drupal

移动到新创建的目录:

1cd drupal

现在我们可以为我们的配置文件创建一个目录:

1mkdir nginx-conf

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

1nano nginx-conf/nginx.conf

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

将以下代码添加到文件中. 请确保用自己的域名更换 your_domain:

 1[label ~/drupal/nginx-conf/nginx.conf]
 2server {
 3    listen 80;
 4    listen [::]:80;
 5
 6    server_name your_domain www.your_domain;
 7
 8    index index.php index.html index.htm;
 9
10    root /var/www/html;
11
12    location ~ /.well-known/acme-challenge {
13        allow all;
14        root /var/www/html;
15    }
16
17    location / {
18        try_files $uri $uri/ /index.php$is_args$args;
19    }
20
21    rewrite ^/core/authorize.php/core/authorize.php(.*)$ /core/authorize.php$1;
22
23    location ~ \.php$ {
24        try_files $uri =404;
25        fastcgi_split_path_info ^(.+\.php)(/.+)$;
26        fastcgi_pass drupal:9000;
27        fastcgi_index index.php;
28        include fastcgi_params;
29        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
30        fastcgi_param PATH_INFO $fastcgi_path_info;
31    }
32
33    location ~ /\.ht {
34        deny all;
35    }
36
37    location = /favicon.ico { 
38        log_not_found off; access_log off; 
39    }
40    location = /robots.txt { 
41        log_not_found off; access_log off; allow all; 
42    }
43    location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
44        expires max;
45        log_not_found off;
46    }
47}

我们的服务器块包含以下信息:

指南: **

  • 听着': 这告诉Nginx在 " 80 " 端口上听,这将允许我们使用 Certbot 的 [webroot 插件] (https://certbot.eff.org/docs/using.html?highlight=webroot%20path# webroot ) 来申请证书。 请注意,我们尚未包括 " 443 " 港 -- -- 一旦成功获得证书,我们将更新我们的配置,以纳入SSL。 这定义了我们的服务器名称和服务器块,用于向服务器提出的请求. 在此行中,请务必用自己的域名来替换您的域名。 索引指令定义了处理服务器请求时用作索引的文件 。 我们修改了这里的默认优先级顺序,在"index.html"前移动了"index.php",以便Nginx在可能时优先使用名为"index.php"的文件. *"root": 我们的根指令命名了请求服务器的根目录 。 这个目录/var/www/html'是根据我们Drupal Dockerfile中的指示在建设时作为挂载点而创建的。 这些 Dockerfile 指令还确保 Drupal 发布时的文件被挂载到本卷.
  • ‘重写':如果指定的正则表达式(^/core/ authorize.php/core/ authorize.php (.*)$) 匹配请求的 URI, 将按替换字符串( /core/ authorize.php 1' ) 中指定的修改 URI。 (韩语)_

区块链位置:**

*地点~.众所周知/挑战': 这个位置块将处理向.众所周知'目录提出的请求,其中Certbot将放置一个临时文件,以验证我们域的DNS解决给我们的服务器。 有了这个配置,我们将能够使用 Certbot 的 Webroot 插件来获得我们域的证书 。

  • 位置 /' : 在此位置块中, 我们将使用 try_ files 指令来检查符合个人 URI 请求的文件 。 但是,我们不会将404未找到 ' 状态作为默认,而是将控制权交给Drupal的index.php ' 文件,并附上请求参数。 这个位置块将处理PHP处理,并将这些请求代理到我们的**drupal** 容器. 因为我们的 Drupal Docker 图像将基于 php: fpm 图像, 我们还会在此块中包含针对 [FastCGI 协议] (http://www.mit.edu/~yandros/doc/specs/fcgi-spec.html ) 的配置选项 。 Nginx 对 PHP 请求需要一个独立的 PHP 处理器: 就我们而言,这些请求将由php-fpm' 处理器处理,该处理器包含在`php:fpm' 图像中。 此外,这个位置块包括 FastCGI 特定指令、变量和选项,这些选项将在我们的 Drupal 容器中运行的 Drupal 应用程序中代理请求, 设置解析请求 URI 的首选索引, 并解析 URI 请求 。
  • ' 位置 ~ /.ht' : 此块将处理 '. htaccess' 文件, 因为 Nginx 不会为它们服务 。 deny-all'指令确保.htaccess ' 文件永远不会提供给用户。 这些区块确保 " /favicon.ico " 和 "/robots.txt " 的请求不会被记录。 *`位置'\(css|gif|icojpeg|jpg|jpgjspng) $: 此块关闭静态资产请求的登录,并确保这些资产高度可缓存,因为通常服务费用昂贵.

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

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

有了 Nginx 配置,您可以继续创建环境变量,在运行时传输到您的应用程序和数据库容器。

第2步:定义环境变量

我们的Drupal应用程序需要一个数据库(MySQL,PostgresSQL等)来保存与网站相关的信息.Drupal容器需要在运行时访问某些环境变量,以便访问数据库(MySQL)容器。这些变量包含敏感信息,如数据库的凭证,所以我们不能直接暴露它们在Docker Compose文件中 - 主要文件包含有关我们的容器如何运行的信息。

建议始终在.env 文件中设置敏感值,并限制其流通,这将防止这些值被复制到我们的项目存储库并被公开曝光。

在主项目目录中,~/drupal,创建并打开名为.env的文件:

1nano .env

将下列变量添加到.env 文件中,以您想要使用的身份证代替所突出的部分:

1[label ~/drupal/.env]
2MYSQL_ROOT_PASSWORD=root_password
3MYSQL_DATABASE=drupal
4MYSQL_USER=drupal_database_user
5MYSQL_PASSWORD=drupal_database_password

我们现在已经添加了MySQL root管理帐户的密码,以及我们应用程序数据库的首选用户名和密码。

我们的.env 文件包含敏感信息,因此建议将其包含在项目的.gitignore 和.dockerignore 文件中,以免被添加到我们的 Git 存储库和 Docker 图像中。

如果您打算使用 Git 进行版本控制,则 将当前工作目录初始化为存储库git init:

1git init

打开.gitignore 文件:

1nano .gitignore

添加以下内容:

1[label ~/drupal/.gitignore]
2.env

保存和退出文件。

同样,打开.dockerignore 文件:

1nano .dockerignore

然后添加以下内容:

1[label ~/drupal/.dockerignore]
2.env
3.git

保存和退出文件。

现在我们已经采取措施来保护我们的身份证作为环境变量,让我们进入我们在docker-compose.yml文件中定义我们的服务的下一步。

步骤 3 — 使用 Docker Compose 定义服务

Docker Compose 是定义和运行多容器 Docker 应用程序的工具,我们定义了一个 YAML 文件来配置我们的应用程序的服务。

我们将为我们的 Drupal 应用程序、数据库和 Web 服务器创建不同的容器. 除了这些,我们还将创建一个容器来运行 Certbot以获得我们的 Web 服务器的证书。

创建一个docker-compose.yml文件:

1nano docker-compose.yml

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

 1[label ~/drupal/docker-compose.yml]
 2version: "3"
 3
 4services:
 5  mysql:
 6    image: mysql:8.0
 7    container_name: mysql
 8    command: --default-authentication-plugin=mysql_native_password
 9    restart: unless-stopped
10    env_file: .env
11    volumes:
12      - db-data:/var/lib/mysql
13    networks:
14      - internal

让我们通过这些一个接一个的mysql服务的所有配置选项:

  • 图像': 此选项指定用于创建容器的图像 。 总是建议使用带有适当版本标记的图像,但不包括最后'标记,以避免今后发生冲突。 更多信息,请查阅Docker文档中的Dockerfile最佳做法.
  • Contaner_name': 定义容器的名称。 *命令': 这用于覆盖图像中的默认命令(CMD指令). MySQL 支持不同的认证插件,但"mysql_native_password"是认证的传统方法. 由于PHP,因此Drupal不会支持更新的MySQL认证,我们需要将"--default-authentation-plugin=mysql_native_password"设定为默认认证机制. *"再起": 用于定义容器重启策略 。 " 除非停止 " 政策重新启动一个容器, 除非它被手动停止。
  • env_file' : 这增加了文件的环境变量 。 就我们而言,它将读取前一步骤所定义的.env'文件中的环境变量。 *量': 此挂载主机路径或命名卷, 指定为服务的子选项 。 我们正在将一个名为 " db-data " 的卷子安装到容器上的 " /var/lib/mysql " 目录上,默认 MySQL 将在此撰写其数据文件。 *networks': 这定义了我们的应用程序服务将加入的 " 内部 " 网络。 我们将定义文件末尾的网络。

我们已经定义了我们的mysql服务定义,所以现在让我们把drupal应用服务的定义添加到文件的末尾:

 1[label ~/drupal/docker-compose.yml]
 2...
 3  drupal:
 4    image: drupal:8.7.8-fpm-alpine
 5    container_name: drupal
 6    depends_on:
 7      - mysql
 8    restart: unless-stopped
 9    networks:
10      - internal
11      - external
12    volumes:
13      - drupal-data:/var/www/html

在这个服务定义中,我们正在命名容器并定义重新启动策略,就像我们在mysql服务中一样。

  • 图像: 在这里,我们使用[8.7.8-fpm-alpine](https://github.com/docker-library/drupal/blob/47c6c3f965313a60930e0875867ef9e4cba46f73/8.7/fpm-alpine/Dockerfile) Drupal 图像。 这个图像有我们Nginx网络服务器处理PHP处理所需的php-fpm处理器。 此外,我们正在使用来自Alpine Linux项目的 " 阿尔卑斯山 " 图像,这将缩小整体图像的大小,并在Dockerfile最佳做法中被推荐。 Drupal 有更多版本的图像,所以在 [Dockerhub] (https://hub.docker.com/_/drupal)上查看. 依赖': 这用于表示服务之间的依赖性。 将 " misql " 服务界定为依赖我们的 " drup " 集装箱,将确保我们的 " drup " 集装箱在 " misql " 集装箱之后被创建,并使我们能够顺利地开始应用。 这将确保我们的 " misql " 服务只能通过 " 内部 " 网络从 " drupal " 集装箱取用,同时通过 " 外部 " 网络使其他集装箱取用这一集装箱。 *量': 我们正在将一个名为 " drupal-data " 的卷子加到[Drupal 图像(https://github.com/docker-library/drupal/blob/47c6c3f965313a60930e0875867ef9e4cba46f73/8.7/fpm-alpine/Dockerfile# L50)所创建的 " /var/www/html " 上。 这样使用一个取名的音量将使我们能够与其他容器共享应用程序代码。

接下来,让我们在drupal服务定义后添加 Nginx 服务定义:

 1[label ~/drupal/docker-compose.yml]
 2...
 3  webserver:
 4    image: nginx:1.17.4-alpine
 5    container_name: webserver
 6    depends_on:
 7      - drupal
 8    restart: unless-stopped
 9    ports:
10      - 80:80
11    volumes:
12      - drupal-data:/var/www/html
13      - ./nginx-conf:/etc/nginx/conf.d
14      - certbot-etc:/etc/letsencrypt
15    networks:
16      - external

再次,我们正在命名我们的容器,并使其依赖于Drupal容器以便开始。

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

这里,我们定义了命名的卷和主机路径:

  • drupal-data:/var/www/html:这将将我们的Drupal应用程序代码安装在容器上的相应目录中,我们将其设置为我们的Nginx服务器块中的根目录。
  • ./nginx-conf:/etc/nginx/conf.d:这将安装在主机上的Nginx配置目录到容器上的相应目录,确保我们在主机上的任何更改都会反映在容器中。

最后,我们将为certbot服务添加最后的服务定义,请确保用自己的电子邮件和域名取代sammy@your_domainyour_domain:

 1[label ~/drupal/docker-compose.yml]
 2...
 3  certbot:
 4    depends_on:
 5      - webserver
 6    image: certbot/certbot
 7    container_name: certbot
 8    volumes:
 9      - certbot-etc:/etc/letsencrypt
10      - drupal-data:/var/www/html
11    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

这个定义告诉 Compose 从 Docker Hub 提取 certbot/certbot图像,它还使用命名的卷与 Nginx 容器共享资源,包括在 'certbot-etc' 中的域证书和密钥以及在 'drupal-data' 中的应用程序代码。

我们还使用了depends_on来确保certbot容器在webserver服务运行后启动。

我们没有在这里指定任何网络,因为这个容器不会通过网络与任何服务进行通信. 它只是添加了域证书和密钥,我们使用命名的卷安装了它们。

我们还包括了命令选项,该选项指定一个子命令以容器的默认命令certbot运行。Certbot客户端支持用于获取和安装证书的插件。我们正在使用webroot插件通过在命令行中包含certonly--webroot来获取证书。

certbot服务定义之后,添加网络和体积定义:

 1[label ~/drupal/docker-compose.yml]
 2...
 3networks:
 4  external:
 5    driver: bridge
 6  internal:
 7    driver: bridge
 8
 9volumes:
10  drupal-data:
11  db-data:
12  certbot-etc:

顶级网络密钥允许我们指定要创建的网络。网络允许在所有端口上跨服务/容器进行通信,因为它们位于同一个 Docker 主机上。

键用于定义名为drupal-data,db-datacertbot-etc的卷。当Docker创建卷时,卷的内容存储在主机文件系统上的一个目录中,即/var/lib/docker/volumes/,由Docker管理。

完成的「docker-compose.yml」文件将看起来如下:

 1[label ~/drupal/docker-compose.yml]
 2version: "3"
 3
 4services:
 5  mysql:
 6    image: mysql:8.0
 7    container_name: mysql
 8    command: --default-authentication-plugin=mysql_native_password
 9    restart: unless-stopped
10    env_file: .env
11    volumes:
12      - db-data:/var/lib/mysql
13    networks:
14      - internal
15
16  drupal:
17    image: drupal:8.7.8-fpm-alpine
18    container_name: drupal
19    depends_on:
20      - mysql
21    restart: unless-stopped
22    networks:
23      - internal
24      - external
25    volumes:
26      - drupal-data:/var/www/html
27
28  webserver:
29    image: nginx:1.17.4-alpine
30    container_name: webserver
31    depends_on:
32      - drupal
33    restart: unless-stopped
34    ports:
35      - 80:80
36    volumes:
37      - drupal-data:/var/www/html
38      - ./nginx-conf:/etc/nginx/conf.d
39      - certbot-etc:/etc/letsencrypt
40    networks:
41      - external
42
43  certbot:
44    depends_on:
45      - webserver
46    image: certbot/certbot
47    container_name: certbot
48    volumes:
49      - certbot-etc:/etc/letsencrypt
50      - drupal-data:/var/www/html
51    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
52
53networks:
54  external:
55    driver: bridge
56  internal:
57    driver: bridge
58
59volumes:
60  drupal-data:
61  db-data:
62  certbot-etc:

接下来,让我们开始容器并测试我们的证书请求。

步骤 4 – 获取SSL证书和凭证

如果我们的域请求成功,我们将在我们的输出中看到正确的退出状态,并在Web服务器容器上的/etc/letsencrypt/live文件夹中安装正确的证书。

要在背景中运行容器,请使用docker-compose up命令与-d旗帜:

1docker-compose up -d

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

1[secondary_label Output]
2...
3Creating mysql     ... done
4Creating drupal    ... done
5Creating webserver ... done
6Creating certbot   ... done

使用docker-compose ps命令检查服务的状态:

1docker-compose ps

我们将看到mysql,drupalwebserver服务具有状态Up,而certbot将以0状态消息退出:

1[secondary_label Output]
2  Name Command State Ports
3--------------------------------------------------------------------------
4certbot certbot certonly --webroot ... Exit 0
5drupal docker-php-entrypoint php-fpm Up 9000/tcp
6mysql docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp
7webserver nginx -g daemon off;             Up 0.0.0.0:80->80/tcp

如果您在状态列中看到mysql,drupalwebserver服务的Up,或certbot容器的0以外的输出状态,请用docker-compose logs命令检查服务日志:

1docker-compose logs service_name

现在我们可以检查我们的证书是否安装在webserver容器上,使用docker-compose exec命令:

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

这将产生以下产出:

1[secondary_label Output]
2total 16
3drwx------    3 root root 4096 Oct 5 09:15 .
4drwxr-xr-x 9 root root 4096 Oct 5 09:15 ..
5-rw-r--r--    1 root root 740 Oct 5 09:15 README
6drwxr-xr-x 2 root root 4096 Oct 5 09:15 your_domain

现在一切顺利运行,我们可以编辑我们的certbot服务定义,以删除--staging旗帜。

打开docker-compose.yml文件,转到certbot服务定义,并在命令选项中替换--staging旗帜以--force-renewal旗帜,该旗帜会告诉Certbot您想要请求一个与现有证书相同的域的新证书。

 1[label ~/drupal/docker-compose.yml]
 2...
 3  certbot:
 4    depends_on:
 5      - webserver
 6    image: certbot/certbot
 7    container_name: certbot
 8    volumes:
 9      - certbot-etc:/etc/letsencrypt
10      - drupal-data:/var/www/html
11    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
12...

我们还将包括--no-deps选项告诉Compose它可以跳过启动webserver服务,因为它已经在运行:

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

我们会看到输出表明我们的证书请求成功:

 1[secondary_label Output]
 2Recreating certbot ... done
 3Attaching to certbot
 4certbot      | Saving debug log to /var/log/letsencrypt/letsencrypt.log
 5certbot      | Plugins selected: Authenticator webroot, Installer None
 6certbot      | Renewing an existing certificate
 7certbot      | Performing the following challenges:
 8certbot      | http-01 challenge for your_domain
 9certbot      | http-01 challenge for www.your_domain
10certbot      | Using the webroot path /var/www/html for all unmatched domains.
11certbot      | Waiting for verification...
12certbot      | Cleaning up challenges
13certbot      | IMPORTANT NOTES:
14certbot      |  - Congratulations! Your certificate and chain have been saved at:
15certbot      |    /etc/letsencrypt/live/your_domain/fullchain.pem
16certbot      |    Your key file has been saved at:
17certbot      |    /etc/letsencrypt/live/your_domain/privkey.pem
18certbot      |    Your cert will expire on 2020-01-03. To obtain a new or tweaked
19certbot      |    version of this certificate in the future, simply run certbot
20certbot      |    again. To non-interactively renew *all* of your certificates, run
21certbot      |    "certbot renew"
22certbot      |  - Your account credentials have been saved in your Certbot
23certbot      |    configuration directory at /etc/letsencrypt. You should make a
24certbot      |    secure backup of this folder now. This configuration directory will
25certbot      |    also contain certificates and private keys obtained by Certbot so
26certbot      |    making regular backups of this folder is ideal.
27certbot      |  - If you like Certbot, please consider supporting our work by:
28certbot      |
29certbot      |    Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
30certbot      |    Donating to EFF:                    https://eff.org/donate-le
31certbot      |
32certbot exited with code 0

现在我们已经成功地生成了我们的证书,我们可以更新我们的 Nginx 配置以包括 SSL。

步骤 5 — 更改 Web 服务器配置和服务定义

在 Nginx 中安装 SSL 证书后,我们将需要将所有 HTTP 请求重定向到 HTTPS. 我们还需要指定我们的 SSL 证书和关键位置,并添加安全参数和标题。

由于您将重新创建Web服务器服务以包括这些添加,您现在可以停止它:

1docker-compose stop webserver

这将产生以下产出:

1[secondary_label Output]
2Stopping webserver ... done

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

1rm nginx-conf/nginx.conf

打开文件的另一个版本:

1nano nginx-conf/nginx.conf

将下列代码添加到文件中,以将 HTTP 重定向到 HTTPS,并添加 SSL 凭证、协议和安全标题。

 1[label ~/drupal/nginx-conf/nginx.conf]
 2server {
 3    listen 80;
 4    listen [::]:80;
 5
 6    server_name your_domain www.your_domain;
 7
 8    location ~ /.well-known/acme-challenge {
 9        allow all;
10        root /var/www/html;
11    }
12
13    location / {
14        rewrite ^ https://$host$request_uri? permanent;
15    }
16}
17server {
18    listen 443 ssl;
19    listen [::]:443 ssl;
20    server_name your_domain www.your_domain;
21
22    index index.php index.html index.htm;
23
24    root /var/www/html;
25
26    server_tokens off;
27
28    ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem;
29    ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;
30
31    add_header X-Frame-Options "SAMEORIGIN" always;
32    add_header X-XSS-Protection "1; mode=block" always;
33    add_header X-Content-Type-Options "nosniff" always;
34    add_header Referrer-Policy "no-referrer-when-downgrade" always;
35    add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
36
37    location / {
38        try_files $uri $uri/ /index.php$is_args$args;
39    }
40
41    rewrite ^/core/authorize.php/core/authorize.php(.*)$ /core/authorize.php$1;
42
43    location ~ \.php$ {
44        try_files $uri =404;
45        fastcgi_split_path_info ^(.+\.php)(/.+)$;
46        fastcgi_pass drupal:9000;
47        fastcgi_index index.php;
48        include fastcgi_params;
49        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
50        fastcgi_param PATH_INFO $fastcgi_path_info;
51    }
52
53    location ~ /\.ht {
54        deny all;
55    }
56
57    location = /favicon.ico {
58        log_not_found off; access_log off;
59    }
60    location = /robots.txt {
61        log_not_found off; access_log off; allow all;
62    }
63    location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
64        expires max;
65        log_not_found off;
66    }
67}

HTTP 服务器块将 Webroot 插件指定为 Certbot 更新请求的 .well-known/acme-challenge 目录. 它还包括一个 rewrite 指令,该指令将 HTTP 请求转移到 root 目录到 HTTPS。

HTTPS 服务器块允许sslhttp2。 有关 HTTP/2 如何在 HTTP 协议上迭代以及它可以对网站性能带来哪些好处的更多信息,请参阅 How To Set Up Nginx with HTTP/2 Support on Ubuntu 18.04的介绍。

这些标题允许 SSL,因为我们已包括我们的 SSL 证书和关键位置以及推荐的标题,这些标题将使我们能够在 SSL LabsSecurity Headers服务器测试站点上获得 A 评级。

我们的索引指令也位于这个块中,就像在步骤 1 中讨论的其他 Drupal 特定的位置块一样。

保存并关闭更新的 Nginx 配置文件。

在重建网页服务器容器之前,我们需要为我们的网页服务器服务定义添加443端口映射,因为我们已启用了SSL证书。

打开docker-compose.yml文件:

1nano docker-compose.yml

webserver服务定义中进行以下更改:

 1[label ~/drupal/docker-compose.yml]
 2...
 3  webserver:
 4    image: nginx:1.17.4-alpine
 5    container_name: webserver
 6    depends_on:
 7      - drupal
 8    restart: unless-stopped
 9    ports:
10      - 80:80
11      - 443:443
12    volumes:
13      - drupal-data:/var/www/html
14      - ./nginx-conf:/etc/nginx/conf.d
15      - certbot-etc:/etc/letsencrypt
16    networks:
17      - external
18...

启用SSL证书后,我们的docker-compose.yml将看起来如下:

 1[label ~/drupal/docker-compose.yml]
 2version: "3"
 3
 4services:
 5  mysql:
 6    image: mysql:8.0
 7    container_name: mysql
 8    command: --default-authentication-plugin=mysql_native_password
 9    restart: unless-stopped
10    env_file: .env
11    volumes:
12      - db-data:/var/lib/mysql
13    networks:
14      - internal
15
16  drupal:
17    image: drupal:8.7.8-fpm-alpine
18    container_name: drupal
19    depends_on:
20      - mysql
21    restart: unless-stopped
22    networks:
23      - internal
24      - external
25    volumes:
26      - drupal-data:/var/www/html
27
28  webserver:
29    image: nginx:1.17.4-alpine
30    container_name: webserver
31    depends_on:
32      - drupal
33    restart: unless-stopped
34    ports:
35      - 80:80
36      - 443:443
37    volumes:
38      - drupal-data:/var/www/html
39      - ./nginx-conf:/etc/nginx/conf.d
40      - certbot-etc:/etc/letsencrypt
41    networks:
42      - external
43
44  certbot:
45    depends_on:
46      - webserver
47    image: certbot/certbot
48    container_name: certbot
49    volumes:
50      - certbot-etc:/etc/letsencrypt
51      - drupal-data:/var/www/html
52    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
53
54networks:
55  external:
56    driver: bridge
57  internal:
58    driver: bridge
59
60volumes:
61  drupal-data:
62  db-data:
63  certbot-etc:

保存和关闭文件. 让我们用我们的更新配置重建webserver服务:

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

这将产生以下产出:

1[secondary_label Output]
2Recreating webserver ... done

查看docker-compose ps的服务:

1docker-compose ps

我们将看到mysql,drupalwebserver服务为Up,而certbot将以0状态消息退出:

1[secondary_label Output]
2  Name Command State Ports
3--------------------------------------------------------------------------
4certbot certbot certonly --webroot ... Exit 0
5drupal docker-php-entrypoint php-fpm Up 9000/tcp
6mysql docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp
7webserver nginx -g daemon off;             Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp

现在,我们所有的服务都在运行,我们可以通过 Web 界面安装 Drupal。

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

让我们通过 Drupal 的 Web 界面完成安装。

在网页浏览器中,导航到服务器的域名. 请记住在这里用自己的域名替换 your_domain:

1https://your_domain

选择要使用的语言:

Choose language page on Drupal web interface

点击 保存并继续 . 我们将登陆到 ** 安装配置文件** 页面. Drupal有多个配置文件,所以选择 ** 标准** 配置文件,然后点击 ** 保存并继续** 。

Choose profile page on Drupal web interface

选择数据库类型为 MySQL、MariaDB、Percona Server 或同等类型,并在步骤 2 中的 .env 文件中分别定义的 MYSQL_DATABASEMYSQL_USERMYSQL_PASSWORD 值中输入 数据库名称 、 ** 用户名** 和 ** 密码,然后点击 ** Advanced Options** 并将 ** Host** 值设置为 `mysql' 服务容器名称。

Set up database page on Drupal web interface

配置数据库后,它将开始安装Drupal默认模块和主题:

Install site page on Drupal web interface

一旦网站安装,我们将登陆Drupal网站设置页面以配置网站名称,电子邮件,用户名,密码和区域设置。

Configure site page on Drupal web interface

点击保存并继续后,我们可以看到欢迎来到Drupal页面,这表明我们的Drupal网站正在成功运行。

Welcome to Drupal page on Drupal web interface

现在,我们的Drupal安装完成了,我们需要确保我们的SSL证书会自动更新。

第7步:更新证书

Let’s Encrypt 证书有效期为 90 天,因此我们需要设置一个自动更新流程,以确保它们不会过期。这样做的一种方法是使用cron编程工具创建工作。

让我们创建 ssl_renew.sh 文件来更新我们的证书:

1nano ssl_renew.sh

添加以下代码: 请记住用自己的非根用户更换目录名称:

1[label ~/drupal/ssl_renew.sh]
2
3#!/bin/bash
4
5cd /home/sammy/drupal/
6/usr/local/bin/docker-compose -f docker-compose.yml run certbot renew --dry-run && \
7/usr/local/bin/docker-compose -f docker-compose.yml kill -s SIGHUP webserver

此脚本更改为~/drupal项目目录,并运行以下docker-compose命令。

  • docker-compose run:这将启动一个 certbot 容器,并忽略在我们的 certbot 服务定义中提供的 命令。而不是使用 certonly子命令,我们在这里使用renew子命令,这将更新即将到期的证书。我们在这里包含了--dry-run` 选项来测试我们的脚本。
  • docker-compose kill: 这将向 webserver 容器发送一个 SIGHUP 信号来重新加载 Nginx 配置。

关闭文件并通过运行以下命令使其可执行:

1sudo chmod +x ssl_renew.sh

接下来,打开‘root’ crontab 文件以在指定间隔内运行更新脚本:

1sudo crontab -e

如果这是您第一次编辑此文件,您将被要求选择一个文本编辑器以打开该文件:

 1[secondary_label Output]
 2no crontab for root - using an empty one
 3
 4Select an editor. To change later, run 'select-editor'.
 5  1. /bin/nano
 6  2. /usr/bin/vim.basic
 7  3. /usr/bin/vim.tiny
 8  4. /bin/ed
 9
10Choose 1-4 [1]:
11...

在文件的末尾,添加以下行,用您的用户名取代sammy:

1[label crontab]
2...
3*/5 * * * * /home/sammy/drupal/ssl_renew.sh >> /var/log/cron.log 2>&1

这将使工作间隔设置为每五分钟,以便我们可以测试我们的更新请求是否按预期工作,我们还创建了一个日志文件,‘cron.log’,以记录工作中的相关输出。

五分钟后,使用尾巴命令检查cron.log,看看更新请求是否成功:

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

您将看到确认成功更新的输出:

1[secondary_label Output]
2** DRY RUN: simulating 'certbot renew' close to cert expiry
3**          (The test certificates below have not been saved.)
4
5Congratulations, all renewals succeeded. The following certs have been renewed:
6  /etc/letsencrypt/live/your_domain/fullchain.pem (success)
7** DRY RUN: simulating 'certbot renew' close to cert expiry
8**          (The test certificates above have not been saved.)
9- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

CTRL+C结束尾巴过程。

现在我们可以修改 crontab 文件,以便每周第二天上午 2 点运行脚本。

1[label crontab]
2...
3* 2 * * 2 /home/sammy/drupal/ssl_renew.sh >> /var/log/cron.log 2>&1

退出并保存文件。

现在,让我们从ssl_renew.sh脚本中删除--dry-run选项。

1nano ssl_renew.sh

然后将内容更改为如下:

1[label ~/drupal/ssl_renew.sh]
2#!/bin/bash
3
4cd /home/sammy/drupal/
5/usr/local/bin/docker-compose -f docker-compose.yml run certbot renew && \
6/usr/local/bin/docker-compose -f docker-compose.yml kill -s SIGHUP webserver

我们的cron工作现在将负责我们的SSL证书的到期,当他们有资格时更新它们。

结论

在本教程中,我们使用 Docker Compose 创建了使用 Nginx Web 服务器的 Drupal 安装,作为此工作流的一部分,我们获得了我们想要与 Drupal 网站相关联的域的 TLS/SSL 证书,并在需要时创建了一个 cron 工作来更新这些证书。

如果您想了解更多关于 Docker 的信息,请访问我们的 Docker 主题页面

Published At
Categories with 技术
comments powered by Disqus