静看光阴荏苒
不管不顾不问不说也不念

La Suite Drive:开源协作文件共享程序

La Suite Drive是法国政府主导的又一个开源网盘程序。特点如下:

  • 🔐 将您的文件安全地存储在集中位置
  • 🌐 通过我们的网页界面,随时随地访问您的文件
  • 🔍 强大的搜索功能,可快速查找文件和文件夹
  • 📂 文件结构清晰有序,导航和筛选功能直观易用
  • 🤝 与团队成员共享文件和文件夹
  • 👥 精细化的访问控制,确保您的信息安全,且只与授权人员共享
  • 🏢 创建工作区以组织团队协作和管理共享资源
  • 🚀 易于安装、可扩展且安全的文件存储解决方案

为什么把易于安装给划掉?因为这个项目我认为就目前而言是非常难以安装的,官方没有提供生产部署的文档,且部署步骤太多太杂了。。我认为这与官方的宣传不符,所以给划掉了= =

这里我为了尝鲜体验一番,记录一下用docker compose部署的方式。如果后续官方写了部署文档,请以官方的文档为准。这个项目目前应该还是Beta状态,如果官方后续对项目做了比较大的改动,不保证这篇文章的部署方法一直有效。

准备工作:

1.一台Debian服务器,内存不低于4GB,放行80、443、9199、9299、9980端口。

2.添加域名A记录解析,本文示例域名:drive.example.com、onlyoffice.example.com、collabora.example.com。

3.部署RustFS对象存储服务,或Garage S3对象存储服务。推荐RustFS,因为Drive的文档编辑功能需要S3支持“版本控制”的功能,Garage S3缺少这个功能将导致文档无法保存。本文S3示例域名:rustfs.example.com

4.部署VoidAuth OIDC身份验证服务。本文示例域名:voidauth.example.com

在VoidAuth创建OIDC APP:

设置Redirect URLs:

https://drive.example.com/api/v1.0/callback/

设置PostLogout URL:

https://drive.example.com/api/v1.0/logout-callback/

在RustFS控制台创建存储桶,并启用版本控制:

做好上面的准备工作后,现在可以正式部署Drive了,在服务器内安装Docker:

apt -y update
apt -y install curl
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

新建compose文件:

mkdir -p /opt/drive && cd /opt/drive && nano docker-compose.yml

写入如下内容,需要修改的地方写了注释:

x-common-env: &common-env
  BACKEND_HOST: backend
  FRONTEND_HOST: frontend
  # Django
  DJANGO_ALLOWED_HOSTS: "*"
  DJANGO_SECRET_KEY: 7cafccee9288097a2b3eb64305b0d07bff6682bc50a2b3f99a9696ef2e000fab # 使用openssl rand -hex 32生成
  DJANGO_SETTINGS_MODULE: drive.settings
  DJANGO_CONFIGURATION: Production
  # Logging
  LOGGING_LEVEL_HANDLERS_CONSOLE: ERROR
  LOGGING_LEVEL_LOGGERS_ROOT: INFO
  LOGGING_LEVEL_LOGGERS_APP: INFO
  # Python
  PYTHONPATH: /app
  # Mail
  DJANGO_EMAIL_HOST: mail.example.com
  DJANGO_EMAIL_HOST_USER: smtp
  DJANGO_EMAIL_HOST_PASSWORD: smtppassword
  DJANGO_EMAIL_PORT: 587
  DJANGO_EMAIL_FROM: smtp@example.com
  DJANGO_EMAIL_USE_TLS: true
  DJANGO_EMAIL_BRAND_NAME: "La Suite Numérique"
  DJANGO_EMAIL_LOGO_IMG: "https://drive.example.com/assets/logo-suite-numerique.png"
  # Media S3
  STORAGES_STATICFILES_BACKEND: django.contrib.staticfiles.storage.StaticFilesStorage
  AWS_S3_ACCESS_KEY_ID: imlala
  AWS_S3_SECRET_ACCESS_KEY: s3secretaccesskey
  AWS_S3_REGION_NAME: auto
  AWS_STORAGE_BUCKET_NAME: drive-media-storage
  AWS_S3_SIGNATURE_VERSION: s3v4
  AWS_S3_ENDPOINT_URL: https://rustfs.example.com
  MEDIA_BASE_URL: https://drive.example.com
  # OIDC
  OIDC_OP_JWKS_ENDPOINT: https://voidauth.example.com/oidc/jwks
  OIDC_OP_AUTHORIZATION_ENDPOINT: https://voidauth.example.com/oidc/auth
  OIDC_OP_TOKEN_ENDPOINT: https://voidauth.example.com/oidc/token
  OIDC_OP_USER_ENDPOINT: https://voidauth.example.com/oidc/me
  OIDC_OP_LOGOUT_ENDPOINT: https://voidauth.example.com/oidc/session/end
  OIDC_RP_CLIENT_ID: pcl1xbprEdcbi0xQ
  OIDC_RP_CLIENT_SECRET: youroidcsecret
  OIDC_RP_SIGN_ALGO: RS256
  OIDC_RP_SCOPES: "openid email"
  LOGIN_REDIRECT_URL: https://drive.example.com
  LOGIN_REDIRECT_URL_FAILURE: https://drive.example.com
  LOGOUT_REDIRECT_URL: https://drive.example.com
  OIDC_REDIRECT_ALLOWED_HOSTS: '["https://drive.example.com"]'
  # WOPI
  WOPI_CLIENTS: "collabora,onlyoffice"
  WOPI_COLLABORA_DISCOVERY_URL: https://collabora.example.com/hosting/discovery
  WOPI_ONLYOFFICE_DISCOVERY_URL: https://onlyoffice.example.com/hosting/discovery
  WOPI_SRC_BASE_URL: https://drive.example.com

x-postgres-env: &postgres-env
  # Postgresql db container configuration
  POSTGRES_DB: drive
  POSTGRES_USER: drive
  POSTGRES_PASSWORD: 023917148a35e7c9a62964caabe0334c # 设置数据库密码
  # App database configuration
  DB_HOST: postgresql
  DB_NAME: drive
  DB_USER: drive
  DB_PASSWORD: 023917148a35e7c9a62964caabe0334c # 设置数据库密码
  DB_PORT: 5432

services:
  postgresql:
    image: postgres:16
    restart: unless-stopped
    environment:
      <<: *postgres-env
    volumes:
    - ./data/databases/backend:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
      interval: 1s
      timeout: 2s
      retries: 300

  redis:
    image: redis:5
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 30s
      timeout: 5s
      retries: 5
      start_period: 10s

  backend:
    image: lasuite/drive-backend:main
    restart: unless-stopped
    user: "${DOCKER_USER:-1000}"
    depends_on:
      postgresql:
        condition: service_healthy
        restart: true
      redis:
        condition: service_healthy
    environment:
      <<: [*common-env, *postgres-env]

  frontend:
    image: lasuite/drive-frontend:main
    user: "${DOCKER_USER:-1000}"
    restart: unless-stopped
    depends_on:
      - backend
    environment:
      <<: [*common-env]
    ports:
      - 127.0.0.1:9199:8083
    volumes:
      - ./default.conf.template:/etc/nginx/templates/docs.conf.template
    entrypoint:
      - /docker-entrypoint.sh
    command: ["nginx", "-g", "daemon off;"]
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080"]
      interval: 15s
      timeout: 30s
      retries: 20
      start_period: 10s

  celery:
    image: lasuite/drive-backend:main
    user: ${DOCKER_USER:-1000}
    restart: unless-stopped
    environment:
      <<: [*common-env, *postgres-env]
    command: [ "celery", "-A", "drive.celery_app", "worker", "-l", "INFO" ]

  onlyoffice-docs:
    image: onlyoffice/documentserver:latest
    container_name: onlyoffice-docs
    restart: unless-stopped
    environment:
      - WOPI_ENABLED=true
      - JWT_ENABLED=true
      - JWT_SECRET=be1b32d03c4397d2cabffa3acef7450b  # 设置JWT密钥
    ports:
      - "127.0.0.1:9299:80"
    volumes:
      - ./onlyoffice/logs:/var/log/onlyoffice
      - ./onlyoffice/data:/var/www/onlyoffice/Data
      - ./onlyoffice/lib:/var/lib/onlyoffice
      - ./onlyoffice/db:/var/lib/postgresql

  collabora:
    image: collabora/code:latest
    container_name: collabora-code
    restart: unless-stopped
    ports:
      - "127.0.0.1:9980:9980"
    environment:
      - server_name=collabora.example.com
      - username=admin
      - password=97bfec0e41e788611c636024fa5bd4bb # 设置collabora管理员密码
      - extra_params=--o:ssl.enable=false --o:ssl.termination=true

注意事项:

如果你只想使用一个办公套件,例如onlyoffice,那么请修改如下变量:

WOPI_CLIENTS: "onlyoffice"
#WOPI_COLLABORA_DISCOVERY_URL: https://collabora.example.com/hosting/discovery #注释掉这个变量

Drive的WOPI在默认情况下会使用onlyoffice,如果你不需要collabora code可以不部署,并且onlyoffice的使用体验比collabora code好的多。

新建前端容器需要用到的NGINX配置文件:

nano default.conf.template

写入如下内容:

upstream docs_backend {
    server ${BACKEND_HOST}:8000 fail_timeout=0;
}

upstream docs_frontend {
    server ${FRONTEND_HOST}:3000 fail_timeout=0;
}

server {
    listen 8083;
    server_name localhost;
    charset utf-8;
    # increase max upload size
    client_max_body_size 5120m;
    server_tokens off;
    proxy_ssl_server_name on;

    location @proxy_to_docs_backend {
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_redirect off;
        proxy_pass http://docs_backend;
    }

    location @proxy_to_docs_frontend {
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_redirect off;
        proxy_pass http://docs_frontend;
    }

    location / {
        try_files $uri @proxy_to_docs_frontend;
    }

    location /api {
        try_files $uri @proxy_to_docs_backend;
    }

    location /admin {
        try_files $uri @proxy_to_docs_backend;
    }

    location /media/ {
        # Auth request configuration
        auth_request /media-auth;
        auth_request_set $authHeader $upstream_http_authorization;
        auth_request_set $authDate $upstream_http_x_amz_date;
        auth_request_set $authContentSha256 $upstream_http_x_amz_content_sha256;
        # Pass specific headers from the auth response
        proxy_set_header Authorization $authHeader;
        proxy_set_header X-Amz-Date $authDate;
        proxy_set_header X-Amz-Content-SHA256 $authContentSha256;
        proxy_pass https://rustfs.example.com/drive-media-storage/;
        proxy_set_header Host rustfs.example.com;
        proxy_ssl_name rustfs.example.com;
    }

    # Proxy auth for media-preview
    location /media/preview/ {
        # Auth request configuration
        auth_request /media-auth;
        auth_request_set $authHeader $upstream_http_authorization;
        auth_request_set $authDate $upstream_http_x_amz_date;
        auth_request_set $authContentSha256 $upstream_http_x_amz_content_sha256;
        # Pass specific headers from the auth response
        proxy_set_header Authorization $authHeader;
        proxy_set_header X-Amz-Date $authDate;
        proxy_set_header X-Amz-Content-SHA256 $authContentSha256;
        proxy_pass https://rustfs.example.com/drive-media-storage/;
        proxy_set_header Host rustfs.example.com;
        proxy_ssl_name rustfs.example.com;
    }

    location /media-auth {
        proxy_pass http://docs_backend/api/v1.0/items/media-auth/;
        proxy_set_header X-Forwarded-Proto https;
        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-Original-URL $request_uri;
        # Prevent the body from being passed
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Original-Method $request_method;
    }
}

注意将location /media/location /media/preview/内的域名改为自己的S3域名:

proxy_pass https://rustfs.example.com/drive-media-storage/;
proxy_set_header Host rustfs.example.com;
proxy_ssl_name rustfs.example.com;

启动全部容器:

docker compose up -d

运行数据库迁移、创建Django管理员账号:

docker compose run --rm backend python manage.py migrate
docker compose run --rm backend python manage.py createsuperuser --email imlala@lala.im --password youradminpassword

运行如下命令启用WOPI客户端:

docker compose run --rm backend python manage.py trigger_wopi_configuration

这应该是一个BUG,按道理来说celery会自动执行,但是不知道为什么没生效。如果不执行这个命令将无法使用文档编辑功能。

配置Ferron反向代理:

nano /etc/ferron.kdl

写入如下内容:

drive.example.com {
   proxy "http://127.0.0.1:9199/"
   proxy_request_header_replace "Host" "{header:Host}"
}

onlyoffice.example.com {
   proxy "http://127.0.0.1:9299/"
   proxy_request_header_replace "Host" "{header:Host}"
}

collabora.example.com {
   proxy "http://127.0.0.1:9980/"
   proxy_request_header_replace "Host" "{header:Host}"
   disable_url_sanitizer #true
}

重载Ferron:

systemctl reload ferron

如遇到Ferron反向代理导致上传速度慢,可以参考这篇文章解决。

所有服务将在以下URL提供访问:

https://drive.example.com
https://onlyoffice.example.com/admin
https://collabora.example.com/browser/dist/admin/admin.html

效果:

总结一下部署过程中遇到的问题。

1.由于官方的环境变量配置文件不完整,导致部署非常困难,甚至有些变量还要翻源码才能知道是什么作用= =

2.前端容器必须配置入口点启动脚本,否则无法使用挂载的自定义NGINX配置文件。

3.官方提供的NGINX配置文件缺少对/media/preview/的路由,导致上传的文件无法预览。

4.Ferron反向代理collabora code遇到WebSocket连接失败。原因是Ferron默认会过滤URL防止路径遍历等安全漏洞,collabora code的WebSocket连接URL里面包含https://被Ferron过滤成https:/了,导致后端报错Bad URL。解决办法是关闭Ferron的URL过滤:disable_url_sanitizer #true

5.S3实现不支持版本控制,导致文档无法保存,这个之前已经提过了。

6.S3跨域问题,因为Drive是直接操作S3,没有经过后端,所以S3这边要设置跨域规则。

7.目前需要手动执行python manage.py trigger_wopi_configuration来集成onlyoffice等办公套件,这是一个BUG:见此issue

总之就是这个项目完成度还是非常高的,基本功能都有了,要我说就是还差个文件缩略图和密码分享的功能。但是有一说一部署确实太多坑了,建议再观望一下= =

赞(0)
未经允许不得转载:荒岛 » La Suite Drive:开源协作文件共享程序
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

分享创造快乐

广告合作资源投稿