使用Docker部署NextCloud和Onlyoffice
使用Docker部署NextCloud和Onlyoffice
Nextcloud 是目前最流行的开源私有云盘方案,而 OnlyOffice 提供了强大的在线文档编辑能力。两者结合可以实现文档在线编辑和协作。
但在实际部署中,会遇到很多问题,本文记录部署过程和一些问题及解决方法。
环境准备
环境介绍
以下是我使用的硬件和软件情况
| 项目 | 版本 |
|---|---|
| 架构 | x64 |
| CPU核心 | 8核 |
| 内存 | 16G |
| 操作系统 | Linux(Fedora 43) |
| Docker | Docker version 29.5.3 |
| Docker Compose | Docker Compose version v5.1.4 |
硬件要求
| 项目 | 要求 |
|---|---|
| 内存 | 4G以上(推荐8G) |
| 磁盘 | 20G以上可用空间 |
使用镜像
| 服务 | 镜像 |
|---|---|
| Nextcloud | linuxserver/nextcloud:34.0.0 |
| onlyoffice | onlyoffice/documentserver:9.4.0.1 |
拉取镜像
可以先不用拉取镜像,使用compose部署会自动拉取
docker pull linuxserver/nextcloud:34.0.0
docker pull onlyoffice/documentserver:9.4.0.1
检查环境:
使用以下命令检查docker/docker compose
docker --v
docker compose version
输出版本即表示docker已安装,如果没有安装,需要安装一下可以参考Linux一键安装Docker。
文件准备
运行目录
安装nextcloud和onlyoffice之前,先创建运行目录
mkdir -p /data/container/nextcloud-onlyoffice && cd /data/container/nextcloud-onlyoffice
docker-compose.yml
vim docker-compose.yml
写入以下内容
services:
# ===== Nextcloud (linuxserver 镜像) =====
nextcloud:
image: linuxserver/nextcloud:34.0.0
container_name: nextcloud
restart: unless-stopped
ports:
- "8080:80"
- "8443:443" # HTTPS 端口(可选)
volumes:
- ./nextcloud/config:/config # Nextcloud 程序 + 配置
- ./nextcloud/data:/data # 用户数据
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
networks:
- 1panel-network
# ===== OnlyOffice Document Server =====
onlyoffice:
image: onlyoffice/documentserver:latest
container_name: onlyoffice
restart: unless-stopped
ports:
- "8090:80"
volumes:
- ./onlyoffice/data:/var/www/onlyoffice/Data
- ./onlyoffice/config:/etc/onlyoffice/documentserver
- ./onlyoffice/logs:/var/log/onlyoffice
- ./onlyoffice/fonts:/usr/share/fonts/truetype/custom
environment:
# ⭐ 关键:必须手动指定 JWT 密钥(否则重启后密钥变化导致连接断开)
- JWT_SECRET=${JWT_SECRET}
- JWT_HEADER=${JWT_HEADER}
- JWT_ENABLED=true
- ALLOW_PRIVATE_IP_ADDRESS=true
- TZ=${TZ}
networks:
- 1panel-network
# ==== 网络,我的redis和mysql使用1panel部署的,使用同一网络
networks:
1panel-network:
external: true
环境变量
vim .env
写入以下内容,按需修改
# ===== Nextcloud 配置 =====
# ===== 用户权限=====
PUID=1000
PGID=1000
# ===== OnlyOffice JWT 密钥(如果启用必须手动指定,否则容器重启后会重新生成导致连接断开)=====
JWT_SECRET=你的随机密钥至少32位
JWT_HEADER=AuthorizationJwt
# ===== 时区 =====
TZ=Asia/Shanghai
准备中文字体
onlyoffice缺少中文字体(应该是有的,但是仅仅能显示中文而已,常用的字体基本都没有)。准备字体文件,在 /data/container/nextcloud-onlyoffice目录下新建 onlyoffice/fonts目录(docker-compose.yml中指定的目录),将字体文件放在该目录
初始化
启动容器
完成compose和.env后,启动容器
docker compose up -d
等待容器创建并启动,如果前边没有拉取镜像,这里会自动拉取
初始化Nextcloud
初始化之前可以先配置以下域名,自行配置nginx代理(抽空补充)。
使用浏览器访问http://<your_ip>:<nextcloud_http_port>或者配置的域名,设置管理员用户名和密码,并输入数据库信息,这里使用MySQL/MariaDB(我只比较熟悉MySQL)数据库需要提前创建。如果数据库使用root用户,不提前创建也行,不过不能与已有数据库名重复。
等待初始化完成,会展示推荐的应用,直接跳过,随后再安装
集成onlyoffice
进入NextCloud后,点击头像 --> 应用,找到Office & Text,点一下Nextcloud Office,输入密码开始安装。

安装完成后点击头像 --> 管理设置,找到ONLYOFFICE,填写配置项,然后点保存即可。如果保存报错 连接时发生异常 (文档服务内部发生异常: Error while downloading the document file to be converted.),可以查看配置可信域名
ONLYOFFICE Docs地址:http://<your_ip>:<onlyoffice_http_port> ## 或nginx配置的onlyoffice域名,如果要公网访问,必须使用域名或者有公网IP直接使用公网IP也行,推荐域名。如果只是局域网使用,ip:端口即可
秘钥: .env中设置的JWT_SECRET
授权标头: .env中设置的JWT_HEADER
服务器内部请求 ONLYOFFICE Docs 的地址: http://onlyoffice容器名
ONLYOFFICE Docs 内部请求服务器的地址: http://nextcloud容器名

完善配置
安装好之后,实际上使用过程中还会遇到一些问题,下面列出一些我遇到的问题及解决方案(有些其实也没有完全解决,也是能用就凑合着用了),还有一些优化的配置。
配置可信域名
Nextcloud 默认只允许初始化时的域名或 IP 访问,通过其他 IP 或域名访问时会提示"通过不受信任的域访问"。前边集成ONlyOffice提到的报错其实也是这个原因。添加信任的域名即可。
方案一:通过occ命令添加
# 查看当前可信域名
docker exec nextcloud occ config:system:get trusted_domains
# 添加新的可信域名
docker exec Nextcloud occ config:system:set trusted_domains 1 --value=cloud.example.com # nginx中配置的域名
docker exec Nextcloud occ config:system:set trusted_domains 2 --value=nextcloud # Nextcloud容器名
docker exec Nextcloud occ config:system:set trusted_domains 2 --value=192.168.0.100 # Nextcloud所在服务器的局域网IP
方案二:直接编辑配置文件
- 进入容器运行目录:
cd /data/container/nextcloud-onluoffice
- 编辑配置文件
config.php:
vim nextcloud/config/www/nextcloud/config/config.php
- 按照下面的修改,把需要访问Nextcloud
'trusted_domains' =>
array (
0 => 'cloud.example.com', // nginx中配置的域名
1 => 'Nextcloud', // Nextcloud容器名
2 => '192.168.0.100', // Nextcloud所在服务器的局域网IP
),
添加后再使用trusted_domains中的域名或IP访问就不会报错了,ONlyOffice的连接报错也解决了。
准备中文字体
如果启动容器之前准备好了字体,可以跳过
OnlyOffice缺少中文字体(应该是有的,但是仅仅能显示中文而已,常用的字体基本都没有)。准备字体文件,在 /data/container/nextcloud-onluoffice目录下新建 ONlyOffice/fonts目录(docker-compose.yml中指定的目录),将字体文件放在该目录。
重建OnlyOffice
cd /data/container/nextcloud-onluoffice
docker compose stop onluoffice && docker rm onluoffice && docker compose up -d onluoffice
或者两个容器全都重建,数据已经持久化到宿主机,不会丢失
cd /data/container/nextcloud-onluoffice
docker compose down && docker compose up -d
重建字体缓存
理论上重建容器之后字体会立即生效,可以执行以下命令查看一下,如果输出了添加的字体,就不用执行重建缓存命令了
fc-list :lang=zh
如果没有添加的字体,执行以下命令,等待执行完成即可
docker exec -it onluoffice bash /usr/bin/documentserver-generate-allfonts.sh
Nextcloud显示真实IP
如果使用nginx代理,可能会出现Nextcloud中显示的访问IP为nginx服务器IP,如图中所示,Nextcloud显示的IP是我的nginx服务器在OpenVPN虚拟虚拟局域网中的IP,即使nginx配置了转发真实IP,也没有生效。

原因是请求经过了 客户端 → 公网 Nginx → OpenVPN 隧道 → 内网 Nextcloud 的多层转发。Nginx 虽然设置了 X-Forwarded-For,但 OpenVPN 隧道会建立一个新的 TCP 连接,导致 remote_addr 变成 VPN 虚拟 IP。内网的 Nextcloud 需要正确信任代理链才能获取到真实 IP。使用其他组网方案会不会有这个问题我没有尝试,如果有,也可以尝试这个方案。
修改config.php配置文件,添加如下配置
'trusted_proxies' =>
array (
0 => '10.0.0.1/24', // OpenVPN 虚拟网段 或 局域网网段
1 => '172.16.0.0/12', // Docker 内部网段
),
修改后保存即可生效,不必重启容器

配置Redis
修改config.php配置文件,添加Redis连接配置
'memcache.local' => '\\OC\\Memcache\\Redis',
'memcache.distributed' => '\\OC\\Memcache\\Redis',
'memcache.locking' => '\\OC\\Memcache\\Redis',
'redis' =>
array (
'host' => '你的Redis容器名或IP', // 如 redis、172.18.0.5 等
'password' => '你的Redis密码',
'port' => 6379,
),
解决概览中的警告
打开管理设置-->概览,可以看到有很多警告信息,⚠是功能缺失和安全隐患,ℹ是优化建议。其中“日志中的错误”可以不用管。处理了日志中的错误这个警告也会在,除非将日志清理掉。
这里只解决⚠。

维护窗口启动
这个警告的意思是,Nextcloud 目前不知道你的服务器在什么时间段访问量最少,因此一些消耗资源的后台任务(比如清理临时文件、生成缩略图)可能会在用户活跃的时间段运行,影响使用体验。要解决这个问题,可以设置maintenance_window_start参数,假设希望任务在凌晨3点执行,在config.php中添加:
'maintenance_window_start' => 19,
因为Nextcloud使用UTC时间,所以北京时间需要-8
可用的 Mimetype 迁移
这个设计主要是出于性能考量。当 Nextcloud 升级后,系统可能会引入新的 MIME 类型来更准确地识别文件。对于文件数量庞大的实例,这种数据库迁移可能会消耗较多资源,所以官方没有在升级时自动执行,而是将它设计成了一个需要管理员确认的手动操作。
根据提示执行命令即可
docker exec -it nextcloud occ maintenance:repair --include-expensive
HTTP标头
如果只在局域网中使用,没有配置域名和SSL证书,可以跳过这个。
这个安全警告意味着你的 Nextcloud 服务器没有发送 Strict-Transport-Security (HSTS) 这个关键的 HTTP 响应头。配置它可以让浏览器强制使用 HTTPS 访问你的站点,有效防范中间人攻击。
修复方法是在Nginx中配置中添加一个响应头:
## 在server块中添加
add_header Strict-Transport-Security "max-age=63072000" always
需要注意的一点是,只在nginx代理服务器中配置,警告并不会消失,在容器内的nginx配置也要同步添加,修改文件nextcloud/data/config/nginx/ssl.conf
修改后重载配置:
docker exec -it nextcloud nginx -s reload
Nextcloud卡死的解决
我在使用时遇到Nextcloud时不时就卡死的问题,网络上查找相关解决方案没什么收获,就跟着AI一通改,根本原因目前不是很清楚,但是修改之后确实很少再出现了,先记录一下,以后再遇到在研究。
下边是几个可能的原因
内存不足
Nextcloud + OnlyOffice对内存的要求是比较高的,如果内存不足,上传大文件或OnlyOffice转换时可能会OOM。不过我的内存充足,且没有限制容器内存,应该不是这个问题(有可能是默认的配置有内存限制,没有深入研究)
字体缺失
这里使用的是linuxserver/nextcloud,默认是不含中文字体的,生成含中文文档缩略图时进程挂死,累积后耗尽 PHP-FPM 进程池导致卡死。但是Nextcloud 容器只在极少数场景下需要服务端字体(如内置 PDF 缩略图生成)。如果已用 OnlyOffice 处理文档预览,一般不需要配置。这个作为可选配置,参考OnlyOffice的中文字体配置。不为Nextcloud添加中文字体的话,勾选 使用ONLYOFFICE生成文档预览。

PHP 内存不足
与上述内存不足不太一样,前边提到的内存不足是容器内存不足,这里的PHP内存指的是设置的内存限制。修改配置文件 nextcloud/config/php/www2.ini:
; ===== 上传和文件大小限制 / Upload and file size limits =====
upload_max_filesize = 10G
post_max_size = 10G
max_input_time = 3600
max_execution_time = 3600
; ===== 内存限制 / Memory limit =====
memory_limit = 1024M
; ===== OPcache 优化(大幅提升性能)/ OPcache optimization =====
opcache.enable=1
opcache.interned_strings_buffer=32
opcache.max_accelerated_files=10000
opcache.memory_consumption=256
opcache.save_comments=1
opcache.revalidate_freq=1
上传文件大小的配置,如果使用了Nginx反向代理,需同步配置
client_max_body_size 10G;
client_body_timeout 3600s;
client_header_timeout 3600s;
proxy_read_timeout 3600s;
proxy_connect_timeout 3600s;
proxy_send_timeout 3600s;
数据库死锁
Nextcloud 默认用数据库锁,并发时死锁/长等待,这是最常见的卡死原因,使用Redis做文件锁,参考配置Redis添加Redis配置即可。
PHP-FPM 进程池耗尽
这个不是造成Nextcloud卡死的原因,而是上述问题造成了PHP-FPM 进程池耗尽从而导致Nextcloud卡死,通常表现为浏览器访问Nextcloud 502。
编辑 nextcloud/config/php/www2.ini,调整 PHP-FPM 进程数:
; PHP-FPM 进程池配置 / PHP-FPM process pool
pm = dynamic
pm.max_children = 20 ; 最大子进程数 / max child processes
pm.start_servers = 4 ; 启动时进程数 / processes at startup
pm.min_spare_servers = 2 ; 最小空闲进程 / min spare processes
pm.max_spare_servers = 6 ; 最大空闲进程 / max spare servers
pm.max_requests = 500 ; 每个进程处理请求数后重启 / requests per process before respawn