最近有同事在生产环境倒腾 OnlyOffice,问我最多的一个问题就是:明明服务已经跑起来了,浏览器地址栏也正常打开,为什么集成到系统里一编辑文档就报错、或者保存时提示“无法连接到文档服务器”。排查到最后,几乎都是同一个原因——OnlyOffice 还停留在 HTTP 明文访问,而业务系统已经是 HTTPS 了。浏览器把“HTTPS 页面里发起 HTTP 请求”的行为直接视为混合内容,咔嚓一下给你拦掉。这篇就专门写 OnlyOffice 配置 HTTPS 访问这件事,从方案选型到 Nginx 反向代理,再到常见坑位的排查,一次性说清楚。
我自己经历过从裸 IP 访问到正规域名 HTTPS 的整个改造过程,也会把踩过的问题一并列出来,给正在做同样事情的运维、开发同学当一份参考。这篇文章适合的对象很明确:要么你已经部署好了 OnlyOffice Document Server 正在为编辑页打不开发愁,要么你准备在自建网盘、OA、项目管理软件里集成 OnlyOffice,趁早把 HTTPS 链路设计对,省得后面返工。
1. 整体设计与方案选型
1.1 为什么 HTTPS 会是刚需而不仅仅是“更好”
先说一个很多新手容易忽略的点:OnlyOffice 本身是一个浏览器端在线编辑套件,前端通过 JavaScript SDK 加载文档编辑器,编辑器内部再去访问文档转换、协同编辑的接口。也就是说,页面里会有大量的 XHR 和 WebSocket 请求动态发生。如果你把业务系统跑在 HTTPS 下,而文档服务地址还是 http:// 开头,现代浏览器会严格拦截这类跨协议请求。常见的表现包括:
- 编辑器加载到一半白屏,控制台报
Mixed Content错误; - 文档能打开,但“保存”按钮一直转圈;
- 协同编辑时连接状态异常,多人同时编辑时看不到对方的光标。
解决办法只有一个方向:让 OnlyOffice 的访问地址和上层业务系统保持同样的协议,也就是说给它也配上 HTTPS。
这里要提一个容易被带偏的思路。有人可能在容器层面直接把 OnlyOffice 容器内部 Nginx 改造成监听 443,或者把证书挂载进容器。这个方案不能说完全不行,但维护成本高,升级镜像后配置容易丢,而且 TLS 证书续期、多站点扩展都麻烦。我更推荐在宿主机上用一个独立的 Nginx 做反向代理,统一终结 TLS,再把请求转给 OnlyOffice 容器的 80 端口。这样职责清晰,证书管理也集中在一个入口。
1.2 两种主流架构对比:直挂证书 vs 反向代理
我自己实际做过两种测试,结论非常明确:反向代理是更适合绝大部分团队的方案。
| 对比维度 | 容器内直接改 HTTPS | Nginx 反向代理统一终结 TLS |
|---|---|---|
| 配置复杂度 | 需要改容器内 Nginx 配置,且改完要重启容器 | 只需要在宿主机写一份标准 Nginx server 配置 |
| 证书更新 | 每次续期后都要重新挂载或重启容器 | 在宿主机更新证书,reload Nginx 即可 |
| 多站点扩展 | 一个容器锁死一个证书域名 | 可以按 server_name 路由多个域名 |
| 升级 OnlyOffice 版本 | 新镜像可能覆盖掉你的自定义配置 | 容器保持默认,代理层不受影响 |
| 问题排查 | 出问题要进容器里查日志 | 链路清晰,宿主 Nginx 日志、容器日志分开看 |
所以在下面的实操环节,我默认采用“宿主机 Nginx 反向代理 + 容器保持 80 端口”的架构。这套方案我在 Ubuntu 20.04/22.04 和 CentOS 7 上都搭过,配置思路完全一致。
1.3 配置 HTTPS 涉及的关键技术点
先捋一下整个链路里的核心要素,避免后面操作时一头雾水:
- TLS 证书:生产环境推荐 Let's Encrypt 免费证书或者云厂商的证书服务;内网测试可以用自签名证书;
- Nginx 反向代理:监听 443,把
/和/websocket请求转发到 OnlyOffice 容器; - WebSocket 代理:OnlyOffice 的协同编辑依赖 WebSocket 长连接,Nginx 必须正确配置 Upgrade 头;
- X-Forwarded-Proto 请求头:让 OnlyOffice 内部知道客户端是通过 HTTPS 访问的,保证生成的下载、回调地址正确;
- JWT 密钥:OnlyOffice 8.x 以后默认开启 JWT 校验,应用服务和文档服务必须保持一致。
这几个点里,WebSocket 和 X-Forwarded-Proto 是配置完 HTTPS 后最容易出问题的细节。很多同学只代理了常规的/路径,结果文档能打开但无法协同编辑;还有的改了 HTTPS 后文档地址正常了,但 OnlyOffice 生成的回调地址又变回了 HTTP,导致保存动作失败,问题就在转发头没设置完整。
2. 配置前的准备与信息梳理
2.1 确认 OnlyOffice 的部署形态
动手之前,先确认你手里的 OnlyOffice 是什么形态。目前最主流的是 Docker 安装的 Document Server,镜像名为onlyoffice/documentserver。也有不少人用 Linux 包直接安装在宿主机上,那种情况 Nginx 会直接占用 80 端口,你配置 HTTPS 的方式会稍微不同。
我用 Docker 部署的场景更多,所以下面的步骤以 Docker 部署为准。如果你是通过 RPM/DEB 包直接安装的,先把/etc/onlyoffice/documentserver/里的配置路径、Nginx 站点配置路径找到,核心思路仍然是再加一层 443 监听或修改默认站点配置。实际操作时,我建议先在浏览器里用http://服务器IP访问一次 OnlyOffice 首页,确认服务本身是健康的,再去搞 HTTPS。否则 HTTPS 配好了发现容器起不来,会干扰排查视线。
2.2 准备域名和证书
HTTPS 证书是绑定域名的。如果还在用裸 IP 访问,先决定一件事:你是否有域名可以把文档服务单独解析出来。强烈建议给 OnlyOffice 分配一个独立域名,比如doc.example.com,不要图省事和业务系统共用域名。独立域名在证书管理、故障隔离、跨域配置方面都省心得多。
证书获取有两条路:
- 如果你有公网域名且服务器有公网 IP,用 Let's Encrypt 是最省钱的方案。装好
certbot后,一条命令就能签发证书,还能配置自动续期。 - 如果服务器只在内网使用,比如企业内网部署的 OA 系统,那可以用自签名证书。浏览器会提示“不安全”,但可以通过把证书导入到企业内部 CA 或各终端信任列表来消除告警。我个人在测试阶段也会用自签名证书,等正式上线前再换受信任的证书。
关于证书文件的路径,Nginx 配置时用到的是两个文件:证书公钥(.crt或.pem)和私钥(.key)。Let's Encrypt 签发的证书一般会存放在/etc/letsencrypt/live/你的域名/目录下,文件分别是fullchain.pem和privkey.pem。
2.3 梳理访问链路与会话流程
在配置前,你脑子里要有一条清晰的请求链路,否则出了问题很难定位。正常的访问流程是这样的:
- 用户打开业务系统页面,业务系统通过 HTTPS 加载
https://doc.example.com/web-apps/apps/api/documents/api.js; - 浏览器向
doc.example.com:443发起请求; - 宿主机 Nginx 接收请求,解密 TLS,转发到本地容器的
127.0.0.1:80; - OnlyOffice 容器处理请求,返回编辑页所需的 JS、CSS、HTML;
- 用户编辑文档时,OnlyOffice 再去请求编辑器的回调地址、协同服务地址、WebSocket 地址。
所以要保证整条链路里所有请求走的都是https://doc.example.com。任何一个环节出现 HTTP 或 IP 直连,浏览器就会出现混合内容或跨域问题。这也是为什么我总是强调:只有域名 + HTTPS 才能做到统一协议。
3. 实操:Nginx 反向代理与 HTTPS 配置
3.1 启动 OnlyOffice 容器的推荐参数
如果还没部署 OnlyOffice,下面是经过我多次实践后的一个可靠启动命令。注意端口映射我建议映射到回环地址,而不是直接-p 80:80,这样宿主机上的 Nginx 通过内网访问,不会把容器直接暴露到外网,安全性更好。
docker run -i -t -d \ --name onlyoffice-document-server \ --restart=always \ -e JWT_ENABLED=true \ -e JWT_SECRET=your-strong-secret-key \ -v /app/onlyoffice/logs:/var/log/onlyoffice \ -v /app/onlyoffice/data:/var/www/onlyoffice/Data \ -v /app/onlyoffice/lib:/var/lib/onlyoffice \ -v /app/onlyoffice/db:/var/lib/postgresql \ -p 127.0.0.1:80:80 \ onlyoffice/documentserver这里有几个参数值得你注意:
JWT_SECRET:默认也是启用的,但如果之前用老版本没配置过,集成时尤其容易遇到“文档服务响应无效”之类的提示。务必记下这个密钥,后面集成业务系统时需要用到。- 数据目录挂载:
Data、lib、db、logs四个目录是官方推荐要挂出来的,否则容器重建后证书、数据库、文档数据全部丢失。 - 端口映射:我在宿主机 Nginx 配置里会把请求转发到
127.0.0.1:80,所以这里映射的是回环地址。如果你图省事之前已经用了-p 80:80,那宿主机 Nginx 再监听 80 就会冲突。处理办法是调整映射端口,或者让 Nginx 直接监听 443 和另一个端口用于跳转,具体看你现场情况。
容器起来后,先用curl http://127.0.0.1测试一下能不能返回 HTML。能返回,说明 Each 层是好的。
3.2 编写 Nginx 反向代理配置
下面是我目前在生产环境使用的一份配置,去掉了无关的动静分离等花活,只保留核心内容,逻辑清晰,好排查。
# 用于将 HTTP 请求统一跳转到 HTTPS server { listen 80; server_name doc.example.com; # 证书自动续期时会用到 /.well-known 路径,要放行 location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { return 301 https://$host$request_uri; } } # HTTPS 正式入口 server { listen 443 ssl; http2 on; server_name doc.example.com; # 证书路径,根据实际环境调整 ssl_certificate /etc/letsencrypt/live/doc.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/doc.example.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; # 上传文档时文件可能比较大,限制设大一些 client_max_body_size 100m; # 超时时间适当放宽,文档转换大文件时不容易断 proxy_connect_timeout 600; proxy_read_timeout 600; proxy_send_timeout 600; location / { proxy_pass http://127.0.0.1:80; 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_buffering off; } # OnlyOffice 协同编辑依赖 WebSocket location /websocket { proxy_pass http://127.0.0.1:80/websocket; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 3600s; proxy_send_timeout 3600s; } }配置里几个容易被忽略的细节,我逐个说明。
第一个是proxy_set_header X-Forwarded-Proto $scheme;。OnlyOffice 内部会根据这个头判断当前请求是 http 还是 https,继而生成正确的回调地址。我曾经建过没有加这个头的环境,结果 HTTPS 访问正常,但保存文档时回调地址写成http://,前端一直报“文档保存失败”,排查了很久才定位到是这个头缺失。
第二个是/websocket的代理。OnlyOffice 各版本的协同编辑模块都在这个路径下,必须把 WebSocket 升级请求原样转发。这里有两个要点:一是proxy_http_version必须设为 1.1,二是必须显式设置Upgrade和Connection头。如果你的在线编辑只是单机单用户,不用多人同时改一份文档,WebSocket 断了可能感知不明显;但只要两人同时编辑,就会立刻暴露。
第三个是proxy_buffering off;。老版本编辑文档时偶尔出现“文件上传失败”,和 Nginx 缓冲导致响应体被截断有关,关闭缓冲后这个问题就没有再出现过。
3.3 证书部署与 Nginx 验证流程
证书文件放到服务器后,记得先检查权限。Nginx 的 master 进程以 root 启动,但 worker 进程通常以 nginx 用户运行,证书私钥文件至少要保证能被 nginx 用户读取,否则 reload 时会报权限错误。一般做法是:
sudo chmod 755 /etc/letsencrypt/live/ sudo chmod 644 /etc/letsencrypt/live/doc.example.com/fullchain.pem sudo chmod 644 /etc/letsencrypt/live/doc.example.com/privkey.pem配置写完后,先做语法检查:
nginx -t看到syntax is ok和test is successful后再 reload:
systemctl reload nginx这时从浏览器访问https://doc.example.com,正常情况下地址栏出现小锁,页面可以正常打开 OnlyOffice 文档编辑器的欢迎页或测试页。
3.4 用 curl 验证 HTTPS 链路
浏览器能访问只能说明基本通了,建议再用 curl 做几个级别的验证,可以快速定位问题在人、网络还是配置。
# 验证证书链和站点响应 curl -v https://doc.example.com/ # 验证 WebSocket 升级是否正常 curl -v -H "Connection: Upgrade" -H "Upgrade: websocket" \ -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: SGVsbG9Xb3JsZGV2LmNvbQ==" \ https://doc.example.com/websocket第一个命令能看出证书是否被信任、是否完整。第二个命令如果返回 101 Switching Protocols,说明 WebSocket 代理是通的。如果返回 200 或 4xx,大概率是 Nginx 没有正确识别 WebSocket 升级请求,去检查proxy_set_header Upgrade和Connection的配置。
4. 应用层联动:让在线编辑真正跑在 HTTPS 下
4.1 前端初始化时的配置修改
OnlyOffice 的编辑器前端初始化代码里,有一段类似这样的配置:
new DocsAPI.DocEditor("placeholder", { document: { fileType: "docx", key: "unique-key", title: "example.docx", url: "https://your-app.example.com/files/download" }, documentType: "word", editorConfig: { callbackUrl: "https://your-app.example.com/callback", lang: "zh-CN", user: { id: "user-001", name: "张三" } }, height: "700px", width: "100%" });在 HTTPS 配置完成后,你要重点检查这里面的url和callbackUrl是不是以https://开头。很多项目里这个地址是后端动态拼接的,如果后端配置的协议还是 HTTP,那么即使用户通过 HTTPS 打开了页面,文档下载请求还是会发到 HTTP 地址,照样被浏览器拦截。
这里我建议后端在生成这些地址时,不要硬编码协议,而是直接读取当前请求的协议头和 Host,确保地址始终与页面保持一致。如果你用的是 Spring Boot、Java、.NET 这类框架,它们的工具类通常能根据X-Forwarded-Proto自动生成正确地址,前提是你已经在 Nginx 里把这个头设置对了。
4.2 JWT 校验与跨域配置
OnlyOffice 8.x 之后,Document Server 默认启用 JWT 鉴权。如果你在容器启动时通过环境变量设置了JWT_SECRET,那么在集成配置里也必须设置同样的密钥。有一种很常见的情况:你在部署时用了默认随机密钥,应用端又没同步,结果前端加载完编辑器后,任何文档操作都报错。解决方案就是统一密钥。
如果你不想用 JWT,可以直接在容器环境变量里加JWT_ENABLED=false。但我不建议生产环境这么干,因为 OnlyOffice 的服务端口通常会在内网暴露,没有鉴权的话任何人都可以调用转换接口,容易被滥用。
跨域的问题在 HTTPS 下反而简单了。因为前端页面和文档服务只要都是相同协议,就可以通过设置Access-Control-Allow-Origin来放行。Nginx 里可以加以下配置来解决一些跨域报错:
add_header Access-Control-Allow-Origin "https://your-app.example.com" always; add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always; add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With" always;不过要小心:如果 OnlyOffice 是给多个不同的业务系统共用,Access-Control-Allow-Origin写死一个域名会挡住其他来源。更稳妥的做法是只保持默认,通过 JWT 和网络策略来控制访问。
4.3 私网地址访问限制问题
这是一个非常隐蔽的坑,只在纯内网部署时会出现。OnlyOffice 出于安全考虑,默认不允许文档服务回调私网 IP或保留网段的地址。比如你的业务系统是http://192.168.1.100:8080,OnlyOffice 回调这个地址时会被它内部直接拒绝,界面上表现就是文档一直打不开或者保存失败。
在 OnlyOffice 较新的版本中,这个限制可以通过环境变量控制。启动容器时加入:
-e ALLOW_PRIVATE_IP_ADDRESS=true如果你用的镜像版本没有这个环境变量,也可以去容器内修改/etc/onlyoffice/documentserver/local.json,把allowPrivateIPAddress改为true,然后重启容器或相关服务。但要注意:这个开关在生产公网环境下会有一定风险,开启前要确保 OnlyOffice 服务不对公网随意开放,最好只用防火墙限制来源 IP。
4.4 多语言与本地化配置
HTTPS 配好后,你会顺手遇到另一个高频问题:英文界面用着别扭,想改成中文。这个和 HTTPS 没有直接关系,但在做 OnlyOffice 集成时几乎是必配项。前端初始化时指定语言:
editorConfig: { lang: "zh-CN" }服务端配置中,可以在容器环境变量里加-e LANGUAGE=zh-CN。不过实际我发现大多数项目是在前端配置里控制界面语言,服务端环境变量更多影响的是模板文档的语言。两个地方建议都设置成中文,避免用户看到的界面和系统语言不一致。
5. 常见问题与排查技巧实录
5.1 高频错误速查表
把我在实际运维中遇到的、以及社区里高频出现的问题整理成下表,每一行都对应一个实际症状,你可以照着快速定位,不用从头到尾扫日志。
| 症状 | 可能原因 | 排查方向 |
|---|---|---|
| 页面报 Mixed Content,编辑器白屏 | 业务系统是 HTTPS,文档服务地址仍是 HTTP | 检查前端加载的 api.js 地址是否以 https 开头 |
| 文档能打开,但保存转圈 | 回调地址是 HTTP 或不可达 | 检查X-Forwarded-Proto、callbackUrl |
| 多人协同编辑不生效 | WebSocket 代理未配置或配置错误 | 检查 Nginx 的 /websocket location |
| 编辑器提示“文档服务响应无效” | JWT 密钥前后端不一致 | 统一容器环境变量和应用端配置 |
| 转换大文件时超时 | Nginx 代理超时太短 | 调大proxy_read_timeout、proxy_send_timeout |
| 证书安装后浏览器提示不安全 | 证书链不完整或自签名证书未信任 | 使用 fullchain 证书,或将自签名证书加入系统信任库 |
| 容器和 Nginx 争抢 80 端口 | 端口映射冲突 | 构建-p 127.0.0.1:80:80的回环映射方式 |
| OnlyOffice 无法访问内网系统 | 私网地址限制 | 设置ALLOW_PRIVATE_IP_ADDRESS=true |
这张表我每次排查 OnlyOffice 问题时都会过一遍,大多数问题都能对号入座。
5.2 从日志入手的排查方法论
界面报错信息往往很模糊,真正有信息量的是日志文件。OnlyOffice 容器主要看这几个日志:
- 容器访问错误日志:
docker logs onlyoffice-document-server,可以看到请求到达情况; - OnlyOffice 自身日志:挂载目录
/app/onlyoffice/logs/下的docservice、converter日志; - Nginx 宿主机访问日志:
/var/log/nginx/access.log和error.log。
我在排查“保存失败”这类问题时,会先同时 tail 三份日志:宿主机 Nginx 日志、OnlyOffice 日志、业务系统日志。打开编辑页后做一次保存动作,观察请求是从哪一步断的:
- 如果宿主机 Nginx 日志里根本没有
/callback请求,说明前端没有发起回调,问题大概率在业务系统的回调地址或 JWT 校验; - 如果 Nginx 有请求但容器日志报 401 或签名错误,那就是密钥不一致;
- 如果容器有请求但报连接超时,可能是文档服务器访问回调地址时网络不通,检查私网限制和防火墙。
这样一个链路一个环节地排除,比盲目改配置有效率得多。
5.3 罕见但坑人的几个细节
前面提到的都是高频问题,下面几个是我实际踩过、但网上很少详细说的细节,特别拿出来提醒你。
第一个是容器重建后数据丢失。如果你没有挂载数据卷,只是用docker run启动容器,后面因为升级或改配置重建容器,会发现文档数据、用户配置全部丢失,小则影响使用,大则造成工作成果丢失。我碰到过不止一次。所以部署 OnlyOffice 时一定要把数据和配置目录挂出来,这比 HTTPS 配置本身还重要。
第二个是证书自动续期后忘记 reload Nginx。Let's Encrypt 证书有效期是 90 天,certbot 自动续期成功后只是把新证书写到磁盘,Nginx 并不会自动加载新证书。如果续期后不systemctl reload nginx,在证书到期后的很长一段时间里,客户端访问会出现证书不匹配或直接无法连接。解决方法是配置一条--deploy-hook "systemctl reload nginx"的续期钩子,这个我在自动化脚本里加上后再没出过问题。
第三个是 IPv6 的坑。如果你的服务器开启了 IPv6,而 DNS 解析返回了 AAAA 记录,Nginx 默认只监听 IPv4 的 443 端口时,用户访问会长时间无法连接。遇到这种问题,检查 Nginx 的 listen 指令是否有[::]:443,没有的话加上,或者干脆把 DNS 的 AAAA 记录删掉,只保留 A 记录。这个坑很隐蔽,因为很多问题排查顺序是从证书、代理配置开始,很少有人会想到是 IPv6 监听问题。
第四个是 OnlyOffice 版本升级带来的配置变化。我在多个项目里从 7.x 升到 8.x 时,发现 JWT 默认启用策略有变化,原有的环境变量部分失效,导致集成方报错。升级前务必先看官方 Release Notes,尤其是关于环境变量、JWT、配置文件的变更说明,再决定升级步骤。
最后一个建议:把所有配置尽量都放到容器环境变量和 Nginx 配置里,不要靠每次启动后进容器手改配置文件。因为容器是临时的,重建后一切手工修改都会丢失。我自己的做法是写一份 docker-compose.yml 托管 OnlyOffice 和环境变量,Nginx 配置也放进版本控制,这样无论在哪台机器上重新部署,只要跑一遍 compose 和 Nginx 配置文件,环境就能完整复现。这个习惯帮我省了非常多重复排障的时间。
实际生产环境里,我还见过有人把 OnlyOffice 放在办公室内网,外部访问通过内网穿透到公网域名。这种场景下 HTTPS 配置思路是一样的,但要多注意内网穿透工具本身的 TLS 卸载和 Nginx 证书冲突问题。建议只在一层做 TLS 终结,不要层层加密、层层解密,否则问题会非常难以排查。我个人的体会是,OnlyOffice 配置 HTTPS 本身并不复杂,真正的复杂度在于你要对整个请求链路的每一跳都有数,从 DNS 到 Nginx,再到容器内服务,哪一层掉了链子都会表现为“文档打不开”。按本文的顺序把证书、代理、WebSocket、转发头都做对,再配合日志逐层排查,基本就能稳住了。