Nginx编译安装kTLS QUIC Brotli服务

*升级系统内核

debian11的默认内核不支持kTLS,需要先升级内核。

安装编译依赖

1
2
$ apt -y update
$ apt -y install build-essential libncurses-dev libssl-dev libelf-dev bison bc flex

下载内核源码

1
2
3
4
$ cd /usr/local/src/
$ wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.3.6.tar.gz
$ tar -xvf linux-6.3.6.tar.gz
$ cd linux-6.3.6/

复制内核配置

1
$ cp /boot/config-$(uname -r) .config
  • /boot/config-$(uname -r):这部分表示获取当前正在运行的内核版本的配置文件的路径。/boot/config 是内核配置文件的默认存放位置,而 $(uname -r) 是一个命令替换,会被当前运行的内核版本号所替换。
  • .config:这部分表示目标文件的路径和名称,即复制到当前目录下的 .config 文件。

这条命令的作用是将当前正在运行的内核版本的配置文件复制到当前目录下的 .config 文件,以便后续可能需要使用该配置文件进行编译或其他操作。

生成默认配置

1
$ make olddefconfig

make olddefconfig 生成默认的配置文件。

从先前版本的内核升级到新版本时,内核配置文件可能会有一些新的选项或配置项。make olddefconfig 命令的目的是在保留现有配置的同时,将新的配置项设置为默认值。它会在当前目录下生成一个 .config 文件,其中包含默认配置。

这个目标通常在构建内核之前使用,以确保将新版本的内核配置为默认选项,同时保留您先前的配置设置。这样可以简化配置过程,尤其是当您从旧版本升级到新版本时,您可能不熟悉新版本的所有新选项。

配置内核选项

1
$ make menuconfig

make menuconfig 以文本菜单界面的形式配置内核选项。

构建内核时,可以使用 make menuconfig 命令来打开一个交互式的文本菜单界面。该界面允许您浏览和配置内核的各种选项,包括启用或禁用特定的功能、驱动程序和模块。

通过该菜单界面可以导航到各个配置类别,并对每个选项进行选择、启用或禁用。可以使用键盘导航键移动,按下空格键进行选择或取消选择,按下回车键确认更改。

make menuconfig 提供了一种相对友好和直观的方式来自定义内核配置,以满足特定需求。完成配置后,可以保存配置并继续构建内核。

开启kTLS主要启用内核以下设置:

  • Transport Layer Security HW offload

  • Transport Layer Security TCP stack bypass

设置流程如下

1

选择Networking Support

选择Networking options,空格键选择Transport Layer Security support选项,选择子选项Transport Layer Security HW offloadTransport Layer Security TCP stack bypass,然后Tab键选择Save保存退出

编译内核源码

1
$ make bindeb-pkg

make bindeb-pkg 是一个用于构建 Debian 软件包的 Makefile 目标。

使用 make bindeb-pkg 命令生成的 Debian 软件包是可安装的,可以方便地在 Debian 或基于 Debian 的发行版中进行安装和管理。生成的软件包通常包括内核映像、模块、头文件等相关组件。

这个命令会在构建过程中执行多个任务,如编译内核源代码、构建模块、生成相关文档等。最终生成的 Debian 软件包可用于在目标系统上安装和使用特定版本的内核。

编译出现异常信息

1
2
3
4
5
6
7
...
dpkg-source --before-build .
dpkg-checkbuilddeps: error: Unmet build dependencies: debhelper
dpkg-buildpackage: warning: build dependencies/conflicts unsatisfied; aborting
dpkg-buildpackage: warning: (Use -d flag to override.)
make[1]: *** [scripts/Makefile.package:114: bindeb-pkg] Error 3
make: *** [Makefile:1656: bindeb-pkg] Error 2

缺少依赖,需要安装相关软件,重新编译

1
2
3
$ apt install debhelper -y
$ apt install lz4 -y
$ apt install rsync -y

如果编译过程出现以下异常,需要重新配置内核选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
...
make -f ./Makefile ARCH=x86 KERNELRELEASE=6.3.3 KBUILD_BUILD_VERSION=3 olddefconfig all
#
# No change to .config
#
CALL scripts/checksyscalls.sh
DESCEND objtool
INSTALL libsubcmd_headers
make[6]: *** No rule to make target 'debian/certs/debian-uefi-certs.pem', needed by 'certs/x509_certificate_list'. Stop.
make[5]: *** [scripts/Makefile.build:494: certs] Error 2
make[4]: *** [Makefile:2025: .] Error 2
make[3]: *** [Makefile:357: __build_one_by_one] Error 2
make[2]: *** [debian/rules:8: build-arch] Error 2
dpkg-buildpackage: error: debian/rules binary subprocess returned exit status 2
make[1]: *** [scripts/Makefile.package:114: bindeb-pkg] Error 2
make: *** [Makefile:1656: bindeb-pkg] Error 2

重新打开内核配置界面make menuconfig,选择Cryptographic API选项

选择Certificates for signature checking选项

选择Additional X.509 keys for default system keyring

清空输入框中的debian/certs/debian-uefi-certs.pem,保存后重新执行编译

编译后的内核文件存放在/usr/local/src目录

1
2
3
4
5
6
7
8
9
root@example /usr/local/src # ll
total 246280
drwxrwxr-x 27 root root 4096 Jun 8 02:49 linux-6.3.6/
-rw-r--r-- 1 root root 219260231 Jun 5 07:39 linux-6.3.6.tar.gz
-rw-r--r-- 1 root root 8768384 Jun 8 02:05 linux-headers-6.3.6_6.3.6-8_amd64.deb
-rw-r--r-- 1 root root 22855436 Jun 8 02:05 linux-image-6.3.6_6.3.6-8_amd64.deb
-rw-r--r-- 1 root root 1283336 Jun 8 02:05 linux-libc-dev_6.3.6-8_amd64.deb
-rw-r--r-- 1 root root 6025 Jun 8 02:05 linux-upstream_6.3.6-8_amd64.buildinfo
-rw-r--r-- 1 root root 1766 Jun 8 02:05 linux-upstream_6.3.6-8_amd64.changes

安装内核文件

1
2
3
$ cd /usr/local/src/
$ apt install ./linux-image-6.3.6_6.3.6-8_amd64.deb
$ apt install ./linux-headers-6.3.6_6.3.6-8_amd64.deb

重启操作系统

1
$ reboot

验证

1
2
$ uname -a
Linux example.local 6.3.6 #8 SMP PREEMPT_DYNAMIC Thu Jun 8 02:04:36 UTC 2023 x86_64 GNU/Linux

加载tls模块

1
$ modprobe tls

如果要在系统启动的时候自动加载

1
$ echo 'tls' | tee /etc/modules-load.d/tls.conf

查看模块是否加载成功,如有类似回显说明正常:

1
2
$ lsmod | grep tls
tls 155648 0

编译Nginx

编译源码

nginx目前版本不支持kTLS,需要重新编译

nginx启用kTLS支持的configure命令中的两个关键选项是:

–with-openssl=../openssl

–with-openssl-opt=enable-ktls

其他configure选项用于官方nginx二进制包中包含的模块,这些模块可以在nginx.org上获取,也可以指定一组自定义模块。要查看当前nginx二进制文件使用的构建选项,请运行nginx -V。

QuicTLS编译
1
2
3
4
5
6
$ wget https://github.com/quictls/openssl/archive/refs/tags/openssl-3.0.9-quic1.tar.gz
$ tar -xzf openssl-3.0.9-quic1.tar.gz
$ mv openssl-openssl-3.0.9-quic1 openssl
$ cd openssl
$ ./config
$ make
Nginx编译

要使用openssl-3.0.9-quic构建nginx,请运行以下命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
$ cd /usr/local/src/
$ wget https://nginx.org/download/nginx-1.25.0.tar.gz
$ tar -xzf nginx-1.25.0.tar.gz
$ cd nginx-1.25.0
$ ./configure \
--with-debug \
--prefix=/usr/local \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--user=nginx \
--group=nginx \
--with-compat \
--with-file-aio \
--with-threads \
--with-http_addition_module \
--with-http_auth_request_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_mp4_module \
--with-http_random_index_module \
--with-http_realip_module \
--with-http_secure_link_module \
--with-http_slice_module \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_sub_module \
--with-http_v2_module \
--with-http_v3_module \
--with-mail \
--with-mail_ssl_module \
--with-stream \
--with-stream_realip_module \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-openssl=../openssl \
--with-openssl-opt=enable-ktls \
--with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC -I../openssl/build/include' \
--with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie -L/openssl/build/lib'
$ make -j4
$ make install

如果出现以下异常,请安装pcre模块

1
2
3
4
5
...
./configure: error: the HTTP rewrite module requires the PCRE library.
You can either disable the module by using --without-http_rewrite_module
option, or install the PCRE library into the system, or build the PCRE library
statically from the source with nginx by using --with-pcre=<path> option.

安装pcre

1
$ apt install libpcre3 libpcre3-dev -y
Brotli编译
克隆ngx_brotli
1
2
$ cd /usr/local/src/
$ git clone https://github.com/google/ngx_brotli.git

信息如下:

1
2
3
4
5
6
7
8
$ git clone https://github.com/google/ngx_brotli.git
Cloning into 'ngx_brotli'...
remote: Enumerating objects: 206, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 206 (delta 0), reused 2 (delta 0), pack-reused 203
Receiving objects: 100% (206/206), 74.99 KiB | 3.41 MiB/s, done.
Resolving deltas: 100% (90/90), done.
更新子模块
1
2
$ cd /usr/local/src/ngx_brotli
$ git submodule update --init

信息如下:

1
2
3
4
$ git submodule update --init
Submodule 'deps/brotli' (https://github.com/google/brotli.git) registered for path 'deps/brotli'
Cloning into '/usr/local/src/ngx_brotli/deps/brotli'...
Submodule path 'deps/brotli': checked out 'f4153a09f87cbb9c826d8fc12c74642bb2d879ea'
编译br模块
1
2
3
$ cd /usr/local/src/nginx-1.25.0
$ ./configure --with-compat --add-dynamic-module=/usr/local/src/ngx_brotli
$ make modules

信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
objs/ngx_http_brotli_filter_module_modules.o \
-lm \
-shared
cc -c -fPIC -pipe -O -W -Wall -Wpointer-arith -Wno-unused-parameter -Werror -g -Wno-deprecated-declarations -I src/core -I src/event -I src/event/modules -I src/os/unix -I /usr/local/src/ngx_brotli/deps/brotli/c/include -I objs -I src/http -I src/http/modules \
-o objs/addon/static/ngx_http_brotli_static_module.o \
/usr/local/src/ngx_brotli/static/ngx_http_brotli_static_module.c
cc -c -fPIC -pipe -O -W -Wall -Wpointer-arith -Wno-unused-parameter -Werror -g -Wno-deprecated-declarations -I src/core -I src/event -I src/event/modules -I src/os/unix -I /usr/local/src/ngx_brotli/deps/brotli/c/include -I objs -I src/http -I src/http/modules \
-o objs/ngx_http_brotli_static_module_modules.o \
objs/ngx_http_brotli_static_module_modules.c
cc -o objs/ngx_http_brotli_static_module.so \
objs/addon/static/ngx_http_brotli_static_module.o \
objs/ngx_http_brotli_static_module_modules.o \
-shared
make[1]: Leaving directory '/usr/local/src/nginx-1.25.0'

检查模块文件

1
2
3
$ ll objs/*.so
-rwxr-xr-x 1 root root 5572840 Jun 6 09:18 objs/ngx_http_brotli_filter_module.so*
-rwxr-xr-x 1 root root 72296 Jun 6 09:18 objs/ngx_http_brotli_static_module.so*

Nginx配置

配置kTLS

在nginx.conf文件的server模块添加ssl_conf_command配置

1
2
3
4
sendfile        on;
ssl_conf_command Options KTLS;
tcp_nopush on;
server_tokens off;
配置HTTP/3

在nginx.conf文件的server中添加http3配置

1
2
3
4
5
6
7
8
9
10
11
12
server {
# for better compatibility it's recommended
# to use the same port for http/3 and https
listen 443 quic reuseport;
listen 443 ssl;
add_header Alt-Svc 'h3=":443"; h3-27=":443"; ma=86400';
# 开启 TLS 1.3 0-RTT
ssl_early_data on;
# 添加 Early-Data 头告知后端, 防止重放攻击
proxy_set_header Early-Data $ssl_early_data;
}

配置Brotli

创建modules目录

1
$ mkdir /etc/nginx/modules

拷贝编译好的br模块到nginx模块目录

1
$ cp /usr/local/src/nginx-1.25.0/objs/*.so /etc/nginx/modules/.

编辑模块配置文件

1
$ vi /etc/nginx/modules.conf

写入br模块信息

1
2
3
# 加载br模块
load_module /etc/nginx/modules/ngx_http_brotli_filter_module.so;
load_module /etc/nginx/modules/ngx_http_brotli_static_module.so;

在nginx.conf文件中引入模块配置文件

1
2
3
pid        logs/nginx.pid;
# 引入模块配置文件
include modules.conf;

在nginx.conf的http模块中配置

1
2
3
4
5
6

brotli on;
brotli_comp_level 6;
brotli_static on;
brotli_types application/atom+xml application/javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype application/x-font-ttf application/x-javascript application/xhtml+xml application/xml font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml font/ttf font/woff font/woff2 image/jpeg image/gif image/png;

配置Gzip

在nginx.conf的http模块中配置

1
2
3
4
5
6
7
8
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_comp_level 3;
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/javascript application/json font/ttf font/otf image/svg+xml font/woff2 font/opentype font/x-woff;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;
gzip_static on;

验证Nginx

检查nginx信息

1
2
3
4
5
6
root@example /usr/local/src/nginx-1.25.0 # nginx -V
nginx version: nginx/1.25.0
built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
built with OpenSSL 3.0.9+quic 30 May 2023
TLS SNI support enabled
configure arguments: --with-debug --prefix=/usr/local --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_v3_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-openssl=../openssl --with-openssl-opt=enable-ktls --with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC -I../openssl/build/include' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie -L/openssl/build/lib'
验证kTLS

在nginx.conf开启error_log的debug模式

1
error_log  /var/log/nginx/error.log debug;

重启nginx后访问页面查看nginx日志

1
2
3
4
5
$ grep BIO /var/log/nginx/error.log
2023/06/08 18:46:18 [debug] 706861#706861: *1 BIO_get_ktls_send(): 1

$ grep SSL_sendfile /var/log/nginx/error.log

验证HTTP/3

访问HTTP/3 Check (http3check.net)

输入服务器域名验证,结果如下:

1
2
3
4
5
6
7
8
9
QUIC is supported
HTTP/3 is supported
HTTP/3 Check established a QUIC connection for all attempts made with the given endpoint. See the metrics below for more information.

0-RTT H3
CONNECTION ID PACKET RX HANDSHAKE DONE
B914EA4FD0... 8.775 10.54
19113485D7... 8.473 8.873
Read detailed descriptions of the items and metrics shown above.
验证Brotli

重启nginx访问nginx验证是否生效

1
$ curl -IL https://xxx.xxx -H "Accept-Encoding: gzip, br"

信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ curl -IL https://xxx.xxx -H "Accept-Encoding: gzip, br"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- 0:00:02 --:--:-- 0
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 06 Jun 2023 07:42:40 GMT
Content-Type: text/html
Last-Modified: Tue, 06 Jun 2023 06:08:32 GMT
Connection: keep-alive
Vary: Accept-Encoding
ETag: W/"647ecd60-b89"
Content-Encoding: br