前言

最近把 OnePlus 6 刷成了 postmarketOS(Alpine Linux),并在上面跑 Navidrome 音乐服务。
为了提升访问速度、降低延迟,我决定在 Nginx 上 启用 HTTP/3(QUIC)


环境与目标

设备环境:

  • OnePlus 6(enchilada)
  • postmarketOS edge(Alpine 3.x)
  • 使用 apk 自带的 Nginx 做基础反代(无 HTTP/3 模块)
  • 后端服务:Navidrome 0.53+
  • 无 UDP 硬件 offload 的 Wi-Fi 芯片(意味着 QUIC 性能有限)

目标:

✔️ 自编译 Nginx + QuicTLS 启用 HTTP/3
✔️ 与 apk 原版 Nginx 共存,并平滑切换
✔️ 修复 H3 出现 400 Bad Request 的问题
✔️ 最大化 Navidrome 流媒体播放速度(ARM 优化)
✔️ 重写 OpenRC 脚本使用自编译 nginx
✔️ 保留 HTTP/2 + TLS+ CHACHA20 优化


编译前准备

安装依赖:

1
2
3
4
5
6
7
8
9
10
11
sudo apk add build-base git pcre2-dev zlib-dev brotli-dev jemalloc-dev


QuicTLS 作为 HTTP/3 必须依赖的 TLS 库:

```sh
git clone https://github.com/quictls/openssl.git quictls
cd quictls
./Configure linux-aarch64 --prefix=/opt/quictls --openssldir=/opt/quictls enable-ktls
make -j$(nproc)
sudo make install_sw

编译 Nginx(带 HTTP/3 / HTTP/2 / TLS)

下载 Nginx:

1
2
wget https://nginx.org/download/nginx-1.27.2.tar.gz
tar xf nginx-1.27.2.tar.gz && cd nginx-1.27.2

配置(关键参数一行版):

1
2
3
4
5
6
7
8
./configure \
--prefix=/usr/local/nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_v3_module \
--with-pcre-jit \
--with-cc-opt="-I/opt/quictls/include" \
--with-ld-opt="-L/opt/quictls/lib -Wl,-rpath,/opt/quictls/lib"

编译安装:

1
2
make -j$(nproc)
sudo make install

确认编译成功:

1
/usr/local/nginx/sbin/nginx -V

你应该能看到:

1
2
--with-http_v3_module
--with-http_v2_module

配置文件合并:启用 HTTP/3

示例 server:

1
2
3
4
5
6
7
8
9
10
11
server {
listen 0.0.0.0:443 ssl;
listen [::]:443 ssl;
http2 on;

listen 0.0.0.0:443 quic reuseport;
listen [::]:443 quic reuseport;

server_name navidrome.yourdomain.xyz;

add_header Alt-Svc 'h3=":443"; ma=86400' always;

关键点:

  • listen 443 quic reuseport
  • Alt-Svc: h3=":443"

遇到的致命问题:HTTP/3 全部变 400

实际测试时发现:

1
GET /app/ HTTP/→ 400

但 HTTP/2 / HTTP/都正常。

最终定位:
反代 Navidrome 时发送了错误的 hop-by-hop 头(Upgrade / Connection)
导致后端返回 400。

修复方式是只在确实使用 WebSocket 时才发送 Upgrade / Connection:

1
2
3
4
map $http_upgrade $proxy_connection {
default upgrade;
'' '';
}

并在反代里:

1
2
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;

如果后端不用 WebSocket,可以直接:

1
2
proxy_set_header Upgrade "";
proxy_set_header Connection "";

修复后,HTTP/3 全部正常。


Navidrome 的流媒体专项优化(很关键)

因为 OnePlus 6 的 Wi-Fi 芯片不支持 UDP GSO/GRO → HTTP/3 性能天然受限。
但可以大量优化 Navidrome 的播放体验。

强制 TLS 使用 CHACHA20(ARM 上比 AES-GCM 快很多)

1
2
3
ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
ssl_prefer_server_ciphers on;

禁用 gzip

音频本身已压缩:

1
gzip off;

反代优化(强烈推荐)

1
2
3
4
proxy_buffering off;
proxy_request_buffering off;
proxy_max_temp_file_size 0;
proxy_set_header Accept-Encoding "";

自编译 Nginx 的 OpenRC 服务脚本

替换 /etc/init.d/nginx

1
2
3
command=/usr/local/nginx/sbin/nginx
command_args="-c /etc/nginx/nginx.conf"
pidfile=/run/nginx/nginx.pid

并在 nginx.conf 顶部加:

1
pid /run/nginx/nginx.pid;

最终测试:

1
sudo rc-service nginx restart

此时 OpenRC 已经完全使用自编译 Nginx(带 HTTP/3)。


最终验证

用 curl 验证 H3

1
curl -I --http3-only https://navidrome.yourdomain.xyz

浏览器 F12 → Network → Protocol

你应该看到:

1
2
h3
h3-29

access.log 验证

加入日志格式:

1
$server_protocol

就能看到:

1
HTTP/200

最终配置摘要(可直接参考)

nginx.conf 必要部分

1
2
3
4
5
6
7
8
9
10
11
12
user nginx;
pid /run/nginx/nginx.pid;

map $http_upgrade $proxy_connection {
default upgrade;
'' '';
}

ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256;
ssl_ciphers 'ECDHE-RSA-CHACHA20-POLY1305:ECDHE+AESGCM';
ssl_prefer_server_ciphers on;
gzip off;

server 反代 Navidrome 部分

1
2
3
4
5
6
7
8
9
10
11
12
13
proxy_buffering off;
proxy_request_buffering off;
proxy_max_temp_file_size 0;
proxy_set_header Accept-Encoding "";
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Range $http_range;
proxy_set_header If-Range $http_if_range;

总结:最终可得到的效果

✔ HTTP/3 完整启用(Chrome / curl / QUIC 可见)
✔ Navidrome 流媒体不再卡顿
✔ 浏览器协议优先级:H2、H3 都可用
✔ CPU 占用明显下降(CHACHA20)
✔ 整体吞吐与响应速度显著提升
✔ 可以随时升级Nginx而不影响系统包