如何使用Docker Compose安装WordPress

WordPress是一个免费的开源内容管理系统(CMS),广泛用于推出新网站。运行WordPress通常需要手动安装LAMP或LEMP,使用Docker和Docker Compose等工具可以简化工作。本教程将向您展示如何使用Nginx反向代理设置多容器WordPress安装。它还将向您展示如何为您的应用程序域获取TLS / SSL证书。

介绍

WordPress是一个免费的开源内容管理系统(CMS),它建立在一个带有PHP处理的MySQL数据库上。 由于其可扩展的插件架构和模板系统,以及大部分管理都可以通过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的加密验证请求定向到Certbot客户端以进行自动证书续订。

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

mkdir wordpress && cd wordpress

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

mkdir nginx-conf

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

nano nginx-conf/nginx.conf

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

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

〜/ WordPress的/ nginx的-CONF / nginx.conf
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
  • indexindex指令定义在处理对服务器的请求时将用作索引的文件。 我们在这里修改了默认的优先级顺序,在index.html前面移动index.php ,以便Nginx在可能的情况下优先考虑名为index.php文件。
  • root :我们的root指令为我们服务器的请求命名根目录。 这个目录/var/www/html是在构建时通过我们的WordPress Dockerfile中的指令创建的挂载点 这些Dockerfile指令还确保将WordPress版本中的文件安装到此卷。

位置块:

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

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

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

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

第2步 - 定义环境变量

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

我们可以在.env文件中设置敏感值并限制其循环,而不是在Docker Compose文件中设置所有这些值 - 包含有关容器运行方式的信息的主文件。 这将防止这些值复制到我们的项目存储库并公开公开。

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

nano .env

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

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

〜/ WordPress的/ .ENV
MYSQL_ROOT_PASSWORD=your_root_password
MYSQL_USER=your_wordpress_database_user
MYSQL_PASSWORD=your_wordpress_database_password

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

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

由于.env文件包含敏感信息,因此您需要确保它包含在项目的.gitignore.dockerignore文件中,这些文件分别告诉Git和Docker哪些文件不会复制到Git存储库和Docker镜像。

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

git init

然后打开一个.gitignore文件:

nano .gitignore

.env添加到文件中:

〜/ WordPress的/的.gitignore
.env

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

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

打开文件:

nano .dockerignore

.env添加到文件中:

〜/ WordPress的/ .dockerignore
.env

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

〜/ WordPress的/ .dockerignore
.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数据库服务:

〜/ WordPress的/搬运工-compose.yml
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要创建容器的图像。 我们在这里固定mysql: 8.0图像 ,以避免将来的冲突,因为mysql:latest图像继续更新。 有关版本固定和避免依赖性冲突的更多信息,请参阅有关Dockerfile最佳实践的Docker文档。
  • container_name :指定container_name的名称。
  • restart :这定义了容器重启策略。 默认值为no ,但我们已将容器设置为重新启动,除非手动停止。
  • env_file :该选项告诉Compose我们想要从位于我们的构建上下文中的名为.env的文件中添加环境变量。 在这种情况下,构建上下文是我们当前的目录。
  • environment :此选项允许您添加除.env文件中定义的环境变量之外的其他环境变量。 我们将MYSQL_DATABASE变量设置为等于wordpress ,以便为我们的应用程序数据库提供名称。 因为这是非敏感信息,我们可以直接将它包含在docker-compose.yml文件中。
  • volumes :这里,我们将一个名为dbdata的命名 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的/搬运工-compose.yml
...
  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-alpine WordPress图像 第1步中所述 ,使用此图像可确保我们的应用程序将具有Nginx处理PHP处理所需的php-fpm处理器。 这也是一个来自Alpine Linux项目alpine图像,它将有助于保持我们的整体图像尺寸。 有关使用alpine图像的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_DATABASEwordpress的MySQL服务定义中指定的值相同。
  • volumes :我们正在将一个名为wordpress的命名卷挂载到由WordPress映像创建/var/www/html挂载点。 以这种方式使用命名卷将允许我们与其他容器共享我们的应用程序代码。
  • networks :我们还将wordpress容器添加到app-network网络。

接下来,在wordpress应用程序服务定义下面,为您的webserver Nginx服务添加以下定义:

〜/ WordPress的/搬运工-compose.yml
...
  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以启用我们在第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的加密证书和密钥挂载到容器上的相应目录。

我们再次将此容器添加到app-network网络。

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

〜/ WordPress的/搬运工-compose.yml
  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指定在运行webserver服务时应该启动certbot容器。

我们还包含一个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.comwww. example.com www. example.com 请务必将这些替换为您自己的域名。

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

〜/ WordPress的/搬运工-compose.yml
...
volumes:
  certbot-etc:
  wordpress:
  dbdata:

networks:
  app-network:
    driver: bridge  

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

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

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

〜/ WordPress的/搬运工-compose.yml
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命令启动我们的容器,该命令将按照我们指定的顺序创建和运行容器。 如果我们的域请求成功,我们将在输出中看到正确的退出状态,并在webserver容器的/etc/letsencrypt/live文件夹中安装正确的证书。

使用docker-compose up-d标志创建容器,它将在后台运行dbwordpresswebserver容器:

docker-compose up -d

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

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

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

docker-compose ps

如果一切都成功,您的dbwordpresswebserver服务将为Up ,并且certbot容器将退出并显示0状态消息:

  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           

如果您在dbwordpresswebserver服务的State列中看到除Up之外的任何内容,或者certbot容器的0以外的退出状态,请务必使用certbot docker-compose logs命令检查服务日志:

docker-compose logs service_name

您现在可以使用docker-compose exec检查您的证书是否已挂载到webserver容器:

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

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

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

既然您知道您的请求将成功,您可以编辑certbot服务定义以删除--staging标志。

打开docker-compose.yml

nano docker-compose.yml

使用certbot服务定义查找文件的部分,并使用--force-renewal标志替换command选项中的--staging标志,该标志将告知Certbot您要请求具有相同域的新证书。现有证书。 certbot服务定义现在看起来像这样:

〜/ WordPress的/搬运工-compose.yml
...
  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
...

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

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

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

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 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以包含这些添加项,因此您现在可以停止它:

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/options-ssl-nginx.conf 

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

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

rm nginx-conf/nginx.conf

打开该文件的另一个版本:

nano nginx-conf/nginx.conf

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

〜/ WordPress的/ nginx的-CONF / nginx.conf
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服务器块指定针对.well .well-known/acme-challenge目录的Certbot续订请求的webroot。 它还包括一个重写指令 ,用于将HTTP请求指向根目录到HTTPS。

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

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

此外,我们还提供了一些安全标头,使我们能够对SSL实验室安全标头服务器测试网站等内容进行评级。 这些标题包括X-Frame-OptionsX-Content-Type-OptionsReferrer PolicyContent-Security-PolicyX-XSS-Protection HTTP Strict Transport Security (HSTS)标头已注释掉 - 只有在您了解其含义并评估其“预加载”功能后才能启用此标头。

我们的rootindex指令也位于此块中, 第1步中讨论的其他WordPress特定位置块也是如此。

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

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

打开docker-compose.yml文件:

nano docker-compose.yml

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

〜/ WordPress的/搬运工-compose.yml
...
  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的/搬运工-compose.yml
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  

Save and close the file when you are finished editing.

Recreate the webserver service:

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

Check your services with docker-compose ps :

docker-compose ps

You should see output indicating that your db , wordpress , and webserver services are running:

  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    

With your containers running, you can now complete your WordPress installation through the web interface.

Step 6 — Completing the Installation Through the Web Interface

With our containers running, we can finish the installation through the WordPress web interface.

In your web browser, navigate to your server's domain. Remember to substitute example.com here with your own domain name:

https://example.com

Select the language you would like to use:

WordPress Language Selector

After clicking Continue , you will land on the main setup page, where you will need to pick a name for your site and a username. It's a good idea to choose a memorable username here (rather than "admin") and a strong password. You can use the password that WordPress generates automatically or create your own.

Finally, you will need to enter your email address and decide whether or not you want to discourage search engines from indexing your site:

WordPress Main Setup Page

Clicking on Install WordPress at the bottom of the page will take you to a login prompt:

WordPress Login Screen

Once logged in, you will have access to the WordPress administration dashboard:

WordPress Main Admin Dashboard

With your WordPress installation complete, you can now take steps to ensure that your SSL certificates will renew automatically.

Step 7 — Renewing Certificates

Let's Encrypt certificates are valid for 90 days, so you will want to set up an automated renewal process to ensure that they do not lapse. One way to do this is to create a job with the cron scheduling utility. In this case, we will create a cron job to periodically run a script that will renew our certificates and reload our Nginx configuration.

First, open a script called ssl_renew.sh :

nano ssl_renew.sh

Add the following code to the script to renew your certificates and reload your web server configuration. Remember to replace the example username here with your own non-root username:

~/wordpress/ssl_renew.sh
#!/bin/bash

COMPOSE="/usr/local/bin/docker-compose --no-ansi"

cd /home/sammy/wordpress/
$COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver

This script first assigns the docker-compose binary to a variable called COMPOSE , and specifies the --no-ansi option, which will run docker-compose commands without ANSI control characters . It then changes to the ~/wordpress project directory and runs the following docker-compose commands:

  • docker-compose run : This will start a certbot container and override the command provided in our certbot service definition. Instead of using the certonly subcommand, we're using the renew subcommand here, which will renew certificates that are close to expiring. We've included the --dry-run option here to test our script.
  • docker-compose kill : This will send a SIGHUP signal to the webserver container to reload the Nginx configuration. For more information on using this process to reload your Nginx configuration, please see this Docker blog post on deploying the official Nginx image with Docker .

Close the file when you are finished editing. Make it executable:

chmod +x ssl_renew.sh

Next, open your root crontab file to run the renewal script at a specified interval:

sudo crontab -e 

If this is your first time editing this file, you will be asked to choose an editor:

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]:
...

At the bottom of the file, add the following line:

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

This will set the job interval to every five minutes, so you can test whether or not your renewal request has worked as intended. We have also created a log file, cron.log , to record relevant output from the job.

After five minutes, check cron.log to see whether or not the renewal request has succeeded:

tail -f /var/log/cron.log

You should see output confirming a successful renewal:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
** 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.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

You can now modify the crontab file to set a daily interval. To run the script every day at noon, for example, you would modify the last line of the file to look like this:

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

You will also want to remove the --dry-run option from your ssl_renew.sh script:

~/wordpress/ssl_renew.sh
#!/bin/bash

COMPOSE="/usr/local/bin/docker-compose --no-ansi"

cd /home/sammy/wordpress/
$COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver

Your cron job will ensure that your Let's Encrypt certificates don't lapse by renewing them when they are eligible. You can also set up log rotation with the Logrotate utility to rotate and compress your log files.

结论

In this tutorial, you used Docker Compose to create a WordPress installation with an Nginx web server. As part of this workflow, you obtained TLS/SSL certificates for the domain you want associated with your WordPress site. Additionally, you created a cron job to renew these certificates when necessary.

As additional steps to improve site performance and redundancy, you can consult the following articles on delivering and backing up WordPress assets:

If you are interested in exploring a containerized workflow with Kubernetes, you can also check out: