拓冰建站拓冰建站
首页 / 资讯中心 / 正文

OnlyOffice 打开文档提示“下载失败”,但浏览器明明能访问,怎么解决?

OnlyOffice 打开文档提示“下载失败”但浏览器明明能访问怎么解决一、问题现象服务器上部署了两个服务文档系统运行在 Linux 宿主机 OnlyOffice运行在 Docker 容器文档系统本身在内网运行比如http://PRIVATE_IP:INNER_PORT同时做了公网端口映射PUBLIC_IP:PUBLIC_PORT ↓ PRIVATE_IP:INNER_PORT外部电脑浏览器访问http://PUBLIC_IP:PUBLIC_PORT完全正常。但是在系统里使用 OnlyOffice 打开 Word 文档时却提示错误 下载失败查看 OnlyOffice 日志还能看到类似connect ETIMEDOUT PUBLIC_IP:PUBLIC_PORT也就是说OnlyOffice 想通过公网地址下载文档但是连接超时了。二、最容易误判的地方刚开始看到这个问题很容易想浏览器明明能打开公网地址 为什么 OnlyOffice 说下载失败原因其实很简单浏览器和 OnlyOffice 不是在同一个网络环境里。浏览器访问公网地址的过程你的电脑 ↓ 公网地址 ↓ 服务器这是正常的。但 OnlyOffice 运行在 Docker 里面。它访问公网地址时过程变成Docker 容器 ↓ 访问服务器公网地址 ↓ 公网路由器 ↓ 又想绕回来访问这台服务器有些网络设备不支持这种“出去以后再绕回来”的访问方式。所以就会出现浏览器访问公网地址 正常 Docker 访问公网地址 超时这种问题一般叫NAT 回流 Hairpin NAT NAT Loopback其实不用记名字。你只需要理解Docker 想通过公网 IP 绕一圈再访问同一台服务器结果绕不回来。三、第一步先确认文档服务本身有没有问题先不要急着改 OnlyOffice。直接在宿主机执行curl http://127.0.0.1:INNER_PORT/如果返回HTTP/1.1 200说明服务正常。再执行curl http://PRIVATE_IP:INNER_PORT/如果也正常返回HTTP/1.1 200说明内网访问也没问题。此时可以确定文档服务正常 内网端口正常四、第二步确认公网映射有没有问题直接在外部电脑或者手机流量环境访问http://PUBLIC_IP:PUBLIC_PORT如果浏览器可以正常打开就说明公网地址正常 公网端口映射正常此时不要再一直排查Nginx 端口映射 程序是否启动因为这些基本已经正常。五、第三步进入 OnlyOffice 容器测试这一步最关键。先查看容器docker ps找到 OnlyOffice 容器名称。假设容器名称是onlyoffice进入容器docker exec -it onlyoffice bash然后在容器里测试公网地址curl -v --connect-timeout 5 http://PUBLIC_IP:PUBLIC_PORT/如果出现Trying PUBLIC_IP...然后一直等待最后超时Connection timed out说明 Docker 容器确实访问不了这个公网地址。六、再测试 Docker 能不能直接访问内网地址还在 OnlyOffice 容器里面执行curl -v --connect-timeout 5 http://PRIVATE_IP:INNER_PORT/如果这个可以正常返回HTTP/1.1 200那问题基本就确定了。现在的状态是宿主机 → 内网地址 正常 外部浏览器 → 公网地址 正常 Docker → 内网地址 正常 Docker → 公网地址 超时这种情况下问题基本不是 OnlyOffice 本身。而是Docker 容器无法通过公网 IP 再绕回来访问宿主机服务。七、解决思路我这里不想改程序。程序里面原来访问的是http://PUBLIC_IP:PUBLIC_PORT希望继续保持不变。所以解决办法是Docker 访问公网地址时不让它真的去公网绕一圈而是在 Linux 服务器内部直接把它转到内网地址。比如Docker 原本访问 PUBLIC_IP:PUBLIC_PORT 实际上帮它转成 PRIVATE_IP:INNER_PORT这样程序不用改 OnlyOffice 配置不用改 公网地址不用改八、先查看 Docker 的网段不要直接照抄网上常见的172.17.0.0/16因为不同 Docker 环境的网段可能不一样。先执行docker network ls然后docker network inspect bridge或者直接查看 OnlyOfficedocker inspect onlyoffice找到类似Subnet IPAddress Gateway例如你可能看到Subnet: 172.xx.0.0/16把这个网段记下来。下面统一写成DOCKER_SUBNET九、添加 iptables 规则在宿主机执行iptables -t nat -A PREROUTING \ -s DOCKER_SUBNET \ -p tcp \ -d PUBLIC_IP \ --dport PUBLIC_PORT \ -j DNAT \ --to-destination PRIVATE_IP:INNER_PORT写成一行就是iptables -t nat -A PREROUTING -s DOCKER_SUBNET -p tcp -d PUBLIC_IP --dport PUBLIC_PORT -j DNAT --to-destination PRIVATE_IP:INNER_PORT需要替换DOCKER_SUBNET PUBLIC_IP PUBLIC_PORT PRIVATE_IP INNER_PORT为自己的实际配置。十、这条命令到底干了什么其实非常简单。原来 Docker 想走Docker ↓ PUBLIC_IP:PUBLIC_PORT ↓ 公网 ↓ 再回来现在改成Docker ↓ PUBLIC_IP:PUBLIC_PORT ↓ Linux 发现这个请求 ↓ 直接改成 PRIVATE_IP:INNER_PORT ↓ 文档服务相当于走了一个内部“捷径”。程序本身根本不知道地址被转换了。十一、添加规则以后重新测试再次进入 OnlyOfficedocker exec -it onlyoffice bash然后执行curl -v --connect-timeout 5 http://PUBLIC_IP:PUBLIC_PORT/如果现在可以看到Connected to PUBLIC_IP并且返回HTTP/1.1 200说明问题已经解决。然后再测试实际文档curl -I http://PUBLIC_IP:PUBLIC_PORT/xxx/test.docx如果也能正常返回就可以重新打开 OnlyOffice。之前的下载失败一般就会消失。十二、怎么看规则有没有生效宿主机执行iptables -t nat -L PREROUTING -n -v --line-numbers如果看到类似DNAT tcp -- DOCKER_SUBNET PUBLIC_IP tcp dpt:PUBLIC_PORT to:PRIVATE_IP:INNER_PORT就说明规则已经存在。前面的pkts bytes如果随着 OnlyOffice 打开文档不断增加说明这条规则正在被使用。十三、为什么不能用 OUTPUT这里有个很重要的区别。如果是Linux 宿主机自己的程序访问公网地址可以用OUTPUT例如iptables -t nat -A OUTPUT ...但是 OnlyOffice 是Docker 容器Docker 的数据是从虚拟网卡进入宿主机的。所以应该使用PREROUTING也就是iptables -t nat -A PREROUTING ...简单记宿主机自己访问 → OUTPUT Docker 容器访问 → PREROUTING十四、为什么修改 Nginx 超时时间没用一开始排查 OnlyOffice 下载失败很多人都会去改proxy_connect_timeout proxy_read_timeout proxy_send_timeout client_body_timeout client_max_body_size但如果日志已经明确显示connect ETIMEDOUT而且 Docker 容器里执行curl PUBLIC_IP:PUBLIC_PORT都连接不上。那问题根本还没走到 Nginx 业务处理这一层。也就是说TCP 连接都没建立成功这时候把60 秒改成600 秒只是让它多等一会儿。最终还是超时。所以遇到这种情况优先在 Docker 里面用 curl 测试网络。十五、重启服务器后规则会不会丢会有可能。直接执行的iptables -t nat -A PREROUTING ...属于运行时配置。服务器重启以后可能没有了。所以需要设置成开机自动执行。十六、使用 systemd 实现开机自动添加创建/etc/systemd/system/docker-local-nat.service执行cat /etc/systemd/system/docker-local-nat.service EOF [Unit] DescriptionDocker Local NAT Loopback Afternetwork-online.target docker.service Wantsnetwork-online.target Requiresdocker.service [Service] Typeoneshot RemainAfterExityes ExecStart/bin/sh -c /usr/sbin/iptables -t nat -C PREROUTING -s DOCKER_SUBNET -p tcp -d PUBLIC_IP --dport PUBLIC_PORT -j DNAT --to-destination PRIVATE_IP:INNER_PORT 2/dev/null || /usr/sbin/iptables -t nat -A PREROUTING -s DOCKER_SUBNET -p tcp -d PUBLIC_IP --dport PUBLIC_PORT -j DNAT --to-destination PRIVATE_IP:INNER_PORT ExecStop/bin/sh -c /usr/sbin/iptables -t nat -C PREROUTING -s DOCKER_SUBNET -p tcp -d PUBLIC_IP --dport PUBLIC_PORT -j DNAT --to-destination PRIVATE_IP:INNER_PORT 2/dev/null /usr/sbin/iptables -t nat -D PREROUTING -s DOCKER_SUBNET -p tcp -d PUBLIC_IP --dport PUBLIC_PORT -j DNAT --to-destination PRIVATE_IP:INNER_PORT || true [Install] WantedBymulti-user.target EOF记得把DOCKER_SUBNET PUBLIC_IP PUBLIC_PORT PRIVATE_IP INNER_PORT全部替换成自己的地址。十七、开启开机自启执行systemctl daemon-reload然后systemctl enable --now docker-local-nat.service检查systemctl status docker-local-nat.service看到Active: active (exited)是正常的。因为它只是在启动时执行一次 iptables 命令。十八、确认是不是开机自动启动执行systemctl is-enabled docker-local-nat.service如果返回enabled说明已经设置成功。服务器下次重启以后会自动添加这条规则。十九、完整排查流程以后如果再遇到OnlyOffice 下载失败建议按这个顺序查。先在宿主机curl http://127.0.0.1:INNER_PORT正常再测试curl http://PRIVATE_IP:INNER_PORT正常再从外部浏览器访问http://PUBLIC_IP:PUBLIC_PORT正常再进入 Dockerdocker exec -it onlyoffice bash测试内网curl http://PRIVATE_IP:INNER_PORT再测试公网curl --connect-timeout 5 http://PUBLIC_IP:PUBLIC_PORT如果最终结果是宿主机访问内网 正常 外部访问公网 正常 Docker 访问内网 正常 Docker 访问公网 超时那基本就可以判断Docker NAT 回流问题二十、最后总结这个问题最迷惑人的地方就是明明浏览器可以打开公网地址为什么 OnlyOffice 还是提示下载失败原因是浏览器和OnlyOffice Docker 容器走的不是同一条网络路径。外部浏览器访问正常并不能证明 Docker 容器也能访问。最终解决方式就是Docker 原来访问 PUBLIC_IP:PUBLIC_PORT 通过 iptables 自动转换成 PRIVATE_IP:INNER_PORT核心命令iptables -t nat -A PREROUTING -s DOCKER_SUBNET -p tcp -d PUBLIC_IP --dport PUBLIC_PORT -j DNAT --to-destination PRIVATE_IP:INNER_PORT这样实现不用改程序 不用改 OnlyOffice 不用改公网地址 不用让 Docker 真正绕公网一圈最后再通过 systemd 设置成开机自动执行即可。如果你遇到的现象是浏览器公网访问正常 Docker 内网访问正常 Docker 公网访问超时 OnlyOffice 报 ETIMEDOUT / 下载失败优先检查 NAT 回流不要一直在 Nginx 超时时间上打转。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门