用 nginx 给 Emby 加上 HTTPS 反向代理:WebSocket(播放进度、远程控制要用)、关闭缓冲(边转码边播放)、上传大小限制,另外还有一个容易被忽略的安全点:访问日志会原样记下 URL 里的
api_key。这份配置在写日志前先把密钥打码。
先看清成品
在 box 上用 Docker 实测了 nginx:alpine + Emby 4.10.2.0:
nginx -t显示 successful。- 通过 HTTPS 访问:用
api_key查询参数返回 200,用X-Emby-Token请求头返回 200;WebSocket 握手返回 101。- 打码后的日志: 只出现
api_key=***,完整密钥 0 次。- 默认格式的日志: 换成默认日志格式再请求一次,完整密钥出现了 1 次(见调试示例)。
- 证书用的是 openssl 生成的自签证书;公网证书没有测过。
注意:媒体库里只放你有权使用的内容,比如自己拍的家庭视频、自己购买的影片的合法备份、开放授权的作品。不要安装盗版插件,不要分享资源。硬件加速转码属于 Emby Premiere 的功能(官方 Premiere 页面写明“Hardware Accelerated Transcoding”),请按官方方式订阅,价格以官网为准。
做完之后你会得到什么?
| 成果 | 说明 |
|---|---|
emby.conf |
HTTPS、HTTP/2、WebSocket、关闭缓冲、给 api_key 打码的日志格式 |
docker-compose.yml |
Emby + nginx 放在同一个网络里 |
需要准备哪些环境?
| 项目 | 要求 | 说明 |
|---|---|---|
| 证书 | 内网 CA 或自签证书;有公网域名就用 Let's Encrypt | 文件放在 ./certs/ |
| Docker | 带 Compose 插件 | |
| 访问控制 | 只有自己人用的话,配合 Tailscale | 见 38-jellyfin-C |
文件结构
39-emby-C-src/
├── emby.conf
└── docker-compose.yml
第 1 步:nginx 配置
emby.conf:
# Emby 反向代理(nginx)。证书换成你自己的:家里用自签证书或内网 CA,有公网域名就用 Let's Encrypt
# 把 URL 里的 api_key 打码后再写访问日志:Emby 的部分客户端会把密钥放在查询参数里
map $request_uri $safe_uri {
"~^(?<pre>.*[?&]api_key=)[^&]*(?<post>.*)$" "${pre}***${post}";
default $request_uri;
}
log_format safe '$remote_addr [$time_local] "$request_method $safe_uri" $status $body_bytes_sent';
map $http_upgrade $connection_upgrade { default upgrade; '' close; }
server {
listen 443 ssl;
http2 on;
server_name emby.home.arpa;
ssl_certificate /etc/nginx/certs/emby.crt;
ssl_certificate_key /etc/nginx/certs/emby.key;
access_log /var/log/nginx/emby.access.log safe;
client_max_body_size 100m; # 上传字幕、封面用
location / {
proxy_pass http://embyserver:8096;
proxy_http_version 1.1;
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 Upgrade $http_upgrade; # WebSocket:播放进度、远程控制要用
proxy_set_header Connection $connection_upgrade;
proxy_buffering off; # 边转码边播放,不要让 nginx 缓冲
}
}
docker-compose.yml:
# Emby + nginx(HTTPS 和 WebSocket)。证书文件放在 ./certs 目录
services:
embyserver:
image: emby/embyserver
environment: [UID=1000, GID=1000, GIDLIST=1000]
volumes:
- ./programdata:/config
- /srv/media:/mnt/media:ro
networks: [media]
restart: on-failure
nginx:
image: nginx:alpine
ports: ["443:443"]
volumes:
- ./emby.conf:/etc/nginx/conf.d/emby.conf:ro
- ./certs:/etc/nginx/certs:ro
- ./logs:/var/log/nginx
networks: [media]
restart: unless-stopped
networks:
media: {}
第 2 步:验证
$ docker exec nginx nginx -t
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ curl --cacert certs/emby.crt https://emby.home.arpa/emby/System/Info/Public
{"LocalAddresses":[],"RemoteAddresses":[],"ServerName":"…","Version":"4.10.2.0",…}
$ curl -o /dev/null -w '%{http_code}' --http1.1 -H "Connection: Upgrade" -H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
"https://emby.home.arpa/embywebsocket?api_key=…&deviceId=ngtest"
101
$ cat logs/emby.access.log
172.25.0.1 [21/Oct/2026:08:06:57 +0000] "GET /emby/System/Info/Public" 200 131
172.25.0.1 [21/Oct/2026:08:06:57 +0000] "GET /emby/System/Info?api_key=***" 200 893
172.25.0.1 [21/Oct/2026:08:06:57 +0000] "GET /emby/System/Info" 200 893
检查点:WebSocket 返回 101,日志里只有 ***。(摘录的是测试时那几条普通请求的日志;WebSocket 那一条没有摘录。)
注:示例里把 compose 的端口映射写成 443:443;我在 box 上测试时映射到 18444,域名用的是 hosts 文件里临时加的一条记录。在手机 App 里填 https://你的域名 能正常登录和播放(这一步没有在真机上测)。
调试示例:默认日志格式泄露了密钥
我临时把日志格式换回 nginx 默认的 combined,再请求一次带 api_key 的 URL,日志里出现了:
172.25.0.1 - - [21/Oct/2026:08:07:11 +0000] "GET /emby/System/Info?api_key=<完整API密钥> HTTP/2.0" 200 893 "-" "curl/8.14.1"
完整密钥出现次数:1
能读到日志的人,就能用这个密钥访问你的媒体库。修改方法:用 map 把 $request_uri 里 api_key= 后面的值换成 ***,再用自定义的 log_format safe 写日志。改完以后,同样的请求在日志里完整密钥出现 0 次。自己写的脚本则一律用 X-Emby-Token 请求头(见 39-emby-A)。
常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
| 播放进度不同步,远程控制没反应 | WebSocket 没有升级成功 | 检查 Upgrade / Connection 头,测试应该返回 101 |
| 转码播放时一卡一卡 | nginx 在缓冲响应 | proxy_buffering off |
| 上传字幕失败(413) | 请求体太大 | 调大 client_max_body_size |
| 日志里出现了密钥 | 用的是默认日志格式 | 用 safe 格式,并且换掉已经泄露的密钥 |
模板规则
- 反向代理要同时处理 HTTPS、WebSocket 和日志打码。
- 发现密钥进过日志,就立刻换掉。
- 公网访问配合访问控制;家庭自用优先选 Tailscale。
项目资源
| 用途 | 地址 |
|---|---|
| nginx WebSocket 代理 | https://nginx.org/en/docs/http/websocket.html |
| nginx map 模块 | https://nginx.org/en/docs/http/ngx_http_map_module.html |
| API 密钥认证(官方) | https://dev.emby.media/doc/restapi/API-Key-Authentication.html |
| Emby Premiere 功能列表 | https://emby.media/premiere.html |
反向代理配好以后,最容易被忽略的是日志。密钥一旦进了日志,就会跟着日志文件被备份、复制到各处。打码只需要几行配置,在一开始就加上。