借助 NGINX Unit 在 Ubuntu 上自动安装 WordPress

WordPress 的安装方法数不胜数,在撰写本文之时,Google 搜索“WordPress 安装”的条目多达 488,000 条。虽然如此,但能够全面解释如何以支持长期维护的方式安装 WordPress 和底层操作系统的教程却寥寥无几。原因可能是正确的配置很大程度上取决于具体的需求,也可能是全面的安装教程无法通过简单几句话解释清楚。

在这篇文章中,我们将试着就此给出解决办法。我们提供了在 Ubuntu 上​​自动执行 WordPress 安装的 bash 脚本​​,并详细解释了各部分的作用以及我们的考量取舍。(如果您是一名高级用户,则可跳过这篇文章,​​直接进入脚本部分​​,下载并根据您的环境进行修改。)最终的 WordPress 安装文件是一份可编写脚本,支持 Let's Encrypt,使用 NGINX Unit,并已针对生产环境完成设置。

我们延续了​​上一篇博客​​中介绍的通过 NGINX Unit 部署 WordPress 的基本架构,另外还安装和配置了上一篇博客(或许多其他教程)中没有涵盖的特性:

  • WordPress CLI
  • Let’s Encrypt 和 TLS/SSL 证书
  • Let’s Encrypt 证书自动更新
  • NGINX 缓存
  • NGINX 压缩
  • NGINX HTTPS 和 HTTP/2
  • 流程自动化

本篇文章描述了在同时托管静态资源 Web 服务器、PHP 处理服务器和数据库的单个节点上设置 WordPress 的方法。未来,我们将介绍多主机、多服务的 WordPress 配置安装。您还希望我们讨论什么主题?请在文末评论区告诉我们!


前提条件

  • 计算实例:容器(​​LXC​​ 或 ​​LXD​​、虚拟机或裸机,至少具有 512 MB 可用内存,运行 Ubuntu 18.04 或更高版本
  • 计算实例的 80 和 443 端口向 Internet 开放
  • 已经与计算实例的公共 IP 地址相关联的域名
  • root 权限或通过 sudo 获取的同等访问权限

架构概述

应用架构为三层 Web 应用,与​​上一篇博客​​中描述的应用架构相同。其中包括必须由 PHP 处理器执行的 PHP 脚本和必须由 Web 服务器传递的静态文件。

借助 NGINX Unit 在 Ubuntu 上自动安装 WordPress_第1张图片


一般原则

  • 为了实现幂等,脚本中的许多配置命令都包含在条件语句(if 语句)中,:脚本可以多次运行,并且不会更改正确的设置。
  • 脚本首选通过存储库安装软件,以支持您通过单个命令(例如 Ubuntu 的apt upgrade)安装系统安全补丁。
  • 这些命令将检测其运行环境是否是容器,并相应地进行配置更改。
  • 当指定配置中运行的进程或线程数时,脚本会提供适用于容器、虚拟机或裸机的最佳自动配置参数(​​NGINX Unit 在第 278 行​​,​​NGINX 在第 306 行​​)。
  • 我们使用自动化为先的方法编写配置,希望可以为您创建自己的可重用基础架构即代码提供参考模型。
  • 所有命令都以 root 身份运行,因为它们更改了核心系统配置,但在运行时状态下,WordPress 以常规用户身份运行。

设置环境变量

请在运行脚本之前设置以下环境变量。

  • WORDPRESS_DB_PASSWORD – WordPress 数据库的密码。
  • WORDPRESS_ADMIN_USER – WordPress 管理员的用户名。
  • WORDPRESS_ADMIN_PASSWORD – WordPress 管理员的密码。
  • WORDPRESS_ADMIN_EMAIL – WordPress 管理员的电子邮件地址。
  • WORDPRESS_URL – WordPress 网站的完整 URL,以 https://开头。
  • LETS_ENCRYPT_STAGING – 默认为空,但如果使用 Lets Encrypt 暂存服务器,则设为 1,频繁测试新的部署配置时必需进行此操作。否则,Let’s Encrypt 可能会因请求数量过多而暂时拦截您的 IP 地址。

脚本将检查是否已设置与 WordPress 相关的变量,如果未设置,则退出(第 8–42 行,此处未显示)。​​第 572-576 行​​ 将检查LETS_ENCRYPT_STAGING 的值。


设置派生环境变量

脚本(第 55-61 行,此处未显示)将以下环境变量设置为硬编码值或上一节中设置的变量的派生值。

  • DEBIAN_FRONTEND="noninteractive" – 指示应用自动化脚本正在执行命令,无法进行用户交互。
  • WORDPRESS_CLI_VERSION="2.4.0" –WordPress CLI 的下载版本。
  • WORDPRESS_CLI_MD5= "dedd5a662b80cda66e9e25d44c23b25c" –WordPress CLI 2.4.0 二进制文件(WORDPRESS_CLI_VERSION 变量指定的版本)的加密校验和。​​第 162 行使用该值验证下载的 WordPress CLI 版本是否正确。​​
  • UPLOAD_MAX_FILESIZE="16M" –WordPress 支持上传的最大文件体积。此设置在配置中的多个位置使用,可以对其进行集中定义。
  • TLS_HOSTNAME= "$(echo ${WORDPRESS_URL} | cut -d'/' -f3)" –从 WORDPRESS_URL 变量中提取的系统可寻址主机名。用于从 Lets Encrypt 获取适当的 TLS/SSL 证书,以及 WordPress 自身的 ping 操作(请参见​​将 WordPress 网站主机名添加到 /etc/hosts)。​​
  • NGINX_CONF_DIR="/etc/nginx" –包含 NGINX 配置和主配置文件 nginx.conf 的目录路径。
  • CERT_DIR="/etc/letsencrypt/live/${TLS_HOSTNAME}" –WordPress 网站主机名(派生自 TLS_HOSTNAME 变量)Let’s Encrypt 证书的路径。

将 WordPress 网站主机名分配给计算实例

脚本将计算实例的主机名设置为与 WordPress 网站的域名相匹配。并非所有配置都需要进行此设置,但在单主机设置(如脚本配置的设置)中通过 SMTP 发送出站电子邮件时此设置将非常有帮助。

 63 # Change the hostname to be the same as the WordPress hostname
 64 if [ ! "$(hostname)" == "${TLS_HOSTNAME}" ]; then 
 65 echo "▶ Changing hostname to ${TLS_HOSTNAME}"
 66 hostnamectl set-hostname "${TLS_HOSTNAME}"
 67 fi

将 WordPress 网站主机名添加到 /etc/hosts

WordPress 使用 ​​WP-Cron​​ 插件运行计划任务,前提是 WordPress 可以通过 HTTP 进行 ping 操作。为了确保 WP-Cron 能够在所有环境中正常运行,脚本在 /etc/hosts 中添加了一个条目,从而让 WordPress 可以通过​​本地环回接口​​路由至自身。

 69 # Add the hostname to /etc/hosts
 70 if [ "$(grep -m1 "${TLS_HOSTNAME}" /etc/hosts)" = "" ]; then
 71 echo "▶ Adding hostname ${TLS_HOSTNAME} to /etc/hosts so that WordPress can ping itself"
 72 printf "::1 %s\n127.0.0.1 %s\n" "${TLS_HOSTNAME}" "${TLS_HOSTNAME}" >> /etc/hosts
 73 fi 

后续步骤所需的安装工具

后面的脚本部分将使用某些实用程序,并假定存储库索引已更新。我们更新存储库索引(第 77 行)并即刻安装所需工具(第 78-84 行)。

75 # Make sure tools needed for install are present
 76 echo "▶ Installing prerequisite tools"
 77 apt-get -qq update
 78 apt-get -qq install -y \
 79 bc \
 80 ca-certificates \
 81 coreutils \
 82 curl \
 83 gnupg2 \
 84 lsb-release

添加 NGINX Unit 和 NGINX 开源库

脚本通过 NGINX 官方存储库安装 NGINX Unit 和 NGINX 开源库,以确保我们始终拥有最新的安全更新和补丁修复程序。

此处,脚本通过为系统添加签名密钥并为 apt 配置(定义 Internet 上的存储库位置)添加文件来安装 NGINX Unit 库(第 87–91 行)和 NGINX 开源库(第 94–98 行)。

NGINX Unit 和 NGINX 开源库实际在​​下一部分​​才开始安装。为避免多次更新元数据,我们预先添加了存储库,加快了整体安装速度。

 86 # Install NGINX Unit repository
 87 if [ ! -f /etc/apt/sources.list.d/unit.list ]; then
 88 echo "▶ Installing NGINX Unit repository"
 89 curl -fsSL https://nginx.org/keys/nginx_signing.key | apt-key add -
 90 echo "deb https://packages.nginx.org/unit/ubuntu/ $(lsb_release -cs) unit" > /etc/apt/sources.list.d/unit.list
 91 fi
 92
 93 # Install NGINX repository
 94 if [ ! -f /etc/apt/sources.list.d/nginx.list ]; then
 95 echo "▶ Installing NGINX repository"
 96 curl -fsSL https://nginx.org/keys/nginx_signing.key | apt-key add -
 97 echo "deb https://nginx.org/packages/mainline/ubuntu $(lsb_release -cs) nginx" > /etc/apt/sources.list.d/nginx.list
 98 fi

安装 NGINX、NGINX Unit、PHP MariaDB、Certbot (Let’s Encrypt) 和依赖 (Dependencies)

安装完所有存储库后,我们将更新存储库元数据并安装应用。脚本安装的软件包包括运行 WordPress 时推荐的 ​​PHP 扩展插件​​。

100 echo "▶ Updating repository metadata"
101 apt-get -qq update
102

111 # Install PHP with dependencies and NGINX Unit
112 echo "▶ Installing PHP, NGINX Unit, NGINX, Certbot, and MariaDB"
113 apt-get -qq install -y --no-install-recommends \
114 certbot \
115 python3-certbot-nginx \
116 php-cli \
117 php-common \
118 php-bcmath \
119 php-curl \
120 php-gd \
121 php-imagick \
122 php-mbstring \
123 php-mysql \
124 php-opcache \
125 php-xml \
126 php-zip \
127 ghostscript \
128 nginx \
129 unit \
130 unit-php \
131 mariadb-server 

为 NGINX Unit 和 WordPress 配置 PHP

脚本在 PHP conf.d 目录(第 136-174 行)中创建一个配置文件。该文件设置了 PHP 上传文件的最大体积(第 142 行),将 PHP 错误定向到 STDERR(第 145 行),以便将它们记录在 NGINX Unit 日志中,及重启 NGINX Unit(第 151 行)。

133 # Find the major and minor PHP version so that we can write to its conf.d directory
134 PHP_MAJOR_MINOR_VERSION="$(php -v | head -n1 | cut -d' ' -f2 | cut -d'.'-f1,2)"
135
136 if [ ! -f "/etc/php/${PHP_MAJOR_MINOR_VERSION}/embed/conf.d/30-wordpress-overrides.ini" ]; then
137 echo "▶ Configuring PHP for use with NGINX Unit and WordPress"
138 # Add PHP configuration overrides
139 cat > "/etc/php/${PHP_MAJOR_MINOR_VERSION}/embed/conf.d/30-wordpress-overrides.ini" << EOM
140 ; Set a larger maximum upload size so that WordPress can handle
141 ; bigger media files.
142 upload_max_filesize=${UPLOAD_MAX_FILESIZE}
143 post_max_size=${UPLOAD_MAX_FILESIZE}
144 ; Write error log to STDERR so that error messages show up in the NGINX Unit log
145 error_log=/dev/stderr
146 EOM
147 fi
148
149 # Restart NGINX Unit because we have reconfigured PHP
150 echo "▶ Restarting NGINX Unit"
151 service unit restart

初始化 WordPress MariaDB 数据库

我们选择使用 MariaDB 而不是 MySQL 作为 WordPress 数据库。MariaDB 背后有一个更活跃的开源社区,可以说它能够提供​​更出色的开箱即用性能​​。

脚本初始化新数据库,并为 WordPress 创建凭证,以通过本地环回地址进行访问。

153 # Set up WordPress database
154 echo "▶ Configuring MariaDB for WordPress"
155 mysqladmin create wordpress || echo "Ignoring above error because database may already exist"
156 mysql -e "GRANT ALL PRIVILEGES ON wordpress.*TO \"wordpress\"@\"localhost\" IDENTIFIED BY \"$WORDPRESS_DB_PASSWORD\"; FLUSH PRIVILEGES;"

安装 WordPress CLI 实用程序

现在,脚本将安装 ​​WP-CLI 实用程序​​。使用该程序安装和管理 WordPress 可以让您完全控制 WordPress 配置,而无需手动修改文件,更新数据库或导航到 WordPress 管理员面板。 您还可以使用该程序安装主题或插件及升级 WordPress。

158 if [ ! -f /usr/local/bin/wp ]; then
159 # Install the WordPress CLI
160 echo "▶ Installing the WordPress CLI tool"
161 curl --retry 6 -Ls "https://github.com/wp-cli/wp-cli/releases/download/v${WORDPRESS_CLI_VERSION}/wp-cli-${WORDPRESS_CLI_VERSION}.phar" > /usr/local/bin/wp
162 echo "$WORDPRESS_CLI_MD5 /usr/local/bin/wp" | md5sum -c -
163 chmod +x /usr/local/bin/wp
164 fi

安装和配置 WordPress

脚本将最新版本的 WordPress 安装在 /var/www/wordpress 目录下,并进行以下设置:

  • 数据库通过 Unix 域套接字环回接口而不是 TCP 环回接口连接,以减少 TCP 通信量(第 175 行)。
  • 当客户端通过 HTTPS 连接到 NGINX 时,WordPress 将向 URL 添加 https:// 前缀,并将远程主机名(由 NGINX 提供)传递 给 PHP。我们为此配置使用一段 PHP 代码(第 180-189 行)。
  • WordPress 需要使用 HTTPS 进行登录(第 194 行)。
  • WordPress 的默认 URL 结构是资源型结构(第 201 行)。
  • 为 WordPress 目录设置正确的文件系统权限(第 207-210 行)。
166 if [ ! -d /var/www/wordpress ]; then
167 # Create WordPress directories
168 mkdir -p /var/www/wordpress
169 chown -R www-data:www-data /var/www
170
171 # Download WordPress using the WordPress CLI
172 echo "▶ Installing WordPress"
173 su -s /bin/sh -c 'wp --path=/var/www/wordpress core download' www-data
174
175 WP_CONFIG_CREATE_CMD="wp --path=/var/www/wordpress config create --extra-php --dbname=wordpress --dbuser=wordpress --dbhost=\"localhost:/var/run/mysqld/mysqld.sock\" --dbpass=\"${WORDPRESS_DB_PASSWORD}\""
176 
177 # This snippet is injected into the wp-config.php file when it is created.
178 # It informs WordPress that we are behind a reverse proxy and as such
179 # allow it to generate links using https.
180 cat > /tmp/wp_forwarded_for.php << 'EOM'
181 /* Turn HTTPS 'on' if HTTP_X_FORWARDED_PROTO matches 'https' */
182 if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) {
183 $_SERVER['HTTPS'] = 'on';
184 }
185
186 if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
187 $_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
188 }
189 EOM
190 
191 # Create WordPress configuration
192 su -s /bin/sh -p -c "cat /tmp/wp_forwarded_for.php | ${WP_CONFIG_CREATE_CMD}" www-data
193 rm /tmp/wp_forwarded_for.php
194 su -s /bin/sh -p -c "wp --path=/var/www/wordpress config set 'FORCE_SSL_ADMIN' 'true'" www-data
195
196 # Install WordPress
197 WP_SITE_INSTALL_CMD="wp --path=/var/www/wordpress core install --url=\"${WORDPRESS_URL}\" --title=\"${WORDPRESS_SITE_TITLE}\" --admin_user=\"${WORDPRESS_ADMIN_USER}\" --admin_password=\"${WORDPRESS_ADMIN_PASSWORD}\" --admin_email=\"${WORDPRESS_ADMIN_EMAIL}\" --skip-email"
198 su -s /bin/sh -p -c "${WP_SITE_INSTALL_CMD}" www-data
199
200 # Set permalink structure to a sensible default that isn't in the UI
201 su -s /bin/sh -p -c "wp --path=/var/www/wordpress option update permalink_structure '/%year%/%monthnum%/%postname%/'" www-data
202
203 # Remove sample file because it is cruft and could be a security problem
204 rm /var/www/wordpress/wp-config-sample.php
205
206 # Ensure that WordPress permissions are correct
207 find /var/www/wordpress -type d -exec chmod g+s {} \;
208 chmod g+w /var/www/wordpress/wp-content
209 chmod -R g+w /var/www/wordpress/wp-content/themes
210 chmod -R g+w /var/www/wordpress/wp-content/plugins
211 fi

配置 NGINX Unit

脚本将 NGINX Unit 配置为运行 PHP 和处理 WordPress 路径、隔离 PHP 进程命名空间,并调谐性能设置。以下三个特性需要注意:

  1. 命名空间支持根据脚本是否正在容器中运行有条件地进行定义(第 213-224 行)。必需采用这种定义方式,原因是大多数容器配置都不支持在其内部运行其他容器。

2. 启用命名空间支持后,network 命名空间将被禁用(第 218 行)。要支持 WordPress 访问自己的端点并连接 Internet 必需禁用 network 命名空间。

3. 使用以下算法计算最大进程数(第 226-228 行):(运行 MariaDB 和 NGINX Unit 的可用内存)/(PHP 内存限制 + 5)。然后在第 277-280 行的 NGINX Unit 配置中设置该值。

此值可确保始终至少有两个 PHP 进程在运行,这一点很重要,因为 WordPress 自身会进行多次异步调用,并且如果没有其他进程运行,WP-Cron 等操作将会失败。由于此处生成的设置是保守设置,因此您可能需要根据特定的 WordPress 配置增减此设置。许多生产系统设置通常在 10 到 100 之间。

213 if [ "${container:-unknown}" != "lxc" ] && [ "$(grep -m1 -a container=lxc /proc/1/environ | tr -d '\0')" == "" ]; then
214 NAMESPACES='"namespaces": {
215 "cgroup": true,
216 "credential": true,
217 "mount": true,
218 "network": false,
219 "pid": true,
220 "uname": true
221 }'
222 else
223 NAMESPACES='"namespaces": {}'
224 fi
225
226 PHP_MEM_LIMIT="$(grep 'memory_limit' /etc/php/7.4/embed/php.ini | tr -d ' ' | cut -f2 -d= | numfmt --from=iec)"
227 AVAIL_MEM="$(grep MemAvailable /proc/meminfo | tr -d ' kB' | cut -f2 -d: | numfmt --from-unit=K)"
228 MAX_PHP_PROCESSES="$(echo "${AVAIL_MEM}/${PHP_MEM_LIMIT}+5" | bc)"
229 echo "▶ Calculated the maximum number of PHP processes as ${MAX_PHP_PROCESSES}.You may want to tune this value due to variations in your configuration.It is not unusual to see values between 10-100 in production configurations." 
230 
231 echo "▶ Configuring NGINX Unit to use PHP and WordPress"
232 cat > /tmp/wordpress.json << EOM
233 {
234 "settings": {
235 "http": {
236 "header_read_timeout": 30,
237 "body_read_timeout": 30,
238 "send_timeout": 30,
239 "idle_timeout": 180,
240 "max_body_size": $(numfmt --from=iec ${UPLOAD_MAX_FILESIZE})
241 }
242 },
243 "listeners": {
244 "127.0.0.1:8080": {
245 "pass": "routes/wordpress"
246 }
247 },
248 "routes": {
249 "wordpress": [
250 {
251 "match": {
252 "uri": [
253 "*.php",
254 "*.php/*",
255 "/wp-admin/"
255  ]
257 },
258 "action": {
259 "pass": "applications/wordpress/direct"
260 }
261 },
262 {
263 "action": {
264 "share": "/var/www/wordpress",
265 "fallback": {
266 "pass": "applications/wordpress/index"
267 }
268 }
269 }
270 ]
271 },
272 "applications": {
273 "wordpress": {
274 "type": "php",
275 "user": "www-data",
276 "group": "www-data",
277 "processes": {
278 "max": ${MAX_PHP_PROCESSES},
279 "spare": 1
280 },
281  "isolation": {
282 ${NAMESPACES}
283 },
284 "targets": {
285 "direct": {
286 "root": "/var/www/wordpress/"
287 },
288 "index": {
289 "root": "/var/www/wordpress/",
290 "script": "index.php"
291 }
292 }
293 }
294 }
295 }
296 EOM
297 
298 curl -X PUT --data-binary @/tmp/wordpress.json --unix-socket /run/control.unit.sock http://localhost/config 

配置 NGINX

  • ​​配置核心 NGINX 参数​​
  • ​​配置 NGINX 压缩设置​​
  • ​​为 WordPress 配置 NGINX 参数​​

配置核心 NGINX 参数

该脚本为 NGINX 缓存目录创建了一个目录(第 301 行),并创建了 NGINX nginx.conf 主配置文件(第 304–341 行)。配置设置中包括 NGINX 工作进程数(第 306 行)和上传文件的最大体积(第 325 行)。第 329 行导入了​​下一部分​​中定义的压缩配置,第 332–337 行设置了缓存参数。

300 # Make directory for NGINX cache
301 mkdir -p /var/cache/nginx/proxy
302 
303 echo "▶ Configuring NGINX"
304 cat > ${NGINX_CONF_DIR}/nginx.conf << EOM
305 user nginx;
306 worker_processes auto;
307
308 error_log /var/log/nginx/error.log warn;
309 pid /var/run/nginx.pid;
310
311 events {
312 worker_connections 1024;
313 }
314
315 http {
316 include ${NGINX_CONF_DIR}/mime.types;
317 default_type application/octet-stream;
318
319 log_format main '\$remote_addr - \$remote_user [\$time_local] "\$request" '
320 '\$status \$body_bytes_sent "\$http_referer" '
321 '"\$http_user_agent" "\$http_x_forwarded_for"';
322
323 access_log /var/log/nginx/access.log main;
324 sendfile on;
325 client_max_body_size ${UPLOAD_MAX_FILESIZE};
326 keepalive_timeout 65;
327
328 # GZIP settings
329 include ${NGINX_CONF_DIR}/gzip_compression.conf;
330
331 # Cache settings
332 proxy_cache_path /var/cache/nginx/proxy
333 levels=1:2
334 keys_zone=wp_cache:10m
335 max_size=10g
336 inactive=60m
337 use_temp_path=off;
338
339 include ${NGINX_CONF_DIR}/conf.d/*.conf;
340 }
341 EOM

配置 NGINX 压缩设置

在将内容发送给客户端之前动态压缩内容能够有效提高网站性能,但前提是压缩配置正确无误。脚本使用 GitHub 上 ​​h5bp 存储库​​ 中的配置(第 346–414 行)。

343 cat > ${NGINX_CONF_DIR}/gzip_compression.conf << 'EOM'
344 # Credit: https://github.com/h5bp/server-configs-nginx/
345
346 # ----------------------------------------------------------------------
347 # | Compression |
348 # ----------------------------------------------------------------------
349 
350 # https://nginx.org/en/docs/http/ngx_http_gzip_module.html
351 
352 # Enable gzip compression.
353 # Default: off
354 gzip on;
355
356 # Compression level (1-9).
357 # 5 is a perfect compromise between size and CPU usage, offering about 75%
358 # reduction for most ASCII files (almost identical to level 9).
359 # Default: 1
360 gzip_comp_level 6;
361
362 # Don't compress anything that's already small and unlikely to shrink much if at
363 # all (the default is 20 bytes, which is bad as that usually leads to larger
364 # files after gzipping).
365 # Default: 20
366 gzip_min_length 256;
367
368 # Compress data even for clients that are connecting to us via proxies,
369 # identified by the "Via" header (required for CloudFront).
370 # Default: off
371 gzip_proxied any;
372
373 # Tell proxies to cache both the gzipped and regular version of a resource
374 # whenever the client's Accept-Encoding capabilities header varies;
375 # Avoids the issue where a non-gzip capable client (which is extremely rare
376 # today) would display gibberish if their proxy gave them the gzipped version.
377 # Default: off
378 gzip_vary on;
379
380 # Compress all output labeled with one of the following MIME-types.
381 # `text/html` is always compressed by gzip module.
382 # Default: text/html
383 gzip_types
384 application/atom+xml
385 application/geo+json
386 application/javascript
387 application/x-javascript
388 application/json
389 application/ld+json
390 application/manifest+json
391 application/rdf+xml
392 application/rss+xml
393 application/vnd.ms-fontobject
394 application/wasm
395 application/x-web-app-manifest+json
396 application/xhtml+xml
397 application/xml
398 font/eot
399 font/otf
400 font/ttf
401 image/bmp
402 image/svg+xml
403 text/cache-manifest
404 text/calendar
405 text/css
406 text/javascript
407 text/markdown
408 text/plain
409 text/xml
410 text/vcard
411 text/vnd.rim.location.xloc
412 text/vtt
413 text/x-component
414 text/x-cross-domain-policy;
415 EOM

为 WordPress 配置 NGINX 参数

接下来,脚本在 conf.d 目录下创建一个名为 default.conf 的 NGINX 配置文件,并设置 WordPress(第 417–541 行)。配置如下:

  • 启用通过 Certbot 从 Let's Encrypt 获得的 TLS 证书(第 445-447 行;有关 Certbot 的配置问题,请参见​​下一部分​​)。
  • 实施由 Let's Encrypt 定义为最佳实践的 TLS 安全设置(第 449-454 行)
  • 默认情况下,启用代理请求的缓存时间为 1 小时(第 458 行)
  • 禁用两个常见请求文件 favicon.ico 和 robots.txt 的访问日志记录,以及在找不到资产时的错误日志记录(第 465-474 行)
  • 拒绝访问隐藏文件和某些 .php 文件,以防止非法访问或无意执行(第 476–500 行)
  • 禁用静态文件内容和字体文件的访问日志记录(第 503-510 行)
  • 设置字体文件的 ​​Access-Control-Allow-Origin header​​(第 508 行)
  • 将路由设置应用于 index.php 文件和其他静态文件(第 512–539 行)
417 cat > ${NGINX_CONF_DIR}/conf.d/default.conf << EOM
418 upstream unit_php_upstream {
419 server 127.0.0.1:8080;
420 
421 keepalive 32;
422 }
423
424 server {
425 listen 80;
426 listen [::]:80;
427
428 # ACME-challenge used by Certbot for Let's Encrypt
429 location ^~ /.well-known/acme-challenge/ {
430 root /var/www/certbot;
431 }
432 
433 location / {
434 return 301 https://${TLS_HOSTNAME}\$request_uri;
435 }
436 }
437
438 server {
439 listen 443 ssl http2;
440 listen [::]:443 ssl http2;
441 server_name ${TLS_HOSTNAME};
442 root /var/www/wordpress/;
443 
444 # Let's Encrypt configuration
445 ssl_certificate ${CERT_DIR}/fullchain.pem;
446 ssl_certificate_key ${CERT_DIR}/privkey.pem;
447 ssl_trusted_certificate ${CERT_DIR}/chain.pem;
448
449 include ${NGINX_CONF_DIR}/options-ssl-nginx.conf;
450 ssl_dhparam ${NGINX_CONF_DIR}/ssl-dhparams.pem;
451
452 # OCSP stapling
453 ssl_stapling on;
454 ssl_stapling_verify on;
455
456 # Proxy caching
457 proxy_cache wp_cache;
458 proxy_cache_valid 200 302 1h;
459 proxy_cache_valid 404 1m;
460 proxy_cache_revalidate on;
461 proxy_cache_background_update on; 
462 proxy_cache_lock on;
463 proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
464
465 location = /favicon.ico { 
466 log_not_found off;
467 access_log off;
468 }
469 
470 location = /robots.txt {
471 allow all;
472 log_not_found off;
473 access_log off;
474 }
475 
476 # Deny all attempts to access hidden files such as .htaccess, .htpasswd, 
477 # .DS_Store (Mac).
478 # Keep logging the requests to parse later (or to pass to firewall utilities 
479 # such as fail2ban).
480 location ~ /\.{
481 deny all;
482 }
483 
484 # Deny access to any files with a .php extension in the uploads directory.
485 # Works in sub-directory installs and also in multi-site network;
486 # Keep logging the requests to parse later (or to pass to firewall utilities 
487 # such as fail2ban).
488 location ~* /(?:uploads|files)/.*\.php\$ {
489 deny all;
490  }
491
492 # WordPress: deny wp-content, wp-includes php files
493 location ~* ^/(?:wp-content|wp-includes)/.*\.php\$ {
494 deny all;
495 }
496 
497 # Deny public access to wp-config.php
498 location ~* wp-config.php {
499 deny all;
500 }
501 
502 # Do not log access for static assets, media
503 location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ {
504 access_log off;
505 }
506 
507 location ~* \.(?:svgz?|ttf|ttc|otf|eot|woff2?)$ {
508 add_header Access-Control-Allow-Origin "*";
509 access_log off;
510 }
511
512 location / {
513 try_files \$uri @index_php;
514 }
515 
516 location @index_php {
517 proxy_socket_keepalive on;
518 proxy_http_version 1.1;
519 proxy_set_header Connection "";
520 proxy_set_header X-Real-IP \$remote_addr;
521 proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
522 proxy_set_header X-Forwarded-Proto \$scheme;
523 proxy_set_header Host \$host;
524 
525 proxy_pass http://unit_php_upstream;
526 }
527 
528 location ~* \.php\$ {
529  proxy_socket_keepalive on;
530 proxy_http_version 1.1;
531 proxy_set_header Connection "";
532 proxy_set_header X-Real-IP \$remote_addr;
533 proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
534 proxy_set_header X-Forwarded-Proto \$scheme;
535 proxy_set_header Host \$host;
536 
537 try_files \$uri =404;
538 proxy_pass http://unit_php_upstream;
539 }
540 }
541 EOM

配置 Certbot 以处理 Let’s Encrypt 证书和自动更新

​​Certbot​​ 是电子前沿基金会 (EFF) 推出的一款免费工具,可从 Let's Encrypt 获取并自动更新 TLS 证书。脚本将执行以下操作,配置 Certbot 为 NGINX 处理Let's Encrypt 证书:

  1. 关闭 NGINX(第 544 行)

2. 使用当前推荐的设置下载 TLS 参数(第 550–564 行)

3. 运行 Certbot 为站点检索 TLS 证书(第 578–585 行)

4. 重启 NGINX 以使用 TLS 证书(第 588 行)

5. 将 Certbot 配置为每天凌晨 3:24 运行,并检查是否需要更新 TLS 证书;如果需要更新,则将下载新的证书并重新加载 NGINX(第 591-594 行)

543 echo "▶ Stopping NGINX in order to set up Let's Encrypt"
544 service nginx stop
545 
546 mkdir -p /var/www/certbot
547 chown www-data:www-data /var/www/certbot
548 chmod g+s /var/www/certbot
549 
550 if [ ! -f ${NGINX_CONF_DIR}/options-ssl-nginx.conf ]; then
551 echo "▶ Downloading recommended TLS parameters"
552 curl --retry 6 -Ls -z "Tue, 14 Apr 2020 16:36:07 GMT" \
553 -o "${NGINX_CONF_DIR}/options-ssl-nginx.conf" \
554 "https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf" \
555 || echo "Couldn't download latest options-ssl-nginx.conf"
556 fi
557
558 if [ ! -f ${NGINX_CONF_DIR}/ssl-dhparams.pem ]; then
559 echo "▶ Downloading recommended TLS DH parameters"
560 curl --retry 6 -Ls -z "Tue, 14 Apr 2020 16:49:18 GMT" \
561 -o "${NGINX_CONF_DIR}/ssl-dhparams.pem" \
562 "https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem" \
563  || echo "Couldn't download latest ssl-dhparams.pem"
564 fi
565
566 # If tls_certs_init.sh hasn't been run before, let's remove the self-signed certs
567 if [ ! -d "/etc/letsencrypt/accounts" ]; then
568 echo "▶ Removing self-signed certificates"
569  rm -rf "${CERT_DIR}"
570 fi
571
572 if [ "" = "${LETS_ENCRYPT_STAGING:-}" ] || [ "0" = "${LETS_ENCRYPT_STAGING}" ]; then
573 CERTBOT_STAGING_FLAG=""
574 else
575 CERTBOT_STAGING_FLAG="--staging"
576 fi
577
578 if [ ! -f "${CERT_DIR}/fullchain.pem" ]; then
579 echo "▶ Generating certificates with Let's Encrypt"
580 certbot certonly --standalone \
581 -m "${WORDPRESS_ADMIN_EMAIL}" \
582 ${CERTBOT_STAGING_FLAG} \
583 --agree-tos --force-renewal --non-interactive \
584 -d "${TLS_HOSTNAME}"
585 fi
586 
587 echo "▶ Starting NGINX in order to use new configuration"
588 service nginx start
589
590 # Write crontab for periodic Let's Encrypt cert renewal
591 if [ "$(crontab -l | grep -m1 'certbot renew')" == "" ]; then
592 echo "▶ Adding certbot to crontab for automatic Let's Encrypt renewal"
593 (crontab -l 2>/dev/null; echo "24 3 * * * certbot renew --dry-run --nginx --post-hook 'service nginx reload'") | crontab -
594 fi

自定义您的 WordPress 网站

以上为您介绍了我们的 bash 脚本如何配置 NGINX 开源版和 NGINX Unit,以托管一个启用 TLS/SSL 的生产就绪型网站。您可能想要根据自己的需求进一步定制您的网站:

  • 启用 ​​Brotli​​, 获得更佳的 HTTPS 动态压缩性能
  • 安装带有 ​​WordPress 规则​​的 ​​ModSecurity​​,以防止网站遭受自动化攻击
  • 根据自己的需求,为 WordPress ​​设置备份程序​​
  • 使用(Ubuntu 中的)​​AppArmor​​​​保护您的 WordPress 安装​​
  • 安装 ​​postfix​​ 或 ​​msmtp​​,以支持 WordPress 发送出站电子邮件
  • 对您的网站进行基准测试,了解它可以支持多少流量

为了获得更出色的网站性能,建议您升级到我们基于 NGINX 开源版的企业级商业支持产品 NGINX Plus。NGINX Plus 用户可享受动态加载的 ​​Brotli 模块​​和 ​​NGINX ModSecurity WAF​​(需额外付费)。我们还为您提供了基于 F5 业界领先安全技术的 NGINX Plus WAF 模块 ​​NGINX App Protect​​。


更多资源

想要更及时全面地获取NGINX相关的技术干货、互动问答、系列课程、活动资源?请前往​​NGINX开源社区​​官方网站 。

你可能感兴趣的:(nginx)