为个人博客配置更好用的Nginx服务器
发表于 ,已有 16 条评论,总计 1746 次阅读 | 点我进行简繁转换

为个人博客配置更好用的Nginx服务器

发表于 | 已有 16 条评论,总计 1746 次阅读
一篇展示我是如何更好地使用 Nginx 服务器的伪教程。

在所有之前的

声明:本文展示了我个人站点的 Nginx 服务器的安装、设置和优化的过程以及一些相关的简要说明。本文内容会随时调整和更新,同时这是一篇具有大量主观想法的指导性文章,如果有疑问或持有不同意见,还望友善地留言,我会尽可能地和你一同讨论并学习。

本站的系统环境与配置

在本站建立之时,已经是“现代”互联网标准通行的时代。相关标准和技术,如 HTTP2/TLS1.3/Gzip 等已经趋于主流,HTTP3/QUIC/Brotli 等新标准新技术也已经被积极推行。这些都为我们带来了很多方便,如在 HTTP 时代,我们要为自己和用户之间传递的信息的安全担心,但在 HTTPS 时代,我们不用为其投入更多的精力,因为更安全的 TLS1.3 协议在为我们保驾护航。
我们现在有诸多更好更安全的新标准和新技术,本文接下来将简单地介绍如何在我们个人网站的 Nginx 上,去应用一些更加“现代”的东西。

本站现行的系统环境

截至 2020 年 5 月 29 日,本站的系统环境如下:

本站的一些系统配置

我修改了一些与内核及网络有关的配置参数以优化性能。

#为系统使用 Google 的 TCP BBR 拥塞控制算法(内核版本需 4.9.0 及以上)
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
#一些与网络有关的参数
net.core.netdev_max_backlog = 262144
net.core.somaxconn = 262144
net.ipv4.neigh.default.gc_stale_time = 120
net.ipv4.tcp_max_orphans = 262144
net.ipv4.tcp_max_syn_backlog = 262144
#一些与内核有关的参数
fs.file-max = 655350
kernel.msgmax = 65535
kernel.msgmnb = 65535
kernel.sysrq=1
vm.overcommit_memory = 1
vm.swappiness = 10
vm.vfs_cache_pressure = 50
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535

安装 Nginx 服务器

下文命令均以 Ubuntu 19.10 (APT) 为例,如你正使用过于老旧的 Ubuntu 或其他发行版或软件包管理器,请酌情更改到适当的命令。

通过软件源安装

我推荐个人用户通过软件源安装自己所需要的软件包,这样不仅能最大程度保证兼容性和稳定性。还能方便地使用包管理工具进行重安装、升级或卸载从软件源安装的软件包。通过源码进行编译安装对于不需要高度自定义的、技术和管理能力相对较弱的个人用户来说,只会让自己的文件分散得到处都是而不便于日后统一管理。

#使用 Ubuntu 官方源
apt update && apt install nginx-full -y
#这里我使用 https://launchpad.net/~eilander/+archive/ubuntu/nginx 提供的 Nginx Mainline 软件包,它提供更新的主线版本(官方源为 Stable 版本)
apt update && apt install software-properties-common -y
add-apt-repository ppa:eilander/nginx
apt update && apt install nginx-full -y

通过源码编译安装

这里只演示相对基本的 Nginx 编译安装方式,并为其启用了 HTTP/2 支持、添加了 OpenSSL 库使其支持 TLS 连接、添加了 ngx_brotli 模块使其支持 Brotli 压缩。如你需要更多自定义,可参看其官方文档

安装依赖与组件

这里默认操作用户为 root,操作目录为/usr/src

安装编译依赖
apt install build-essential git libpcre3 libpcre3-dev zlib1g-dev -y
获取必要组件
cd /usr/src
#获取 Nginx(截至 2020 年 5 月 29 日,Nginx 的主线版本为 1.19.0)
wget https://nginx.org/download/nginx-1.19.0.tar.gz
tar -fxvz nginx-1.19.0.tar.gz
#获取 OpenSSL
git clone https://github.com/openssl/openssl.git
#获取 ngx_brotli 模块
git clone https://github.com/google/ngx_brotli.git
cd ngx_brotli && git submodule update --init --recursive && cd ..

开始编译并安装

cd nginx-1.19.0
./configure --with-openssl=../openssl --with-openssl-opt=enable-tls1_3 --with-http_ssl_module --with-http_v2_module --add-module=../ngx_brotli
make && make install

注意:以上两种安装方式二选一即可。

为 Nginx 添加动态模块

这里以 ngx_brotli 模块为例,演示如何在已安装 Nginx 的情况下,为其动态地添加模块。

添加 ngx_brotli 模块

获取 ngx_brotli 模块

cd /usr/src
git clone https://github.com/google/ngx_brotli.git
cd ngx_brotli && git submodule update --init --recursive && cd ..

获取软件包源码

添加下载源
#编辑 /etc/apt/sources.list 添加或启用来自软件源的源码包
#这里使用 nano 编辑器,你也可以使用 vim 等其他编辑器
nano /etc/apt/sources.list
#如你使用官方软件源,需要添加以下行或删除其所在行的注释符`#`
deb-src http://archive.ubuntu.com/ubuntu eoan main restricted
deb-src http://archive.ubuntu.com/ubuntu eoan-updates main restricted
下载软件包源码
apt update && apt install build-essential cmake git libgd-dev libgeoip-dev libxslt-dev -y
apt source nginx-full

获取当前编译参数

使用nginx -V命令获取当前 Nginx 的编译参数,以下为示例:

root@localhost:/usr/src# nginx -V
nginx version: nginx/1.19.0
built with OpenSSL 1.1.1c  28 May 2019
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/usr/src/nginx-1.19.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-stream_ssl_preread_module --with-mail=dynamic --with-mail_ssl_module

编译 ngx_brotli 模块

进入 Nginx 源码目录并执行以下命令:

cd nginx-1.19.0
./configure --add-dynamic-module=../ngx_brotli \
#这里粘贴上文获取的当前 Nginx 的编译参数
--with-cc-opt='-g -O2 -fdebug-prefix-map=/usr/src/nginx-1.19.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-stream_ssl_preread_module --with-mail=dynamic --with-mail_ssl_module
make modules

加载 ngx_brotli 模块

执行make modules命令后,将在当前目录下的 objs 文件夹中生成ngx_http_brotli_filter_module.songx_http_brotli_static_module.so两个文件,将其复制出来即可。

#为区分版本,这里进行了重命名(路径不强制)
cp objs/ngx_http_brotli_filter_module.so /usr/lib/nginx/modules/ngx_http_brotli_filter_module_1.19.0.so
cp objs/ngx_http_brotli_static_module.so /usr/lib/nginx/modules/ngx_http_brotli_static_module_1.19.0.so

完成以上操作后,在 Nginx 配置文件的 Main 区中添加以下内容后重启 Nginx。

load_module /usr/lib/nginx/module/ngx_http_brotli_filter_module.so;
load_module /usr/lib/nginx/module/ngx_http_brotli_static_module.so;

有关load_module参数的相关信息可参见其官方文档

修改 Nginx 配置项

如你未使用我推荐的从软件源安装 Nginx 的 方式或未添加 ngx_brotli 模块,则下文所展示的配置需要你根据实际情况自行调整。

下文展示的配置可以正常实现的前提为:你从软件源安装了 nginx-full 软件包并已添加 ngx_brotli 模块、已获得 SSL 证书(推荐泛域名)。我使用的相对模块化的加载方式为不同的功能区进行了划分,如果你也喜欢这样,可以照做。

全局配置

Nginx 配置文件位于/etc/nginx/nginx.conf,以下是我的配置内容及一些相关说明:

#运行 Nginx 的用户(需要确保有足够的权限)
user                  nginx;
pid                   /run/nginx.pid;
worker_processes      auto;
worker_rlimit_nofile  65535;

include  /etc/nginx/modules-enabled/*.conf;

#加载编译的 ngx_brotli 模块
load_module  /usr/lib/nginx/module/ngx_http_brotli_filter_module.so;
load_module  /usr/lib/nginx/module/ngx_http_brotli_static_module.so;

events {
        accept_mutex        off;
        multi_accept        on;
        #epoll 是一个高版本 Linux 内核中的高性能模型
        use                 epoll;
        worker_connections  65535;
}

http {
        include  /etc/nginx/mime.types;

        #我将一些全站可以共用的配置放在了这里,因为使用了 CDN 网络,所以与连接持久化有关的参数均设置得较高
        client_header_buffer_size      4k;
        default_type                   application/octet-stream;
        keepalive_timeout              300s 300s;#你可以酌情降低此数值
        keepalive_requests             65535;
        send_timeout                   10s;
        sendfile                       on;
        tcp_nodelay                    on;
        tcp_nopush                     on;
        types_hash_max_size            2048;
        server_tokens                  off;
        server_names_hash_bucket_size  64;
        server_name_in_redirect        off;
        ssl_buffer_size                4k;
        #支持的 TLS 协议
        ssl_ciphers                    ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384;#本站仅支持现代的、更安全的浏览器
        #支持的 TLS 版本
        ssl_protocols                  TLSv1.2 TLSv1.3;#本站仅支持现代的、更安全的浏览器
        ssl_prefer_server_ciphers      on;
        ssl_session_cache              shared:SSL:10m;
        ssl_session_tickets            on;
        ssl_session_timeout            1d;#你可以酌情降低此数值
        #OCSP Stapling 参数,与下文站点配置中的 ssl_trusted_certificate 参数相关联
        ssl_stapling                   on;
        ssl_stapling_verify            on;

        #这里关闭了详细的访问日志,如需要可重新开启
        access_log  off;
        error_log   /var/log/nginx/error.log;

        brotli             on;
        brotli_buffers     32 4k;
        brotli_comp_level  11;
        brotli_min_length  32;
        brotli_static      on;
        brotli_types       text/css text/javascript text/mathml text/plain text/x-component text/xml text/vnd.wap.wml application/x-httpd-php image/svg+xml image/x-icon application/javascript application/x-javascript application/json application/xml application/atom+xml application/rss+xml application/xhtml+xml application/xspf+xml font/opentype application/x-font-ttf application/font-woff application/font-woff2 application/msword application/rtf application/x-cocoa application/x-makeself application/x-perl application/x-pilot application/x-tcl application/x-x509-ca-cert application/vnd.ms-excel application/vnd.ms-fontobject application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz image/vnd.microsoft.icon;
        brotli_window      1m;

        gzip               on;
        gzip_buffers       32 4k;
        gzip_comp_level    9;
        gzip_disable       "msie6";
        gzip_http_version  1.1;
        gzip_min_length    32;
        gzip_proxied       off;
        gzip_static        on;
        gzip_types         text/css text/javascript text/mathml text/plain text/x-component text/xml text/vnd.wap.wml application/x-httpd-php image/svg+xml image/x-icon application/javascript application/x-javascript application/json application/xml application/atom+xml application/rss+xml application/xhtml+xml application/xspf+xml font/opentype application/x-font-ttf application/font-woff application/font-woff2 application/msword application/rtf application/x-cocoa application/x-makeself application/x-perl application/x-pilot application/x-tcl application/x-x509-ca-cert application/vnd.ms-excel application/vnd.ms-fontobject application/vnd.google-earth.kml+xml application/vnd.google-earth.kmz image/vnd.microsoft.icon;
        gzip_vary          on;

        open_file_cache_errors    on;
        open_file_cache           max=65535 inactive=30s;
        open_file_cache_min_uses  2;
        open_file_cache_valid     30s;

        #这里引用外部的站点配置
        include  /path/to/sites/*.nginx;
}

站点配置

因我有数十个不同功能的子域名,所以为了方便及减小配置文件大小,我将 HTTP/HTTPS 的共用配置与站点的个体功能实现部分的配置进行了分离,

这里假设我有一example.com域名及数个三级子域,它们均将长期使用 HTTPS 协议,并将www.example.com作为目标域名,下面是配置示例。

HTTP 转发配置

#创建新文件:/path/to/sites/default.nginx
server {
    listen       80;
    server_name  example.com www.example.com;
    include      /path/to/sites/http-site.conf;

    rewrite ^ https://$http_host$request_uri? permanent;
}

server {
    listen       80 default;
    listen       443 ssl http2 default;
    server_name  _;#当直接通过 ip 访问时进行转发
    include      /path/to/sites/https-site.conf;

    rewrite ^ https://www.example.com permanent;
}

HTTP 全局配置

#创建新文件:/path/to/sites/http-site.conf
add_header  X-Content-Type-Options nosniff always;
add_header  X-Frame-Options "SAMEORIGIN" always;
add_header  X-Xss-Protection "1; mode=block" always;

HTTPS 全局配置

#创建新文件:/path/to/sites/https-site.conf
ssl_certificate          /path/to/ca/ssl_fullchain.crt;
ssl_certificate_key      /path/to/ca/ssl.key;
ssl_trusted_certificate  /path/to/ca/ssl_fullchain.crt;

add_header  Strict-Transport-Security "max-age=31536000; includeSubdomains; preload" always;#这是 HSTS 配置,不需要不加入,以免影响同域名的 HTTP 站点
add_header  X-Content-Type-Options nosniff always;
add_header  X-Frame-Options "SAMEORIGIN" always;
add_header  X-Xss-Protection "1; mode=block" always;

子域配置示例

#创建新文件:/path/to/sites/example.com.nginx
server {
    listen       443 ssl http2;
    server_name  example.com;
    include      /path/to/sites/https-site.conf;

    rewrite ^ https://www.example.com permanent;
}

server {
    listen       443 ssl http2;
    server_name  www.example.com;
    include      /path/to/sites/https-site.conf;

    #屏蔽一些无意义的蜘蛛
    if ($http_user_agent ~* "AdIdxBot|AhrefsBot|Bytespider|coccocbot|DotBot|EasouSpider|ia_archiver|iaskspider|MBCrawler|MJ12bot|MSNot-media|Semrush|Teoma|YandexBot|YisouSpider|^$") {
        return 444;
    }

    location / {
    root   /path/to/www;
    index  index.html;
    }
}
注:为了符合 HSTS Preload 的标准,需要先将example.com从 80 端口重定向至 443 端口后再重定向至其他子域的 443 端口。

加入 HSTS 预加载列表

HSTS 是国际互联网工程组织 IETE 正在推行一种新的 Web 安全协议,采用 HSTS 协议的网站可以确保浏览器始终连接到该网站的 HTTPS 加密版本,不需要用户手动在 URL 地址栏中输入加密地址。但单纯的 HSTS 有些许不足,它无法保证用户首次访问网站的安全性,即 HTTP 重定向至 HTTPS 的过程中可能被重定向至其他网站或 HSTS 标识头被篡改。
为了应对此情况,HSTS 预加载列表出现了。它被硬编码到浏览器中,列表中的站点将会默认使用 HTTPS 进行访问,提高了用户首次访问网站的安全性。

申请要求

响应头示例:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

开始申请

访问 HSTS Preload List Submission,在输入框中输入你的主域名,点击提交。它会显示提交状态。如显示错误按照提示更改后重新提交即可。
域名被硬编码到浏览器需要数周或数月,需要耐心等待。

为网站进行评分

分数总会给予人鼓舞,访问 MySSL,即可得到像下图一样的评分结果。

myssl-test.md.png


互联网技术变化得往往非常迅猛,这意味着本文具有较高的时效性,还望参考之时多加考量。

为个人博客配置更好用的Nginx服务器-二维码 本文二维码

评论已关闭
  1. 兄弟,你可以更新了,好久没动过了

    回复
    1. @Oasis

      大兄弟说谁🙄

      回复
  2. 兄弟,你可以更新了,好久没动过了

    回复
    1. @伍子蛇

      最近无事,好久不出门也没接触外面,实在是没有什么感触。
      更新也有的,比如一直在更正Wikipedia 全域恢复访问指南,也在回评论呀(正经脸

      回复
  3. 给跪了

    回复
  4. 我目前是 Centos,用着 oneinstack,有时间折腾一下😂😂😂😂😂

    回复
  5. 用宝塔的话就方便多了

    回复
    1. @青山

      你不明白,对于一个写代码的人来说,用宝塔真的太丢人了,失去了美感

      回复
    2. @青山

      宝塔仅仅是简单的“能用”,“一键 xx”的作用域很小,比如它不能为 Nginx 编译动态模块,很多进阶一些的配置仍要手动编辑。

      回复
      1. @安忆

        即将支持:编译安装时,可以手动添加编译模块。

        回复
        1. @暮山

          挺好的,不过都已经那样手动了,还有用它的必要了吗?

          回复
          1. @安忆

            有呀,毕竟宝塔的主业是网站和服务器的“可视化管理”,对于大多数非专业的站长(比如我)来说,是非常直接的。手动添加编译模块,这个功能是我提的建议,目前已经在测试版本中发布,算是锦上添花的功能。图形化用户界面,才是雪中送炭。

            回复
  6. Ubuntu 我一般都是用 LTS 版本的,更放心一些,非 LTS 版本的支撑太短了。

    回复