emby.wiki · 文档
反向代理Emby(Linux)
使用 SSH、Nginx 和 Certbot 在 Linux 上配置 Emby 反向代理、HTTPS 与自动续期。
本文面向刚购买 Linux 云服务器、希望通过命令行为 Emby 配置 Nginx 反向代理和 HTTPS 的用户。全程使用 SSH、系统包管理器、systemd、Nginx 和 Certbot,无需安装 Web 管理面板。
部署前提 本文负责反向代理与 HTTPS,不包含 Emby 的安装和媒体库建设。一台全新服务器可以作为 Nginx 入口,但必须先有能够正常工作的 Emby 源站。同机部署时,先安装并启动 Emby;分离部署时,先确认另一台服务器上的 Emby 正常。
1. 部署架构#
客户端访问 https://emby.example.com,由 Nginx 的 443 端口接收并处理 TLS,再通过 HTTP 转发到 Emby 的 8096 端口。
| 部署方式 | 客户端入口 | Nginx 到 Emby | 适用情况 |
|---|---|---|---|
| 同一台服务器 | Nginx 公网域名,HTTPS 443 | http://127.0.0.1:8096 | Emby 和 Nginx 安装在同一台主机 |
| 两台服务器 | Nginx 公网域名,HTTPS 443 | http://10.0.0.20:8096 | 两台主机通过可信私网连接 |
公网通常只需允许 TCP 80、443,以及用于管理的 SSH 端口(默认 22)。80 用于 HTTP 跳转和 Let's Encrypt 验证,443 用于实际访问。Emby 8096 应限制在本机或私网内,不应默认向整个公网开放。
两台服务器之间若经过公网,应先建立可信的加密隧道,或使用经过证书验证的 HTTPS 上游;客户端到 Nginx 的 HTTPS 不会自动加密 Nginx 到 Emby 的 HTTP 连接。
2. 准备参数与操作约定#
| 占位符 | 含义 | 示例 |
|---|---|---|
YOUR_DOMAIN | 指向 Nginx 的域名,不带协议、路径和端口 | emby.example.com |
EMBY_HOST | Nginx 能访问的 Emby 地址 | 127.0.0.1 或 10.0.0.20 |
EMBY_PORT | Emby 实际 HTTP 监听端口 | 8096 |
YOUR_EMAIL | 接收证书账户通知的邮箱 | admin@example.com |
同机部署示例:
YOUR_DOMAIN = emby.example.com
EMBY_HOST = 127.0.0.1
EMBY_PORT = 8096
分离部署示例:
YOUR_DOMAIN = emby.example.com
EMBY_HOST = 10.0.0.20
EMBY_PORT = 8096
先替换,再执行 上述等号只是参数说明,不是 Shell 命令。本文的
YOUR_DOMAIN、EMBY_HOST、EMBY_PORT、YOUR_EMAIL都是需要手动替换的占位符,不会被 Shell 自动展开。Nginx 中的$host、$scheme、$http_upgrade等则是 Nginx 原生变量,必须保留。
除 SSH 登录命令外,命令默认在 Nginx 服务器上执行;标明“Emby 服务器”的命令才在源站执行。本文保留 sudo,已通过 sudo -i 切换到 root 时可省略。发行版安装命令只执行对应的一组。
3. 登录服务器并确认系统#
在本地终端使用云厂商提供的用户名、IP 和认证方式登录:
ssh root@服务器IP
云厂商提供普通用户时,可分别使用:
ssh ubuntu@服务器IP
ssh debian@服务器IP
使用非默认 SSH 端口或指定私钥时,例如:
ssh -p 2222 -i ~/.ssh/你的私钥 ubuntu@服务器IP
登录后查看身份;普通用户需要管理员权限时执行:
whoami
sudo -i
识别发行版、内核、CPU 架构和网络:
cat /etc/os-release
uname -a
uname -m
ip addr
ip route
Connection timed out 通常需要检查公网 IP、SSH 端口、云安全组和系统防火墙。Permission denied 则优先核对用户名、密码或 SSH 私钥,以及服务器是否允许该认证方式。常见初始用户名包括 root、ubuntu、debian、rocky、ec2-user,以厂商说明为准。
保持管理连接 修改防火墙时保留当前 SSH 窗口,再开一个终端确认能够重新登录。若 SSH 使用 2222 等其他端口,后文的 22 必须改成真实端口。
4. 验证 Emby 源站#
Emby 源站没有正常工作时,不要开始配置 Nginx。 先确认源站可以响应 HTTP 请求,再处理反向代理。
同机部署#
curl -I http://127.0.0.1:8096/
curl -v http://127.0.0.1:8096/
sudo ss -lntp | grep 8096
HTTP 返回可能是正常页面或重定向,不必强求根路径一定返回 200;关键是连接成功,并且响应来自 Emby。若 HEAD 请求不被支持,以 curl -v 的 GET 请求和浏览器测试为准。
监听结果可能包含 127.0.0.1:8096 或 0.0.0.0:8096。前者仅本机可访问;后者表示所有 IPv4 接口监听,仍需通过防火墙限制公网访问。
两台服务器#
在 Nginx 服务器 上测试:
curl -v http://EMBY_HOST:EMBY_PORT/
nc -vz EMBY_HOST EMBY_PORT
若缺少诊断工具,按系统安装;nc 只用于额外的 TCP 测试,curl 是主要检查工具。
| 系统 | 安装 curl 和 nc |
|---|---|
| Debian / Ubuntu | sudo apt update,然后 sudo apt install -y curl netcat-openbsd |
| Rocky / AlmaLinux / RHEL / CentOS Stream / Fedora | sudo dnf install -y curl nmap-ncat |
| openSUSE | sudo zypper install curl netcat-openbsd |
| Arch Linux | sudo pacman -Syu curl openbsd-netcat |
源站不通时,先在 Emby 服务器 上运行 sudo ss -lntp | grep 8096:没有输出可能是服务未启动或端口已改;只监听 127.0.0.1 时,另一台服务器无法连接。分离部署必须监听可达的私网地址,并只允许 Nginx 的来源地址访问。具体限制方法见第 16 节。
5. 配置 DNS 与 IPv4 / IPv6#
在域名的 DNS 管理处建立 A 记录,指向 Nginx 服务器 的公网 IPv4,而不是 Emby 私网 IP。例如:
记录类型:A
主机名:emby
目标 IPv4:203.0.113.10
最终域名:emby.example.com
203.0.113.10 是文档示例地址,请替换成自己的公网 IP。若 DNS 服务有代理/CDN 开关,本教程的直连架构使用“仅 DNS”;启用额外代理后,访问路径、证书检查和来源 IP 都会改变。
getent ahosts YOUR_DOMAIN
dig +short YOUR_DOMAIN A
dig +short YOUR_DOMAIN AAAA
dig 未安装时,可安装对应工具包:
| 系统 | 命令 |
|---|---|
| Debian / Ubuntu | sudo apt install -y dnsutils |
| RPM 系 | sudo dnf install -y bind-utils |
| openSUSE | sudo zypper install bind-utils |
| Arch Linux | sudo pacman -S bind |
没有真正可用的 IPv6 时,不要建立 AAAA。错误的 AAAA 会导致部分设备优先连接到错误地址,也会影响 Let's Encrypt 验证。使用 IPv6 时,必须同时满足:AAAA 正确、服务器 IPv6 可达、安全组与防火墙放行 IPv6、Nginx 监听 IPv6。
6. 放行云厂商安全组#
系统防火墙放行不等于云平台已经放行。在服务器所属的云安全组或云防火墙中检查入站规则:
| TCP 端口 | 用途 | 来源建议 |
|---|---|---|
| 22,或实际 SSH 端口 | SSH 管理 | 尽可能只允许自己的管理 IP |
| 80 | HTTP 和 HTTP-01 验证 | 对外服务所需的公网来源 |
| 443 | HTTPS | 对外服务所需的公网来源 |
提供 IPv6 服务时,也要配置相应 IPv6 规则。若服务器位于路由器之后,80、443 的端口转发应指向 Nginx 服务器。不要把 8096 加入面向所有公网地址的规则。
7. 安装 Nginx#
Debian / Ubuntu#
sudo apt update
sudo apt install -y nginx curl ca-certificates
sudo systemctl enable --now nginx
全新服务器需要更新系统软件时,可在确认变更和重启要求后执行 sudo apt upgrade -y。不要把全量升级当作反向代理配置的必需步骤。
Rocky / AlmaLinux / RHEL / CentOS Stream#
sudo dnf install -y nginx curl ca-certificates
sudo systemctl enable --now nginx
需要更新系统时使用 sudo dnf update -y。RHEL 的软件包可用性取决于订阅和已启用的软件仓库;出现找不到包时,先检查官方仓库状态。
Fedora#
sudo dnf install -y nginx curl ca-certificates
sudo systemctl enable --now nginx
需要更新系统时使用 sudo dnf upgrade --refresh -y。
openSUSE#
sudo zypper refresh
sudo zypper install nginx curl ca-certificates
sudo systemctl enable --now nginx
Arch Linux#
Arch 应避免只刷新仓库而不升级系统:
sudo pacman -Syu nginx curl ca-certificates
sudo systemctl enable --now nginx
安装后的检查#
command -v nginx
sudo nginx -v
sudo nginx -t
sudo systemctl status nginx --no-pager -l
curl -I http://127.0.0.1/
初次安装看到默认 Welcome 页面是正常现象;此时尚未配置 Emby 反代。若提示 nginx: command not found,检查是否安装成功以及管理命令目录是否在 PATH 中;若服务启动失败,查看:
sudo journalctl -u nginx -n 100 --no-pager
sudo journalctl -xeu nginx
端口占用和配置错误的统一排查方法见第 18 节。不要直接终止不明进程或删除其他站点来解决冲突。
8. 配置系统防火墙#
先检查系统正在使用的防火墙,只采用符合当前环境的一套规则。不要在已有规则的服务器上盲目叠加 UFW 和 firewalld。
UFW#
Debian / Ubuntu 缺少 UFW 时:
sudo apt install -y ufw
启用前先放行实际 SSH 端口,再允许 HTTP / HTTPS:
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose
SSH 使用其他端口时先替换 22。IPv6 服务还应检查 /etc/default/ufw 中的 IPv6 设置和状态输出中的 IPv6 规则。启用后用另一个 SSH 终端验证能够重新登录,再关闭旧连接。
firewalld#
RPM 系缺少组件时使用:
sudo dnf install -y firewalld
openSUSE 对应使用 sudo zypper install firewalld。已有防火墙时先确认现有 SSH 放行策略,再决定是否启用新服务。使用默认 SSH 服务的全新环境可执行:
sudo systemctl enable --now firewalld
sudo firewall-cmd --get-active-zones
根据输出选择承载公网网卡的实际区域。下面以 public 为例,使用其他区域时替换所有 public:
sudo firewall-cmd --zone=public --add-service=ssh
sudo firewall-cmd --zone=public --permanent --add-service=ssh
sudo firewall-cmd --zone=public --permanent --add-service=http
sudo firewall-cmd --zone=public --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --list-all
自定义 SSH 端口应先加入对应的运行时和永久规则,例如 --add-port=2222/tcp,而不是仅依赖默认 ssh 服务。在远程启用 firewalld 前确认初始区域允许管理连接,并准备云控制台恢复途径。
9. 检查 SELinux#
Rocky、AlmaLinux、RHEL、CentOS Stream、Fedora 等系统可能启用 SELinux:
getenforce
输出为 Enforcing 时,允许 Nginx 的 Web 服务域连接上游:
sudo setsebool -P httpd_can_network_connect 1
getsebool httpd_can_network_connect
检查结果应包含:
httpd_can_network_connect --> on
同机 curl 可以连接 Emby,但 Nginx 返回 502 且错误日志有权限拒绝时,要检查 SELinux。保留 SELinux 保护,不使用临时或永久关闭 SELinux 的方式绕过问题。
10. 配置并测试 HTTP 反向代理#
先验证 Nginx 到 Emby 的转发,再增加 TLS。这样可以区分源站、代理和证书的问题。
选择配置文件并备份#
先查看现有配置:
sudo nginx -T
sudo cp -a /etc/nginx /root/nginx-backup-$(date +%Y%m%d-%H%M%S)
Debian / Ubuntu:
sudo nano /etc/nginx/sites-available/emby
Rocky / AlmaLinux / RHEL / CentOS Stream / Fedora:
sudo nano /etc/nginx/conf.d/emby.conf
openSUSE / Arch 的包配置可能不同,先查看 /etc/nginx/nginx.conf 中 http { ... } 的 include。选择已在 http 上下文中包含的目录;若没有合适目录,可以创建 /etc/nginx/conf.d,并在现有 http { ... } 中加入一次:
include /etc/nginx/conf.d/*.conf;
然后编辑 /etc/nginx/conf.d/emby.conf。不要把本文站点配置直接覆盖整个 nginx.conf,也不要在 server 或 location 中包含带有 map 的文件。
缺少编辑器时,用相应包管理器安装 nano:Debian / Ubuntu 使用 sudo apt install -y nano,RPM 系使用 sudo dnf install -y nano,openSUSE 使用 sudo zypper install nano,Arch 使用 sudo pacman -S nano。nano 中使用 Ctrl+O、Enter 保存,再 Ctrl+X 退出。
完整 HTTP 配置#
先替换三个占位符,再保存以下配置:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name YOUR_DOMAIN;
client_max_body_size 0;
location / {
proxy_pass http://EMBY_HOST:EMBY_PORT;
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 X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
proxy_request_buffering off;
}
}
同机示例替换为 server_name emby.example.com; 和 proxy_pass http://127.0.0.1:8096;。IPv6 上游地址要放在方括号内,例如 proxy_pass http://[fd00::20]:8096;。
map 必须处于 http 上下文,且全局只定义一次。若已有完全相同的 $connection_upgrade 映射,沿用现有定义,不要重复创建。不支持 IPv6 的系统可移除 [::] 的监听行,同时不发布 AAAA;后面的最终配置也要保持一致。
启用、检查与 reload#
Debian / Ubuntu 还需要建立链接:
sudo ln -s /etc/nginx/sites-available/emby /etc/nginx/sites-enabled/emby
ls -l /etc/nginx/sites-enabled/
提示 File exists 时先检查已有链接是否指向正确文件,不要强制覆盖。其他发行版在正确的包含目录中保存配置即可。
每次修改后先检查:
sudo nginx -t
只有出现 syntax is ok 和 test is successful,才执行:
sudo systemctl reload nginx
形成“修改 → nginx -t → reload”的习惯,常规配置变更无需反复 restart。若服务尚未运行,应先排除启动问题并启动服务。
测试 HTTP#
curl -I http://YOUR_DOMAIN/
curl -v http://YOUR_DOMAIN/
DNS 尚未生效时,在 Nginx 本机指定 Host:
curl -v -H "Host: YOUR_DOMAIN" http://127.0.0.1/
此测试只证明本机虚拟主机匹配和代理路径正常,还需从外部网络验证域名访问。打开浏览器确认 Emby 页面能够加载;HTTP 阶段仅用于验证,完成 HTTPS 后再进行正式登录和播放验收。
出现 Welcome 页面时优先检查 DNS、server_name、配置是否启用。Debian / Ubuntu 的默认链接为 /etc/nginx/sites-enabled/default;确认服务器没有依赖该配置的其他站点后再删除:
sudo rm /etc/nginx/sites-enabled/default
之后仍需 sudo nginx -t 成功才 reload。删除默认站点不是部署的必需步骤;不要删除其他配置。
11. WebSocket 与流媒体参数#
完整配置已包含所需指令,无需再次重复添加。
| 指令 | 用途 |
|---|---|
proxy_http_version 1.1; | 明确使用 HTTP/1.1 与上游通信 |
Upgrade、Connection 代理头与 map | 转发 WebSocket 协议升级,支持实时状态和长连接 |
proxy_read_timeout 3600s; | 等待上游相邻读取操作的超时 |
proxy_send_timeout 3600s; | 向上游相邻写入操作的超时 |
proxy_buffering off; | 将上游响应及时传给客户端,避免通常的代理响应缓冲 |
proxy_request_buffering off; | 流式转发请求体,避免先完整缓存后再传给上游 |
3600 秒并不是“影片只能播放一小时”,也不是整个请求的总时长上限;这些 timeout 主要控制两次读写之间的等待。播放中断应结合日志、源站负载和网络排查,不能只把超时无限增加。
普通 Range 请求会按正常代理规则传递。没有具体问题时,不要人为重写 Range 或 If-Range;修改不当会破坏进度拖动和分段请求。也不要为 Emby API、登录响应或媒体请求盲目增加共享缓存。
12. 设置 Emby 后台#
进入 Emby 的 Dashboard → Network(控制台 → 网络),按实际版本的界面名称配置:
| 项目 | 建议值 |
|---|---|
| External Domain / 外部域名 | YOUR_DOMAIN,例如 emby.example.com |
| Public HTTPS Port / 公共 HTTPS 端口 | 443 |
| Secure Connection Mode / 安全连接模式 | Handled by reverse proxy / 由反向代理处理 |
| Local HTTP Port / 本地 HTTP 端口 | 保持实际源站端口,默认 8096 |
外部域名不填写 https://、路径或端口。若设置公共 HTTP 端口,本教程的入口为 80;这不会改变 Emby 的本地监听端口。TLS 在 Nginx 终止,本方案不要求把 Nginx 的私钥复制到 Emby。
需要远程访问时,确认服务器和对应用户允许远程连接。若版本提供“检查代理头以确定真实客户端 IP”的选项,确认其适合当前代理环境;同时限制 8096 的来源,避免客户端绕过 Nginx 伪造代理头。关闭不需要的自动端口映射,避免路由器自动暴露 Emby 端口。
在 HTTPS 尚未配置好时,443 的对外地址暂时不可用;完成下面步骤后,用最终 HTTPS 地址验收并按界面提示应用设置。
13. 验证 ACME 并申请证书#
创建 webroot 与测试文件#
HTTP 反代已经正常后执行:
sudo mkdir -p /var/www/letsencrypt/.well-known/acme-challenge
echo test | sudo tee /var/www/letsencrypt/.well-known/acme-challenge/test
在现有 80 端口的 server 块内,与 location / 并列加入:
location ^~ /.well-known/acme-challenge/ {
root /var/www/letsencrypt;
default_type text/plain;
try_files $uri =404;
}
保留原来的 map 和 Emby 代理配置。这里的 root 会将请求映射到 /var/www/letsencrypt/.well-known/acme-challenge/,不要再把 .well-known 重复写入 root。
sudo nginx -t
检查成功后:
sudo systemctl reload nginx
curl -fsS http://YOUR_DOMAIN/.well-known/acme-challenge/test
必须返回:
test
还要从服务器以外的网络实际访问这个 URL。只有本机能访问不能证明公网验证成功。HTTP-01 必须能够从公网通过 80 端口取到验证文件;此路径不能被登录、挑战页面、错误的代理路由或全站跳转规则截走。
在 SELinux 系统中,若该目录出现权限拒绝,检查文件权限与安全上下文;需要为自定义 webroot 明确标记时可使用:
sudo semanage fcontext -a -t httpd_sys_content_t '/var/www/letsencrypt(/.*)?'
sudo restorecon -Rv /var/www/letsencrypt
已有相同规则时使用 semanage fcontext -m 修改,而非重复添加。RPM 系缺少 semanage 时通常安装 policycoreutils-python-utils。不要把 webroot 或私钥目录改成全员可写。
安装 Certbot#
Debian / Ubuntu:
sudo apt update
sudo apt install -y certbot
Fedora,以及已提供 Certbot 包的 RPM 仓库:
sudo dnf install -y certbot
openSUSE:
sudo zypper install certbot
Arch Linux:
sudo pacman -S certbot
Rocky / AlmaLinux 等环境可能需要发行版支持的 EPEL 仓库,RHEL 还涉及订阅仓库。若显示找不到包,先按发行版与 Certbot 官方安装说明 选择适用安装方式,不要加入不明软件源,也不要同时混用多套 Certbot 安装。
申请并确认路径#
最简交互方式:
sudo certbot certonly \
--webroot \
-w /var/www/letsencrypt \
-d YOUR_DOMAIN
或者明确提供邮箱,阅读并同意 Let's Encrypt 的服务条款后执行:
sudo certbot certonly \
--webroot \
-w /var/www/letsencrypt \
-d YOUR_DOMAIN \
-m YOUR_EMAIL \
--agree-tos
两种方式任选其一,不要重复申请。certonly 只取得证书,不会自动替你完成本文的 Nginx HTTPS 配置。成功后检查 Certbot 报告的实际路径:
sudo certbot certificates
sudo ls -l /etc/letsencrypt/live/YOUR_DOMAIN/
通常为:
/etc/letsencrypt/live/YOUR_DOMAIN/fullchain.pem
/etc/letsencrypt/live/YOUR_DOMAIN/privkey.pem
若同名证书已经存在,实际目录可能带 -0001 等后缀。最终配置必须使用 Certbot 输出的真实路径,不要只按域名猜测。
申请失败时#
先重新访问测试文件,确认仍然返回 test:
curl -v http://YOUR_DOMAIN/.well-known/acme-challenge/test
dig +short YOUR_DOMAIN A
dig +short YOUR_DOMAIN AAAA
sudo ss -lntp | grep ':80'
sudo tail -n 100 /var/log/nginx/error.log
根据使用的防火墙执行 sudo ufw status verbose 或 sudo firewall-cmd --zone=public --list-all,并检查云安全组。403 优先查读取权限、SELinux 和访问规则;404 优先查 webroot、虚拟主机与路径;超时优先查 DNS、网络和 80 端口。
检查 Certbot 日志 /var/log/letsencrypt/letsencrypt.log。有 AAAA 时 IPv6 也必须提供正确验证内容,不能依赖验证服务总是回退 IPv4。修复原因后再申请,避免反复申请触发限额。通用 TLS 连接排查见第 18 节。
14. 最终 HTTPS 配置与验证#
完整配置#
证书申请成功后,替换本文创建的 Emby 站点文件内容,不要把下列配置追加到旧的同名 server 后面,也不要覆盖其他站点。保留全局唯一的 map;若它已在其他公共文件定义,省去这里重复的 map。
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name YOUR_DOMAIN;
location ^~ /.well-known/acme-challenge/ {
root /var/www/letsencrypt;
default_type text/plain;
try_files $uri =404;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name YOUR_DOMAIN;
ssl_certificate /etc/letsencrypt/live/YOUR_DOMAIN/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/YOUR_DOMAIN/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
client_max_body_size 0;
location / {
proxy_pass http://EMBY_HOST:EMBY_PORT;
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 X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
proxy_request_buffering off;
}
}
替换域名、上游和证书路径。fullchain.pem 包含服务器证书与中间证书;privkey.pem 是私钥,不能公开或修改为全员可读。client_max_body_size 0 取消请求体大小限制,有明确上传需求时可以改为合适上限,如 1g。
ACME 路径保留在 HTTP 上,其余 HTTP 请求返回 301。不要在 HTTP server 顶层加入统一 return 301 截走验证请求。TLS 1.3 需要相应 Nginx / OpenSSL 支持,使用发行版维护的当前软件包。
检查并加载#
sudo nginx -t
成功后才执行:
sudo systemctl reload nginx
curl -I http://YOUR_DOMAIN/
确认普通 HTTP 路径返回 301,且 Location 指向 HTTPS;ACME 测试路径应仍然返回 test:
curl -fsS http://YOUR_DOMAIN/.well-known/acme-challenge/test
curl -I https://YOUR_DOMAIN/
curl -v https://YOUR_DOMAIN/
HTTPS 根路径可能返回 200 或 Emby 的正常重定向。不要用跳过证书验证的方式当作验收成功。
检查 TLS 握手、证书链和主机名:
openssl s_client \
-connect YOUR_DOMAIN:443 \
-servername YOUR_DOMAIN \
-verify_hostname YOUR_DOMAIN \
-verify_return_error
查看证书是否对应域名、是否在有效期内,以及是否显示 Verify return code: 0 (ok);按 Ctrl+C 退出。还应在外部网络的浏览器和手机客户端实际访问 https://YOUR_DOMAIN,完成登录、图片、字幕、播放与进度拖动检查。
15. 自动续期与证书加载#
检查续期链路和已有定时任务#
sudo certbot renew --dry-run
systemctl list-timers --all | grep -i certbot
systemctl list-unit-files | grep -i certbot
dry-run 成功说明当前验证和续期流程基本正常,不等于定时任务已经启用,也不等于 Nginx 会自动加载新证书。某些软件包使用 cron;可同时检查 /etc/cron.d/ 中的 Certbot 配置。
定时器名称随安装方式不同,可能是 certbot.timer、certbot-renew.timer 等。确认实际存在的定时器后再启用,例如存在 certbot.timer 时:
sudo systemctl enable --now certbot.timer
如果没有自动任务,按当前安装方式的官方说明补齐,不要重复创建多套续期任务。
续期成功后 reload Nginx#
本文使用 certonly --webroot,应设置部署钩子,让证书续期成功后检查配置并重新加载 Nginx:
sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh > /dev/null <<'EOF'
#!/bin/sh
set -eu
nginx -t
systemctl reload nginx
EOF
sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
sudo /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
确认该文件名没有覆盖已有不同钩子;已有等效钩子时沿用即可。支持 --run-deploy-hooks 的 Certbot 可进一步验证:
sudo certbot renew --dry-run --run-deploy-hooks
如果版本不支持该选项,保留普通 dry-run 和上面的钩子单独测试。续期需要持续保留 80 端口、ACME location、正确 DNS 和可读取的 webroot。
16. 两台服务器部署与上游保护#
示例中的私网地址:
Nginx IP = 10.0.0.10
Emby IP = 10.0.0.20
Emby HTTP Port = 8096
确认两台服务器真的共享可路由的私网;仅把不同云厂商的 IP 写成 10.0.0.x 不会自动建立私网。
在 Emby 服务器检查监听:
sudo ss -lntp | grep 8096
Emby 必须监听可达的私网接口,不能只监听回环。UFW 环境允许 Nginx 私网地址:
sudo ufw allow from 10.0.0.10 to any port 8096 proto tcp
sudo ufw status numbered
这条允许规则本身不会撤销已经存在的公网允许规则。确认 UFW 启用、入站默认策略符合预期,并检查是否仍有向任意来源开放 8096 的旧规则;按实际规则编号谨慎删除错误规则,不影响 SSH。云安全组也只允许 Nginx 的实际来源地址访问 8096。
firewalld 环境可在 Emby 私网接口的实际区域加入来源限制。下面仅以 internal 区域为例,先确认接口绑定和区域规则:
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --zone=internal --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.10/32" port port="8096" protocol="tcp" accept'
sudo firewall-cmd --reload
sudo firewall-cmd --zone=internal --list-all
若区域本身已允许所有入站流量或已有宽泛 8096 规则,单独加这条规则不会形成限制,需要结合现有策略调整。
回到 Nginx 服务器验证:
curl -v http://10.0.0.20:8096/
nc -vz 10.0.0.20 8096
站点上游改为 proxy_pass http://10.0.0.20:8096;,然后按 nginx -t → reload 生效。禁止为图省事默认向公网开放 8096。
17. 安全与维护建议#
- 只开放必要入口:公网 HTTP 80、HTTPS 443,SSH 尽量限制管理来源。
- 同机 Emby 尽可能只供回环地址访问;分离部署仅允许可信 Nginx 地址访问源站。检查 IPv4 和 IPv6 两套暴露面。
- 使用强密码、受维护的软件包和适当的 Emby 用户权限。不要为普通播放用户授予不必要的管理或媒体删除权限。
- 保留 SELinux 和防火墙;变更前备份 Nginx 配置,每次修改先检查再 reload。
- 不公开证书私钥。排错时不要公开包含账户、令牌或敏感请求参数的完整日志。
- 若增加 CDN、其他代理或隧道,应重新审视证书验证、超时、真实 IP 信任和代理头;本文的基础配置假定 Nginx 是公网第一层代理。
- 定期检查定时续期结果和 Nginx 加载的证书有效期,并实际测试长时间播放。
18. 常见故障排查#
502 Bad Gateway#
先在 Nginx 服务器检查上游;端口监听检查要在 Emby 所在服务器执行:
curl -v http://EMBY_HOST:EMBY_PORT/
sudo ss -lntp | grep 8096
sudo nginx -T | grep -n proxy_pass
sudo tail -n 100 /var/log/nginx/error.log
Emby 改过端口时相应替换 8096。Connection refused 优先查服务、监听地址和端口;连接超时查上游网络与访问规则;Permission denied 在 SELinux 系统上检查:
getenforce
getsebool httpd_can_network_connect
504 Gateway Timeout#
查看源站响应时长和负载:
time curl -v http://EMBY_HOST:EMBY_PORT/
top
free -h
df -h
sudo tail -f /var/log/nginx/error.log
分离部署时,资源命令应在 Emby 服务器也执行。区分源站卡住、CPU 转码瓶颈、GPU 不可用、磁盘空间不足或 I/O 等待、上游网络和代理超时。df -h 只查看容量,不代表 I/O 性能。不要把 timeout 设成几天来掩盖性能问题。
413 Request Entity Too Large#
检查实际生效的 client_max_body_size:
sudo nginx -T | grep -n client_max_body_size
client_max_body_size 0;
值 0 取消请求体大小限制;需要上限时可以用 client_max_body_size 1g;。修改后仍需检查再 reload。如果前面还有其他代理,要同时检查那一层的限制。
WebSocket 故障#
sudo nginx -T | grep -n -E 'Upgrade|Connection|proxy_http_version'
确认生效的 location 中有 HTTP/1.1、Upgrade 和 Connection,以及唯一且有效的 map。浏览器开发者工具可查看 WebSocket 请求是否正常升级为 101。仅能打开网页不代表实时连接正常。
视频播放一段时间后断开#
sudo tail -f /var/log/nginx/error.log
确认 proxy_read_timeout 3600s;、proxy_send_timeout 3600s; 和 proxy_buffering off; 生效;同时检查 Emby 转码 CPU、GPU、磁盘 I/O、上游带宽与客户端网络。若只有拖动进度失败,检查 Range 响应和是否存在自定义头或缓存规则,先移除未经验证的重写。
DNS 或部分设备无法连接#
dig +short YOUR_DOMAIN A
dig +short YOUR_DOMAIN AAAA
getent ahosts YOUR_DOMAIN
curl -4 -I https://YOUR_DOMAIN/
curl -6 -I https://YOUR_DOMAIN/
只有配置了可用 IPv6 时才要求 curl -6 成功。检查 A / AAAA 是否指向同一个服务入口、DNS 缓存是否更新,以及两种地址族是否同时放行。不要保留指向旧服务器的 AAAA。
HTTPS、证书或 TLS 错误#
证书申请失败按第 13 节检查 ACME、DNS 和 80 端口;HTTPS 建立后失败则检查 443 监听、证书域名、有效期、系统时间、证书链及实际路径:
sudo certbot certificates
sudo nginx -T | grep -n -E 'ssl_certificate|listen.*443|server_name'
timedatectl status
证书路径不存在、私钥权限不正确或证书与密钥不匹配会使 nginx -t 失败。证书已续期但浏览器仍看到旧证书时,检查部署钩子和 Nginx reload 是否成功;不要关闭证书验证来“修复”。
配置语法错误、重复监听与 Welcome 页面#
sudo nginx -t
sudo nginx -T
sudo nginx -T | grep -n "listen 80"
sudo nginx -T | grep -n default_server
unknown directive 检查拼写、模块支持和指令上下文;map directive is not allowed here 表示 map 放错位置。duplicate listen 检查同一 server 内的重复声明或冲突选项;多个普通站点共享 80 本身是正常的。duplicate default server 检查同一地址端口是否重复指定 default_server。
Welcome 页面则检查域名匹配、文件包含和 Debian / Ubuntu 的启用链接,按第 10 节谨慎处理默认站点。使用 nginx -T 查看时不要公开其中的敏感信息。
80 / 443 端口冲突#
sudo ss -lntp | grep -E ':80\b|:443\b'
sudo lsof -iTCP:80 -sTCP:LISTEN
sudo lsof -iTCP:443 -sTCP:LISTEN
缺少 lsof 时安装对应软件包,例如 sudo apt install -y lsof 或 sudo dnf install -y lsof。常见占用者为 Apache、httpd、Caddy、另一套 Nginx 或 Docker 容器,可检查:
sudo systemctl status apache2 --no-pager -l
sudo systemctl status httpd --no-pager -l
执行与当前发行版相符的检查。确认服务和其他站点用途后再调整端口或服务,避免直接 kill -9 或盲目停用正在工作的入口。
Nginx 日志#
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log
sudo tail -n 100 /var/log/nginx/error.log
sudo journalctl -u nginx -n 100 --no-pager
如果站点配置了单独的 access_log 或 error_log,以实际路径为准。tail -f 用 Ctrl+C 退出。结合请求时间、状态码和上游报错定位故障。
19. 最终检查清单#
- 已确认 Linux 发行版、SSH 用户和实际管理端口
- 已确认 Emby 8096 或实际源站端口正常
- 已确认 DNS A 记录指向 Nginx
- 已检查 AAAA,错误或不用的记录已处理
- 云安全组已开放 80 / 443,并保留必要 SSH 入口
- 系统防火墙已开放 80 / 443,并验证 SSH 可重新登录
- Nginx 已安装并设置开机启动
- 已备份原配置,其他站点未被误删
- nginx -t 成功
- HTTP 反代正常
- SELinux 已按实际环境正确配置
- WebSocket Headers 和 map 正常
- Emby External Domain 正确
- Public HTTPS Port = 443
- Secure Connection Mode = Handled by reverse proxy
- ACME Challenge 已从外部网络验证可以正常访问
- HTTPS 证书申请成功,配置使用实际证书路径
- 普通 HTTP 请求自动跳转 HTTPS,ACME 路径保留
- HTTPS 主机名、有效期和证书链验证正常
- Emby 登录正常
- 海报和图片正常
- 字幕正常
- 视频播放正常
- 拖动进度正常
- 手机客户端正常
- 长时间播放正常
- certbot renew --dry-run 成功
- 已确认自动续期任务启用
- 续期后检查并 reload Nginx 的钩子已验证
- Emby 8096 没有不必要暴露公网,包括 IPv6
参考官方说明:Nginx 代理模块、Emby 网络设置、Let's Encrypt 验证方式、Let's Encrypt IPv6 支持、Certbot 使用与续期。

