背景

使用过 Nginx 的朋友应该都知道,Nginx 站点的配置文件需要根据程序类型、HTTPS 支持等等各类因素进行编写,如果每次创建站点都重新编写就很麻烦,并且配置文件的“个人规范”不够统一。

编写好完整的站点配置文件,下次建站时复制粘贴固然也能解决这个问题,但是如果 SSL 相关配置、安全配置、Gzip功能、调用 PHP-FPM 等代码都集于一个文件,那文件就会很长、不便于维护。实现配置模块化就是为了解决这个问题 or 满足自己的强迫症。

本教程基于 Debian 系统,如果你是根据“Debian 纯命令手动安装LEMP(LNMP)建站环境套件”这个教程安装的 Nginx 和 PHP,并且 Acme 的文件验证目录是 /www/acme 那么这个教程你基本可以照抄,如果你是自己安装的建站套件,需要对以下教程的操作进行理解并修正实际的文件路径。相关文章:

原理

将 Nginx 建站常用的功能代码(SSL 相关配置、安全配置、Gzip 功能、调用PHP、伪静态)保存为独立的配置文件,然后编写一个建站模板,通过注释、取消注释选择各种功能,设置域名、主目录路径等可变配置完成建站。

一、创建功能模板

1.创建适用于 acme.sh 的验证目录配置模板

nano /etc/nginx/acme.conf

写入代码:

# 申请SSL证书验证文件目录设置
location ^~ /.well-known/acme-challenge/ {
    # 默认MIME类型
    default_type "text/plain";
    # 验证文件目录
    root /www/acme;
}
保存并退出(保存:Ctrl+O | 退出:Ctrl+X)

2.创建 SSL 相关的配置模板

nano /etc/nginx/enable_ssl.conf

写入代码:

# SSL/TLS 协议
ssl_protocols TLSv1.3 TLSv1.2;
# 加密套件
ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:AES128-GCM-SHA256:!aNULL:!MD5:!DSS;
# 协商优先选择服务器端支持的加密套件
ssl_prefer_server_ciphers on;
# 设置用于缓存 SSL 会话信息的共享内存大小
ssl_session_cache shared:SSL:10m;
# 设置 SSL 会话缓存的超时时间
ssl_session_timeout 10m;
# 关闭 Session Ticket
ssl_session_tickets   off;

3.创建启用 PHP 的配置模板(根据 PHP 版本修改代码)

nano /etc/nginx/enable_php74.conf

写入代码:

location ~ [^/]\.php(/|$) {
    try_files $uri =404;
    fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

4.创建启用 PHP 并开启 pathinfo 支持的配置模板(根据 PHP 版本修改代码)

nano /etc/nginx/enable_php74_with_pathinfo.conf

写入代码:

location ~ [^/]\.php(/|$) {
    try_files $uri =404;
    fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;

    # 开启 pathinfo 支持
    set $real_script_name $fastcgi_script_name;
    if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
        set $real_script_name $1;
        set $path_info $2;
    }
    fastcgi_param SCRIPT_FILENAME $document_root$real_script_name;
    fastcgi_param SCRIPT_NAME $real_script_name;
    fastcgi_param PATH_INFO $path_info;
}

5.创建安全配置模板

nano /etc/nginx/security.conf

写入代码:

# 添加安全响应头
# 防止页面被嵌套到其他网站
add_header X-Frame-Options         SAMEORIGIN;
# 启用 XSS 过滤器(跨站脚本攻击防范 )
add_header X-XSS-Protection        "1; mode=block" always;
# 防止浏览器对响应内容进行嗅探
add_header X-Content-Type-Options    "nosniff" always;
# 禁止安全降级(HTTPS→HTTP)请求资源
add_header Referrer-Policy         "no-referrer-when-downgrade" always;

# 禁用目录列表
autoindex off;

# 安全配置-禁止访问敏感目录或文件
location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md) {
    return 404;
}
# 安全配置-禁止在证书验证目录放入敏感文件
if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {
    return 403;
}

6.创建通用的其它配置模板

nano /etc/nginx/general.conf

写入代码:

# 媒体静态资源设定
location ~ .*\.(jpg|jpeg|png|gif|ico|heic|webp|tiff|svg|mp3|m4a|aac|ogg|wav|mp4|mov|mpeg|avi|flv|wmv|webm|swf|pdf|txt|doc|docx|xls|xlsx|ppt|pptx|zip|rar|7z|woff|woff2)$ {
    # 添加响应头声明资源仅由客户端缓存,过期时间为 2592000 秒(30天)。
    add_header Cache-Control "private, max-age=2592000";
    # 将错误日志重定向到黑洞
    error_log /dev/null;
    # 将访问日志重定向到黑洞
    access_log /dev/null;
}
# 媒体静态资源设定
location ~ .*\.(js|css)?$ {
    # 添加响应头声明资源仅由客户端缓存,过期时间为 604800 秒(7天)。
    add_header Cache-Control "private, max-age=604800";
    # 将错误日志重定向到黑洞
    error_log /dev/null;
    # 将访问日志重定向到黑洞
    access_log /dev/null;
}
# 屏蔽不遵守Robot规则的垃圾蜘蛛
if ($http_user_agent ~* (DataForSeoBot|DotBot|AhrefsBot|BLEXBot|MJ12bot)) {
    return 404;
}

7.创建开启 Gzip 功能的配置模板

nano /etc/nginx/gzip.conf

写入代码:

# gzip 功能开关
gzip on;
# 启用应答头"Vary: Accept-Encoding"(声明数据经过了压缩处理)
gzip_vary on;
# 设定触发压缩的条件为无条件(做为反向代理的时候启用)
gzip_proxied any;
# gzip 压缩级别
gzip_comp_level 6;
# 设置需要压缩的MIME类型
gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;

8.创建各类网站程序专用的配置模板

(1)创建适用于 WordPress 的伪静态和安全配置模板

nano /etc/nginx/wordpress.conf

写入代码:

# WordPress伪静态配置
location /
{
     try_files $uri $uri/ /index.php?$args;
}

rewrite /wp-admin$ $scheme://$host$uri/ permanent;


# 匹配 xmlrpc.php 文件请求
location ~* ^/xmlrpc.php$ {
    # 拒绝所有访问
    deny all;
    # 返回403错误代码
    return 403;
    # 将错误日志重定向到黑洞
    error_log /dev/null;
    # 将访问日志重定向到黑洞
    access_log /dev/null;
}

# 匹配目录的 PHP 脚本请求
location ~* /(?:uploads|files|wp-content|wp-includes)/.*.php$ {
    # 拒绝所有访问
    deny all;
    # 将错误日志重定向到黑洞
    error_log /dev/null;
    # 将访问日志重定向到黑洞
    access_log /dev/null;
}

(2)创建适用于 Typecho 的伪静态和安全配置模板

nano /etc/nginx/typecho.conf

写入代码:

# Typecho 伪静态配置
if (-f $request_filename/index.html){
    rewrite (.*) $1/index.html break;
}
if (-f $request_filename/index.php){
    rewrite (.*) $1/index.php;
}
if (!-f $request_filename){
    rewrite (.*) /index.php;
}

(3)创建适用于 ThinkPHP 的伪静态和安全配置模板

nano /etc/nginx/thinkphp.conf

写入代码:

# 匹配 ThinkPHP 重要目录
location ~* (runtime|application)/{
    # 禁止访问-返回403错误
    return 403;
}

# ThinkPHP 伪静态配置
location / {
    # 如果文件不存在,保存当前请求的文件名
    if (!-e $request_filename){
        # 使用正则表达式将请求重写到 index.php 并附加查询参数,停止处理其他的 location 匹配,并将控制返回给 Nginx。
        rewrite  ^(.*)$  /index.php?s=$1  last;   break;
    }
}

二、创建通用的建站模板

1.特别说明

截至发文时间,Nginx 的最新稳定版为 1.24.x,以下模板也基于 1.24.x 版本;如果你使用 1.25.3 版本以上的 Nginx,需要修改建站模板中的部分代码,主要是修改监听端口部分用于开启 HTTP2 协议支持的代码。

查看已安装的 Nginx 版本:nginx -v

(1)适用于 Nginx 1.24 的配置:

    # 监听 IPv4 的 443 端口,开启 SSL 支持并启用 HTTP/2 协议
    listen        443 ssl http2;
    # 监听 IPv6 的 443 端口,开启 SSL 支持并启用 HTTP/2 协议
    #listen        [::]:443 ssl http2;

(2)适用于 Nginx 1.25.3 以上的配置:

    # 监听 IPv4 的 443 端口,开启 SSL 支持。
    listen        443 ssl;
    # 监听 IPv6 的 443 端口,开启 SSL 支持。
    #listen        [::]:443 ssl;
    # 启用 HTTP/2 协议
    http2        on;

2.创建用于申请证书的建站模板文件

nano /etc/nginx/sites-available/example_acme.conf

写入代码:

# HTTP
server {
    # 监听 IPv4 的 80 端口
    listen        80;
    # 监听 IPv6 的 80 端口
    #listen          [::]:80;
    # 绑定域名
    server_name    www.example.com example.com;

    # 引用安全配置模板
    include security.conf;

    # 引用适用于 acme.sh 的验证目录配置模板
    include acme.conf;

    # 关闭访问日志
    access_log  off;
    # 将错误日志写入黑洞
    error_log  /dev/null;
}

3.创建适用于单域名的建站模板文件

nano /etc/nginx/sites-available/example_single_name.conf

写入代码:

# HTTPS
server {
    # 监听 IPv4 的 443 端口,开启 SSL 支持并启用 HTTP/2 协议
    listen        443 ssl http2;
    # 监听 IPv6 的 443 端口,开启 SSL 支持并启用 HTTP/2 协议
    #listen        [::]:443 ssl http2;

    # 绑定域名
    server_name    www.example.com;
    # 站点根目录
    root        /www/wwwroot/www.example.com;
    # 默认文档
    index        index.php index.html;

    # SSL 证书路径
    ssl_certificate        /www/cert/www.example.com/fullchain.pem;
    # SSL 证书密钥路径
    ssl_certificate_key /www/cert/www.example.com/privkey.pem;

    # 引用 SLL 相关的配置模板
    include enable_ssl.conf;

    # 引用 PHP 7.4 配置模板
    #include enable_php74.conf;
    # 引用 PHP 7.4 配置模板(开启 pathinfo 支持)
    #include enable_php74_with_pathinfo.conf;

    # 引用适用于 WordPress 的伪静态和安全配置模板
    #include wordpress.conf;
    # 引用适用于 Typecho 的伪静态和安全配置模板
    #include typecho.conf;
    # 引用适用于 ThinkPHP 的伪静态和安全配置模板
    #include thinkphp.conf;

    # 引用安全配置模板
    include security.conf;

    # 告知浏览器始终通过 HTTPS 与网站建立连接(HSTS),HTTPS 最低有效期为一年。
    #add_header Strict-Transport-Security "max-age=31536000";

    # 引用通用的其它配置模板
    include general.conf;

    # 引用开启 Gzip 功能的配置模板
    include gzip.conf;

    # 访问日志文件
    access_log  /www/wwwlogs/www.example.com.access.log;
    # 错误日志文件和记录级别设定
    error_log  /www/wwwlogs/www.example.com.error.log warn;
}

# HTTP
server {
    # 监听 IPv4 的 80 端口
    listen        80;
    # 监听 IPv6 的 80 端口
    #listen          [::]:80;
    # 绑定域名
    server_name    www.example.com;

    # 匹配根目录全部请求
    location / {
        # 永久重定向到主站
        return 301    https://www.example.com$request_uri;
    }

    # 引用安全配置模板
    include security.conf;

    # 引用适用于 acme.sh 的验证目录配置模板
    include acme.conf;

    # 访问日志文件
    access_log  /www/wwwlogs/www.example.com.access.log;
    # 错误日志文件和记录级别设定
    error_log  /www/wwwlogs/www.example.com.error.log warn;
}

4.创建适用于双域名的建站模板文件

nano /etc/nginx/sites-available/example_double_name.conf

写入代码:

# HTTPS(WWW)
server {
    # 监听 IPv4 的 443 端口,开启 SSL 支持并启用 HTTP/2 协议
    listen        443 ssl http2;
    # 监听 IPv6 的 443 端口,开启 SSL 支持并启用 HTTP/2 协议
    #listen        [::]:443 ssl http2;

    # 绑定域名
    server_name    www.example.com;
    # 站点根目录
    root        /www/wwwroot/www.example.com;
    # 默认文档
    index        index.php index.html;

    # SSL 证书路径
    ssl_certificate        /www/cert/www.example.com/fullchain.pem;
    # SSL 证书密钥路径
    ssl_certificate_key /www/cert/www.example.com/privkey.pem;

    # 引用 SLL 相关的配置模板
    include enable_ssl.conf;

    # 引用 PHP 7.4 配置模板
    #include enable_php74.conf;
    # 引用 PHP 7.4 配置模板(开启 pathinfo 支持)
    #include enable_php74_with_pathinfo.conf;

    # 引用适用于 WordPress 的伪静态和安全配置模板
    #include wordpress.conf;
    # 引用适用于 Typecho 的伪静态和安全配置模板
    #include typecho.conf;
    # 引用适用于 ThinkPHP 的伪静态和安全配置模板
    #include thinkphp.conf;

    # 引用安全配置模板
    include security.conf;

    # 告知浏览器始终通过 HTTPS 与网站建立连接(HSTS),HTTPS 最低有效期为一年。
    #add_header Strict-Transport-Security "max-age=31536000";

    # 引用通用的其它配置模板
    include general.conf;

    # 引用开启 Gzip 功能的配置模板
    include gzip.conf;

    # 访问日志文件
    access_log  /www/wwwlogs/www.example.com.access.log;
    # 错误日志文件和记录级别设定
    error_log  /www/wwwlogs/www.example.com.error.log warn;
}

# HTTP(WWW)
server {
    # 监听 IPv4 的 80 端口
    listen        80;
    # 监听 IPv6 的 80 端口
    #listen          [::]:80;
    # 绑定域名
    server_name    www.example.com;

    # 匹配根目录全部请求
    location / {
        # 永久重定向到主站
        return 301    https://www.example.com$request_uri;
    }

    # 引用安全配置模板
    include security.conf;

    # 引用适用于 acme.sh 的验证目录配置模板
    include acme.conf;

    # 访问日志文件
    access_log  /www/wwwlogs/www.example.com.access.log;
    # 错误日志文件和记录级别设定
    error_log  /www/wwwlogs/www.example.com.error.log warn;
}

# HTTP & HTTPS(Non-WWW)
server {
    # 监听 IPv4 的 80 端口
    listen        80;
    # 监听 IPv6 的 80 端口
    #listen          [::]:80;
    # 监听 IPv4 的 443 端口,开启 SSL 支持并启用 HTTP/2 协议
    listen        443 ssl http2;
    # 监听 IPv6 的 443 端口,开启 SSL 支持并启用 HTTP/2 协议
    #listen        [::]:443 ssl http2;

    # 绑定域名
    server_name    example.com;

    # SSL 证书路径
    ssl_certificate        /www/cert/www.example.com/fullchain.pem;
    # SSL 证书密钥路径
    ssl_certificate_key /www/cert/www.example.com/privkey.pem;

    # 引用 SLL 相关的配置模板
    include enable_ssl.conf;

    # 匹配根目录全部请求
    location / {
        # 永久重定向到主站
        return 301    https://www.example.com$request_uri;
    }

    # 引用安全配置模板
    include security.conf;

    # 引用适用于 acme.sh 的验证目录配置模板
    include acme.conf;

    # 访问日志文件
    access_log  /www/wwwlogs/www.example.com.access.log;
    # 错误日志文件和记录级别设定
    error_log  /www/wwwlogs/www.example.com.error.log warn;
}

至此,Nginx 配置文件的模块化已经实现,如果以上步骤不包含你需要的特殊配置以及其它程序的专用配置,你可以根据以上教程自行添加。

三、创建站点的步骤

1.创建数据库(按需)

2.创建站点目录并上传网站文件

mkdir /www/wwwroot/www.abc.com

3.配置网站目录、文件的权限(按需)

4.复制用于申请证书的建站模板文件,使用主域名命名

cp /etc/nginx/sites-available/example_acme.conf /etc/nginx/sites-available/www.abc.com.conf

5.编辑复制的配置文件

nano /etc/nginx/sites-available/www.abc.com.conf

修改配置文件中的域名配置:

server_name     www.abc.com abc.com;

6.创建站点配置文件的软链接以启用站点

ln -s /etc/nginx/sites-available/www.abc.com.conf /etc/nginx/sites-enabled/www.abc.com.conf

7.测试 nginx 配置文件

nginx -t

8.重新加载 nginx 配置

systemctl reload nginx

9.使用 acme.sh 申请证书

单域名:acme.sh --issue -d www.abc.com --keylength ec-256 --webroot /www/acme

双域名:acme.sh --issue -d www.abc.com -d abc.com --keylength ec-256 --webroot /www/acme

10.创建用于存放站点证书的目录

mkdir -p /www/cert/www.abc.com/

11.安装证书到指定的目录

acme.sh --install-cert -d www.abc.com --ecc \
--key-file /www/cert/www.abc.com/privkey.pem \
--fullchain-file /www/cert/www.abc.com/fullchain.pem \
--ca-file /www/cert/www.abc.com/ca.pem \
--reloadcmd "systemctl force-reload nginx"

12.安装证书后,删除当前站点配置文件

rm /etc/nginx/sites-available/www.abc.com.conf

13.根据需求重新复制建站配置模板,使用主域名命名

单域名:cp /etc/nginx/sites-available/example_single_name.conf /etc/nginx/sites-available/www.abc.com.conf

双域名:cp /etc/nginx/sites-available/example_double_name.conf /etc/nginx/sites-available/www.abc.com.conf

14.编辑站点配置文件

nano /etc/nginx/sites-available/www.abc.com.conf

根据实际需求修改配置,例如:域名、站点根目录、证书目录、PHP 模式选择、网站程序专用配置模板引用、开关 HSTS 标头、日志文件路径修改、301跳转地址等等,下面的示例中,假设站点有两个域名,主要域名为:www.abc.com,次要域名为:abc.com,次要域名要实现自动跳转到主要域名,站点启用 HTTPS 支持并用于运行 WordPress。

# HTTPS(WWW)
server {
    # 监听 IPv4 的 443 端口,开启 SSL 支持并启用 HTTP/2 协议
    listen        443 ssl http2;
    # 监听 IPv6 的 443 端口,开启 SSL 支持并启用 HTTP/2 协议
    #listen        [::]:443 ssl http2;

    # 绑定域名
    server_name    www.abc.com;
    # 站点根目录
    root        /www/wwwroot/www.abc.com;
    # 默认文档
    index        index.php index.html;

    # SSL 证书路径
    ssl_certificate        /www/cert/www.abc.com/fullchain.pem;
    # SSL 证书密钥路径
    ssl_certificate_key /www/cert/www.abc.com/privkey.pem;

    # 引用 SLL 相关的配置模板
    include enable_ssl.conf;

    # 引用 PHP 7.4 配置模板
    include enable_php74.conf;
    # 引用 PHP 7.4 配置模板(开启 pathinfo 支持)
    #include enable_php74_with_pathinfo.conf;

    # 引用适用于 WordPress 的伪静态和安全配置模板
    include wordpress.conf;
    # 引用适用于 Typecho 的伪静态和安全配置模板
    #include typecho.conf;
    # 引用适用于 ThinkPHP 的伪静态和安全配置模板
    #include thinkphp.conf;

    # 引用安全配置模板
    include security.conf;

    # 告知浏览器始终通过 HTTPS 与网站建立连接(HSTS),HTTPS 最低有效期为一年。
    #add_header Strict-Transport-Security "max-age=31536000";

    # 引用通用的其它配置模板
    include general.conf;

    # 引用开启 Gzip 功能的配置模板
    include gzip.conf;

    # 访问日志文件
    access_log  /www/wwwlogs/www.abc.com.access.log;
    # 错误日志文件和记录级别设定
    error_log  /www/wwwlogs/www.abc.com.error.log warn;
}

# HTTP(WWW)
server {
    # 监听 IPv4 的 80 端口
    listen        80;
    # 监听 IPv6 的 80 端口
    #listen          [::]:80;
    # 绑定域名
    server_name    www.abc.com;

    # 匹配根目录全部请求
    location / {
        # 永久重定向到主站
        return 301    https://www.abc.com$request_uri;
    }

    # 引用安全配置模板
    include security.conf;

    # 引用适用于 acme.sh 的验证目录配置模板
    include acme.conf;

    # 访问日志文件
    access_log  /www/wwwlogs/www.abc.com.access.log;
    # 错误日志文件和记录级别设定
    error_log  /www/wwwlogs/www.abc.com.error.log warn;
}

# HTTP & HTTPS(Non-WWW)
server {
    # 监听 IPv4 的 80 端口
    listen        80;
    # 监听 IPv6 的 80 端口
    #listen          [::]:80;
    # 监听 IPv4 的 443 端口,开启 SSL 支持并启用 HTTP/2 协议
    listen        443 ssl http2;
    # 监听 IPv6 的 443 端口,开启 SSL 支持并启用 HTTP/2 协议
    #listen        [::]:443 ssl http2;

    # 绑定域名
    server_name    abc.com;

    # SSL 证书路径
    ssl_certificate        /www/cert/www.abc.com/fullchain.pem;
    # SSL 证书密钥路径
    ssl_certificate_key /www/cert/www.abc.com/privkey.pem;

    # 引用 SLL 相关的配置模板
    include enable_ssl.conf;

    # 匹配根目录全部请求
    location / {
        # 永久重定向到主站
        return 301    https://www.abc.com$request_uri;
    }

    # 引用安全配置模板
    include security.conf;

    # 引用适用于 acme.sh 的验证目录配置模板
    include acme.conf;

    # 访问日志文件
    access_log  /www/wwwlogs/www.abc.com.access.log;
    # 错误日志文件和记录级别设定
    error_log  /www/wwwlogs/www.abc.com.error.log warn;
}

15.测试 nginx 配置文件

nginx -t

16.重新加载 nginx 配置

systemctl reload nginx

最后

没有最后了,如果你有遇到什么问题或者有更好的建议,欢迎留言。

Last modification:December 30, 2023
If you think my article is useful to you, please feel free to appreciate