LWluswen / JUSTIN
← 返回文章

Entry / 云服务

服务器配置nextcloud

由caddy反代

7 分钟阅读作者:Justin
Internet
   │
   │ HTTPS :443
   ▼
现有 Caddy
   │
   │ HTTP,仅本机
   ▼
127.0.0.1:11080
   │
   ▼
Nextcloud 35 Apache 容器
   ├── MariaDB
   ├── Redis
   └── Cron

Caddy 继续独占 80/443;Nextcloud 绝不直接监听公网。 我们只给现有 Caddy 增加一个域名反代,不修改现有站点。Nextcloud 官方 Docker 示例本身就支持把 Apache 容器绑定到 127.0.0.1:8080 后交给外部反代,因此这种部署方式是标准做法。

截至 2026 年 9 月 29 日,Nextcloud 35 是当前主版本,35.0.1 已发布;下面固定在 35-apache 主版本系列,避免未来突然跨大版本升级。


1. 准备域名

假设你准备使用:

cloud.example.com

把:

cloud.example.com

的 DNS A 记录指向 Rocky Linux 服务器的公网 IPv4。

如果服务器有 IPv6,也可以配置 AAAA。

由于你的 Caddy 已经正常代理其他服务:

  • 不需要额外开放端口
  • 不开放 11080
  • 继续只开放 80/443

Caddy 在域名正确解析到服务器、80/443 可达的情况下,可以自动申请并续期 HTTPS 证书。

下面把:

cloud.example.com

替换成你的真实域名即可。


2. 检查现有 Caddy

先不要动 Caddy 配置。

执行:

sudo systemctl status caddy

然后:

sudo caddy validate --config /etc/caddy/Caddyfile

应该看到类似:

Valid configuration

备份现有配置:

sudo cp -a /etc/caddy/Caddyfile /etc/caddy/Caddyfile.backup

这一点很重要。整个过程中我们只会:

添加 Nextcloud 的站点块
↓
caddy validate
↓
systemctl reload caddy

不会 restart Caddy,也不会覆盖你已有的反代配置。


3. 安装 Docker

如果已经安装 Docker 和 Compose,可以直接跳到第 4 步。

Rocky Linux 9 属于 RHEL 兼容发行版。Docker 官方 RPM 仓库提供 Docker Engine、containerd、Buildx 和 Compose Plugin;Docker 官方同时提醒,衍生发行版并不属于其直接验证的平台。

安装仓库:

sudo dnf install -y dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

安装:

sudo dnf install -y \
    docker-ce \
    docker-ce-cli \
    containerd.io \
    docker-buildx-plugin \
    docker-compose-plugin

启动:

sudo systemctl enable --now docker

检查:

sudo docker version

以及:

sudo docker compose version

Docker 官方目前推荐使用:

docker compose

而不是旧的:

docker-compose

Compose Plugin 是当前官方安装方式。


4. 创建 Nextcloud 项目目录

我建议统一放在:

/opt/nextcloud

执行:

sudo mkdir -p /opt/nextcloud
cd /opt/nextcloud

为了后续编辑方便:

sudo nano .env

填写:

NEXTCLOUD_DOMAIN=cloud.example.com

DB_ROOT_PASSWORD=这里填写一个很长的MariaDB-root密码
DB_PASSWORD=这里填写另一个很长的Nextcloud数据库密码

例如密码至少建议 32 位随机字符。

可以用:

openssl rand -base64 32

分别生成两次。

然后:

sudo chmod 600 /opt/nextcloud/.env

5. 创建 Docker Compose

执行:

sudo nano /opt/nextcloud/compose.yaml

写入:

services:
  db:
    image: mariadb:lts
    container_name: nextcloud-db
    restart: unless-stopped

    command:
      - --transaction-isolation=READ-COMMITTED

    volumes:
      - nextcloud_db:/var/lib/mysql

    environment:
      MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      MARIADB_DATABASE: nextcloud
      MARIADB_USER: nextcloud
      MARIADB_PASSWORD: ${DB_PASSWORD}
      MARIADB_AUTO_UPGRADE: "1"
      MARIADB_DISABLE_UPGRADE_BACKUP: "1"

  redis:
    image: redis:alpine
    container_name: nextcloud-redis
    restart: unless-stopped

  app:
    image: nextcloud:35-apache
    container_name: nextcloud-app
    restart: unless-stopped

    depends_on:
      - db
      - redis

    ports:
      - "127.0.0.1:11080:80"

    volumes:
      - nextcloud_html:/var/www/html

    environment:
      MYSQL_HOST: db
      MYSQL_DATABASE: nextcloud
      MYSQL_USER: nextcloud
      MYSQL_PASSWORD: ${DB_PASSWORD}

      REDIS_HOST: redis

      NEXTCLOUD_TRUSTED_DOMAINS: ${NEXTCLOUD_DOMAIN}

      APACHE_DISABLE_REWRITE_IP: "1"
      TRUSTED_PROXIES: "172.16.0.0/12"

      OVERWRITEPROTOCOL: https
      OVERWRITECLIURL: https://${NEXTCLOUD_DOMAIN}

      PHP_MEMORY_LIMIT: 512M
      PHP_UPLOAD_LIMIT: 2G
      APACHE_BODY_LIMIT: 0

  cron:
    image: nextcloud:35-apache
    container_name: nextcloud-cron
    restart: unless-stopped

    entrypoint: /cron.sh

    depends_on:
      - db
      - redis

    volumes:
      - nextcloud_html:/var/www/html

volumes:
  nextcloud_db:
  nextcloud_html:

这个结构基本直接沿用了 Nextcloud 官方 Compose 架构:MariaDB + Redis + Apache + Cron,并且 app 与 cron 使用相同的 Nextcloud volume。


6. 为什么这里用了 Redis

对于单纯的 Notability 备份,其实没有 Redis Nextcloud 也能运行。

但我仍建议部署。

Nextcloud 官方建议 Redis 用于:

  • 分布式缓存
  • Transactional File Locking
  • 降低数据库锁开销
  • 避免并发上传时对数据库造成额外压力

尤其 WebDAV 会不断上传、覆盖文件,Redis 文件锁对这种工作负载比较合适。

我们的 Redis:

没有 ports:

所以:

公网 → 不能访问 Redis
宿主机公网 IP → 也没有暴露 6379

只有 Docker 内部的 Nextcloud 可以访问。


7. 为什么 Nextcloud 只监听 127.0.0.1

关键配置是:

ports:
  - "127.0.0.1:11080:80"

而不是:

ports:
  - "11080:80"

这样:

公网 → 服务器IP:11080

不能直接访问。

只有:

服务器本机 → 127.0.0.1:11080

可以访问。

所以流量只能是:

iPad
 ↓
HTTPS
 ↓
Caddy :443
 ↓
127.0.0.1:11080
 ↓
Nextcloud

这也是 Nextcloud 官方 Docker 示例使用的模式。


8. 启动 Nextcloud

执行:

cd /opt/nextcloud

先检查 Compose:

sudo docker compose config

没有错误后:

sudo docker compose pull

然后:

sudo docker compose up -d

查看:

sudo docker compose ps

应该看到:

nextcloud-app
nextcloud-cron
nextcloud-db
nextcloud-redis

都是 Running。


9. 检查 Nextcloud 本地端口

服务器上执行:

curl -I http://127.0.0.1:11080

正常情况下会得到:

HTTP/1.1 200 OK

或者初始化阶段可能是:

HTTP/1.1 302 Found

都属于正常。

再检查:

sudo ss -lntp | grep 11080

你应该看到类似:

127.0.0.1:11080

不应该是:

0.0.0.0:11080

这一点尤其重要。


10. 配置现有 Caddy

现在才修改 Caddy。

打开:

sudo nano /etc/caddy/Caddyfile

⚠️ 保留里面所有已有内容。

假设现在是:

a.example.com {
    reverse_proxy 192.168.1.10:8080
}

b.example.com {
    reverse_proxy 127.0.0.1:9000
}

不要删除。

只在后面增加:

cloud.example.com {
    header Strict-Transport-Security "max-age=15552000"

    reverse_proxy 127.0.0.1:11080
}

最终类似:

a.example.com {
    reverse_proxy 192.168.1.10:8080
}

b.example.com {
    reverse_proxy 127.0.0.1:9000
}

cloud.example.com {
    header Strict-Transport-Security "max-age=15552000"

    reverse_proxy 127.0.0.1:11080
}

不要给 Caddy 配另外的 80/443。

Caddy 的 reverse_proxy 默认会设置:

X-Forwarded-For
X-Forwarded-Proto
X-Forwarded-Host

这正是 Nextcloud 判断外部真实 HTTPS 地址和客户端 IP 所需要的信息。


11. 先验证 Caddy,千万不要直接重启

执行:

sudo caddy validate --config /etc/caddy/Caddyfile

只有看到:

Valid configuration

才继续。

然后:

sudo systemctl reload caddy

这里是:

reload

不是:

restart

因此已有连接和现有代理的影响会尽可能小。

检查:

sudo systemctl status caddy

12. 验证原来的 Caddy 服务

假设你之前已有:

https://a.example.com

执行:

curl -I https://a.example.com

确认仍正常。

然后:

curl -I https://cloud.example.com

应该能得到类似:

HTTP/2 200

或者:

HTTP/2 302

查看证书:

curl -Iv https://cloud.example.com

不能有 TLS 错误。


13. 初始化 Nextcloud

浏览器打开:

https://cloud.example.com

第一次会进入 Nextcloud 初始化。

创建管理员,例如:

用户名:
justin

以及一个强密码。

数据库已经通过 Docker 配置好了:

数据库:MariaDB
数据库名:nextcloud
数据库用户:nextcloud
数据库服务器:db

正常情况下 Docker 镜像会自动读取这些配置,不需要手工连接 localhost。

等待初始化完成即可。


14. 检查 Nextcloud 状态

执行:

cd /opt/nextcloud

然后:

sudo docker compose exec -u www-data app php occ status

应该类似:

installed: true
maintenance: false
needsDbUpgrade: false

查看系统配置:

sudo docker compose exec -u www-data app php occ config:list system

查看后台任务模式:

sudo docker compose exec -u www-data app php occ background:cron

Nextcloud 官方推荐生产环境使用 Cron,而不是依赖用户访问网页触发的 AJAX 后台任务。

我们的:

nextcloud-cron

容器就是负责这个工作的。


15. 检查 Nextcloud 管理后台

访问:

头像
→ Administration settings
→ Overview

重点看看有没有:

Reverse proxy
HTTPS
WebDAV
Transactional file locking
Background jobs

相关警告。

HSTS 最低建议 15552000 秒,所以前面的 Caddy 配置:

header Strict-Transport-Security "max-age=15552000"

可以满足 Nextcloud 的安全检查要求。


16. 创建专门用于 Notability 的账号

我不建议直接让 Notability 使用 Nextcloud 管理员账号。

可以新建:

用户名:
notability

或者:

justin

给它设足够的存储配额,例如:

50 GB

然后登录这个普通用户。


17. 创建 Notability 文件夹

在 Nextcloud Files 中新建:

Notability

得到:

/
└── Notability/

以后 Notability 会把备份放进去。


18. 创建 Nextcloud App Password

这一步强烈推荐。

登录用于 Notability 的 Nextcloud 用户:

右上角头像
→ Personal settings
→ Security

找到:

Devices & sessions

创建 App Password。

名称可以填:

Notability iPad

它会生成一组密码。

例如:

abcde-fghij-klmno-pqrst-uvwxy

保存下来。

以后 Notability:

用户名 = Nextcloud 用户名
密码 = App Password

不要使用管理员密码。

Nextcloud 官方明确建议第三方 WebDAV 客户端使用 App Password;除了更安全,还能避免常规密码验证带来的额外开销。


19. 确定 WebDAV 地址

假设:

域名:
cloud.example.com

Nextcloud 用户:
justin

那么标准 WebDAV 地址是:

https://cloud.example.com/remote.php/dav/files/justin/

Nextcloud 官方目前规定第三方 WebDAV 文件客户端使用:

https://服务器/remote.php/dav/files/USERNAME/

因此不要填:

https://cloud.example.com

也不要只填:

https://cloud.example.com/remote.php/dav

建议使用完整地址:

https://cloud.example.com/remote.php/dav/files/justin/

20. 先测试 WebDAV

在服务器或 Mac 上测试:

curl \
    -u 'justin:你的AppPassword' \
    -X PROPFIND \
    -H 'Depth: 1' \
    'https://cloud.example.com/remote.php/dav/files/justin/'

如果正常,应该返回 XML,例如:

<d:multistatus>
...
</d:multistatus>

HTTP 状态通常:

207 Multi-Status

这是 WebDAV 的正常响应。

Nextcloud 官方也使用 PROPFIND 测试 WebDAV。


21. 测试创建目录

还可以实际测试:

curl \
    -u 'justin:你的AppPassword' \
    -X MKCOL \
    'https://cloud.example.com/remote.php/dav/files/justin/WebDAV-Test'

然后进入 Nextcloud 网页。

如果看到:

WebDAV-Test

说明:

Caddy
 ↓
Nextcloud
 ↓
WebDAV
 ↓
认证
 ↓
文件写入

整条链路都正常。

测试结束可以删除这个目录。


22. 在 Notability 中配置

根据 Notability 2026 年 3 月更新的官方文档,当前 iOS 版本仍支持:

Third-Party Backup
→ WebDAV servers

进入:

Notability
→ Library
→ Settings
→ Connected Services
→ Third-Party Backup

开启:

Third-Party Backup

选择:

WebDAV

填写:

Server / WebDAV URL:
https://cloud.example.com/remote.php/dav/files/justin/

Username:
justin

Password:
刚才生成的 App Password

然后连接。


23. 设置备份目录

连接成功后:

Third-Party Backup
→ Destination

选择:

Notability

即:

Nextcloud
└── Notability

Notability 官方默认也会使用一个名为 Notability 的目录。


24. 备份格式怎么选

你的用途是 考研笔记长期备份,我建议:

NTB / Note

而不是 PDF。

目前官方说明,Notability 原生格式适合完整备份和恢复,可以保留更多 Notability 专有数据;PDF 则主要用于跨平台查看。

可以这样理解:

格式 推荐用途
NTB / Note ⭐ 灾难恢复、重新导入 Notability
PDF 长期通用阅读
PDF + Recording 希望普通软件也能读取录音

如果只能选一个:

选 NTB / Note。

因为你的 Nextcloud 在这里首先承担的是:

Notability 灾备

而不是 PDF 文档服务器。


25. Notability 的备份机制

需要特别注意:

这不是同步,而是单向备份。

例如:

Notability
    ↓
Nextcloud

而不是:

Notability
 ↕
Nextcloud

Notability 官方说明,删除 Notability 中的笔记:

不会删除 Nextcloud 中已经存在的备份

同样,在 Nextcloud 删除备份:

也不会删除 Notability 中的原始笔记

这对于备份实际上是好事。


26. 第一次备份

开启 Third-Party Backup 后,Notability 会开始备份现有笔记。

以后通常是在:

编辑笔记
→ 返回 Library

之后重新备份该笔记。Notability 官方当前就是这样描述其触发机制的。

首次大量上传时,不建议:

关闭 Notability
锁屏很久
切换不稳定网络

让它先把第一次完整备份做完。


27. 在 Nextcloud 中确认

进入:

https://cloud.example.com

查看:

Files
└── Notability

应该逐渐出现:

高数.ntb
408操作系统.ntb
英语.ntb
...

如果用了 PDF:

高数.pdf
408操作系统.pdf
...

28. 推荐的最终架构

你的整个备份体系可以做成:

                    ┌─────────────┐
                    │   iCloud    │
                    │   同步      │
                    └──────▲──────┘
                           │
                           │ 双向同步
                           │
┌─────────────┐      ┌─────┴───────┐
│ iPhone/Mac  │◄────►│ Notability  │
└─────────────┘      │    iPad     │
                     └──────┬──────┘
                            │
                            │ 单向 WebDAV Backup
                            ▼
                    ┌───────────────┐
                    │     Caddy     │
                    │ HTTPS :443    │
                    └───────┬───────┘
                            │
                       localhost
                         :11080
                            │
                            ▼
                    ┌───────────────┐
                    │   Nextcloud   │
                    └───────┬───────┘
                            │
          ┌─────────────────┼─────────────────┐
          ▼                 ▼                 ▼
       MariaDB            Redis          Docker Volume

其中:

iCloud
= 日常跨设备同步

Nextcloud
= 独立灾备

这是比“只依赖 iCloud”更合理的结构。


29. 日常维护命令

以后查看状态:

cd /opt/nextcloud
sudo docker compose ps

日志:

sudo docker compose logs -f app

最近 100 行:

sudo docker compose logs --tail=100 app

查看 Cron:

sudo docker compose logs --tail=100 cron

升级 Nextcloud 35.x:

cd /opt/nextcloud

sudo docker compose pull

sudo docker compose up -d

因为使用:

image: nextcloud:35-apache

所以这里主要跟随:

35.0.1
→ 35.0.2
→ 35.0.3
...

而不会因为 latest 标签直接跳到未来 Nextcloud 36。


30. 备份 Nextcloud 本身

这里还有一个容易忽略的问题:

Notability → Nextcloud 是备份,但 Nextcloud 自己也需要备份。

至少要备份:

nextcloud_html
nextcloud_db

查看 volume:

sudo docker volume ls | grep nextcloud

大概会看到:

nextcloud_nextcloud_db
nextcloud_nextcloud_html

因此最终比较完整的备份链应该是:

Notability
     │
     ▼
Nextcloud
     │
     ▼
Nextcloud Docker Volume 定期离线备份

否则服务器硬盘坏掉:

Nextcloud + Notability 备份

仍然会一起丢失。


最关键的配置汇总

你最终真正需要记住的是:

公网入口:
https://cloud.example.com

Caddy:
cloud.example.com
        ↓
127.0.0.1:11080

Nextcloud Docker:
127.0.0.1:11080:80

WebDAV:
https://cloud.example.com/remote.php/dav/files/justin/

Notability:
WebDAV URL = 上面的地址
Username   = justin
Password   = Nextcloud App Password
Destination = Notability
Format     = NTB / Note

其中最重要的安全设计是 Nextcloud 的 11080 仅绑定 127.0.0.1,Caddy 仍然是服务器唯一的公网 HTTP/HTTPS 入口。这样部署不会与现有 Caddy 抢占 80/443,也不需要改动你其他反向代理服务。

Discussion / 讨论