VPS + Nginx + Docker + Nextcloud

这篇记录一下我在一台 VPS 上用 宿主机 Nginx + Docker Compose 部署 Nextcloud(FPM) 的过程,以及中间踩到的几个典型坑。

0. 选择 Nextcloud 的原因

  • 自托管:数据和账号完全自己掌控,比第三方网盘更安心。
  • 生态完整:Web / Desktop / Mobile 都有客户端,WebDAV 也可用,适合 Obsidian 等同步场景。
  • 可扩展:后续可以加 Redis、对象存储(S3)、外部存储、OnlyOffice(资源够的话)等。

1. Docker Compose 配置

Nginx 跑在宿主机(因为可能还要代理别的服务),Docker 里只跑 Nextcloud 的核心组件:

  • nextcloud:fpm
  • mariadb
  • redis
  • cron

同时为了安全:

  • FPM 只监听 127.0.0.1:9000(外网不可直接访问)
  • DB/Redis 不暴露端口

首先建立nextcloud目录和权限

mkdir -p /opt/nextcloud/{html,data,db,redis}
chown -R www-data:www-data /opt/nextcloud

docker-compose.yml:

services:
  db:
    image: mariadb:11
    restart: unless-stopped
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
    environment:
      - MYSQL_ROOT_PASSWORD=...
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=...
    volumes:
      - /opt/nextcloud/db:/var/lib/mysql

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    command: ["redis-server", "--save", "", "--appendonly", "no", "--maxmemory", "128mb", "--maxmemory-policy", "allkeys-lru"]

  app:
    image: nextcloud:fpm
    restart: unless-stopped
    depends_on:
      - db
      - redis
    ports:
      - "127.0.0.1:9000:9000"
    environment:
      - MYSQL_HOST=db
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=...
      - REDIS_HOST=redis
      - NEXTCLOUD_ADMIN_USER=admin
      - NEXTCLOUD_ADMIN_PASSWORD=...
      - NEXTCLOUD_TRUSTED_DOMAINS=cloud.example.com
      - PHP_MEMORY_LIMIT=512M
      - PHP_UPLOAD_LIMIT=2G
    volumes:
      - /opt/nextcloud/html:/var/www/html
      - /opt/nextcloud/data:/var/www/html/data

  cron:
    image: nextcloud:fpm
    restart: unless-stopped
    depends_on:
      - app
    volumes:
      - /opt/nextcloud/html:/var/www/html
      - /opt/nextcloud/data:/var/www/html/data
    entrypoint: /cron.sh

为什么用 FPM:因为我想用宿主机 Nginx 统一反代/证书/路由,而不是让容器里再跑一层 Apache/Nginx。

部署:

docker compose up -d
docker compose psbash
docker compose logs --tail=120 app

可以检查(一般需要等一会因为这个versioncheck文件要等nextcloud脚本构建完才会显示(不是容器))

ls -la /opt/nextcloud/html/lib/versioncheck.php

2. Nginx 配置

实际上可以直接参考官方给的nginx: https://docs.nextcloud.com/server/stable/admin_manual/installation/nginx.html

  • 静态资源(CSS/JS/图片等)优先走 Nginx 直接读磁盘:更快
  • 找不到静态资源时 回退到 Nextcloud(index.php):因为 Nextcloud 有些资源是动态生成的(例如 theming 的 CSS)
  • 仅允许 Nextcloud 的“入口 PHP 文件”走 FPM(index.php/remote.php/...),其它 .php 一律 404
  • remote.php 必须可用:否则 WebDAV(/remote.php/dav/...)会 404,文件列表会出各种“空/未找到文件夹”的表现

一个可用的SSL站点配置:

server {
  listen 80;
  server_name cloud.example.com;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl http2;
  server_name cloud.example.com;

  ssl_certificate     /etc/nginx/ssl/cloud.example.com.pem;
  ssl_certificate_key /etc/nginx/ssl/cloud.example.com.key;

  root /opt/nextcloud/html;
  index index.php;

  client_max_body_size 2G;

  location = /.well-known/carddav { return 301 /remote.php/dav; }
  location = /.well-known/caldav  { return 301 /remote.php/dav; }

  # 禁止访问敏感目录/文件(避免直接读到代码/配置)
  location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { deny all; }
  location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { deny all; }

  # 仅允许 Nextcloud “入口 PHP” 走 FPM(remote.php 对 DAV 很关键)
  location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    include fastcgi_params;

    # 关键点:FPM 在容器里,SCRIPT_FILENAME 必须是容器内路径
    fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;

    fastcgi_param HTTPS on;
    fastcgi_read_timeout 300;
    fastcgi_pass 127.0.0.1:9000;
  }

  # 静态资源:存在就直接返回;不存在则交给 Nextcloud(用于 theming CSS / 动态资源)
  location ~* \.(?:css|js|mjs|wasm|svg|gif|png|jpg|jpeg|ico|webp|woff2?|ttf|otf|eot|map|webm|mp4)$ {
    try_files $uri /index.php$request_uri;
    expires 6M;
    access_log off;
  }

  # 页面路由:不要用 $uri/,否则会把 /apps/dashboard/ 当目录,触发 403
  location / {
    try_files $uri /index.php$request_uri;
  }

  # 其它 php 禁止(安全)
  location ~ \.php(?:$|/) { return 404; }
}

3. 常见Bug

Bug A:CSS/JS 404 或页面只剩一个“Nextcloud”标题

  • 现象:HTML 能出来,但大量 /core/css/.../core/js/... 失败
  • 根因:宿主机 Nginx 负责静态资源,如果 root 不对、或宿主机没有完整的 Nextcloud 代码目录,就会 404
  • 解决:确认 /opt/nextcloud/html 有完整源码,并且 Nginx root 指向它

Bug B:/index.php/index.php/... 内部重定向循环(500)

  • 现象:Nginx 日志出现 rewrite or internal redirection cycle ... /index.php/index.php/...
  • 根因:配置里把已经带 /index.php/... 的请求再次拼接进 /index.php$request_uri
  • 解决:让入口 PHP(location ~ ^/(index|remote|...)\.php)优先匹配,且 try_files/fallback 写法不要重复拼接导致循环

Bug C:WebDAV 404,Files 页面“空/未找到文件夹”

  • 现象:/remote.php/dav/... 404(浏览器 Network 里能看到 REPORT/PROPFIND)
  • 根因:Nginx 没把 remote.php 这个入口交给 FPM,直接当静态/目录处理了
  • 解决:入口 PHP 的正则里必须包含 remote.php,并正确设置 PATH_INFO

Bug D:ESM 模块加载失败:.mjs 返回 application/octet-stream

  • 现象:Failed to load module script ... MIME type application/octet-stream
  • 根因:老版本 Nginx 的 /etc/nginx/mime.types 可能没有 mjs 映射,导致 .mjs 默认变成 octet-stream
  • 解决:在 /etc/nginx/mime.types 里把 application/javascript 扩展补上 mjs(并 reload nginx)


📢 转载须知



本文作者:Tianci Hou


本文标题:《VPS + Nginx + Docker + Nextcloud》


本文链接:https://blog.tiancihou.me/vps-nginx-docker-nextcloud/




CC BY-NC-SA


版权声明:本文采用 CC BY-NC-SA 4.0 许可协议。转载请务必保留以上署名及原始链接。



暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇