之前自己组装了一台 NAS,用作私有云,解决大容量网盘,自己跑的一些小应用的问题,还计划作为软路由。 当时对网盘的选择是 NextCloud,最主要的原因就是这是有名气的 Self Hosted 网盘里,最开源的选项, 而这周末,我还是决定更换到 Seafile。

NextCloud 与 Seafile 简单体会

换到 Seafile 之后,简单用了一下,有一下几点体会:

  1. iOS 相册内有 10000+ 张照片,同步到网盘上
    • Seafile 每次尝试同步是,会认为全部已经同步完成,然后逐步检测到未同步照片后同步
    • NextCloud 每次打开,都会有大量的同步任务,然后这一万张就一直同步不完
  2. iOS 端用户体验
    • Seafile 感觉是原生 iOS App
    • NextCloud 感觉是网页版套壳
  3. iOS 端上传 6G+ 大文件
    • Seafile 迟迟不开始,估计是在分块
    • NextCloud 一直在尝试上传,但是一直失败,最后任务找不到了
  4. 历史版本
    • 这个是意外收获,以前都不知道 NextCloud 有历史版本,用了 Seafile 之后,发现两家都有
  5. 文件管理
    • Seafile 中有一个 资料库 的概念,目前还没体会到用处
    • NextCloud 直接就是一个网盘,用起来比较简单
  6. 元文件
    • Seafile 把文件分块后存储,但是提供 fuse 和 WebDAV 用于查看文件
    • NextCloud 直接存储文件,可以直接在 data 目录看到元文件和目录结构
  7. 部署
    • Seafile 总共 3 个容器,用 Docker-compose 一起拉起来
    • NextCloud 两个容器,一个 NextCloud,一个 Postgres 单独部署

最主要影响我的是第一点,同步照片,NextCloud 我尝试过一个晚上没关屏幕,NextCloud 在前台运行, 但是一晚上过去了,没传上去太多,Seafile 反而可以一次次检查,慢慢把所有照片同步上去。

另外 NextCloud 还出现一些登录失败等小问题,目前主观感觉 Seafile 会更稳定一些, 感觉 C+Python 的 Seafile 在性能上,还是比 php 的 NextCloud 性能要高一些。

最后,元文件这个问题,我主要是想把文件都放到 OneDrive 上作为云上备份,Seafile 通过 Fuse, 或者导出备份文件的方式,倒也能解决。

另外,看到一个 Issue 也蛮有意思的,主题大致是有人提出 OwnCloud 开始开发 Golang 版本的 Server 端, 用于替换以前的 php 技术栈,但是看 NextCloud 维护者们还是比较倾向与保护好当前 php 生态, 觉得目前性能上还是足够大部分人使用的。

作为 Golang 开发者,这当然不是我希望看到的

所以,后续会迁移到 Seafile,也会关注 OwnCloud 的 NG

Seafile 安装

作为一名容器开发,我当然是选择通过 Docker 安装

Docker-compose

Arch Linux 直接

sudo pacman -S docker-compose

当然,Golang 的优秀体质,也可以直接在 Docker compose Release 页面直接下载二进制, 放到 PATH 下就好了。

再下载对应 docker-compose.yaml 文件,就可以启动多个容器了。

启动 Seafile

通过 Docker 安装教程里,能看到给出的 Docker compose 配置文件, 简单说明一下,这个 docker-compose.yaml 配置了 3 个容器,分别是:

  • mariadb: 开源版 MySQL
  • Memcached: 加速缓存
  • Seafile: 本体

我稍微修改了一下:

version: '2.0'
services:
  db:
    image: mariadb:10.1
    container_name: seafile-mysql
    restart: always
    environment:
    - MYSQL_ROOT_PASSWORD=Password  # Requested, set the root's password of MySQL service.
    - MYSQL_LOG_CONSOLE=true
    ports:
    - "13306:3306"
    volumes:
    - /host/dir/mysql:/var/lib/mysql  # Requested, specifies the path to MySQL data persistent store.
    networks:
    - seafile-net

  memcached:
    image: memcached:1.5.6
    restart: always
    container_name: seafile-memcached
    entrypoint: memcached -m 256
    networks:
    - seafile-net

  seafile:
    image: seafileltd/seafile-mc:latest
    container_name: seafile
    restart: always
    ports:
    - "10050:80"
    - "10058:8080"
#      - "10053:443"  # If https is enabled, cancel the comment.
    volumes:
    - /host/dir/seafile/:/shared   # Requested, specifies the path to Seafile data persistent store.
#      - /cabin/umbrella/seafile/seafdav.conf:/opt/seafile/conf/seafdav.conf
    environment:
    - DB_HOST=db
    - DB_ROOT_PASSWD=Password  # Requested, the value shuold be root's password of MySQL service.
    - TIME_ZONE=Etc/GMT+8  # Optional, default is UTC. Should be uncomment and set to your local time zone.
    - [email protected] # Specifies Seafile admin user, default is '[email protected]'.
    - SEAFILE_ADMIN_PASSWORD=adminPassword     # Specifies Seafile admin password, default is 'asecret'.
    - SEAFILE_SERVER_LETSENCRYPT=false   # Whether to use https or not.
    - SEAFILE_SERVER_HOSTNAME=hostname.com # Specifies your host name if https is enabled.
    depends_on:
    - db
    - memcached
    networks:
    - seafile-net

networks:
  seafile-net:

主要修改的地方是:

  • 三个容器,都加了 restart: always: 用于每次开机,容器自启动
  • 数据库容器,加了 ports: - "13306:3306": 用于我在宿主机上访问数据库,备份数据库
  • seafile 容器, ports 增加 "10058:8080" 用于暴露 webdav 端口

另外,我没有暴露 443 端口,但是作为全民 https 时代,我当然也不能拖后腿,后面会说到。

修改完配置文件之后,就可以使用命令启动 Seafile 服务端:

docker-compose up -d

-d 作为可选项,意思是后台运行,一般配置文件写的有问题的时候, 不带 -d ,前台运行能看到日志,排查错误,还是很方便的, 我们配置文件没问题,当然是直接后台启动。

WebDAV

WebDAV 简单的说,就是把文件读写都转成 HTTP 请求,然后当成一个磁盘挂载到机器上。

端口

如上文提到,在 seafile 容器里,我多暴露了一个端口 8080 ,主要用户 WebDAV , 因为 Seafile 在存储文件时,会把文件分割,再将元信息存储到数据库中,主要为了:

  • 加密
  • 增量同步
  • 历史版本

但是带来另一个不便,就是哪怕在机器上,也没法访问备份的文件, 所以在宿主机上就需要通过 WebDAV 或者 fuse 挂载之后访问, fuse 的话,目前是只读的,所以就用 WebDAV 了。

启用 WebDAV

Seafile 默认不启用 WebDAV ,我们需要修改配置文件:

volumes:
- /host/dir/seafile/:/shared   # Requested, specifies the path to Seafile data persistent store.

这是 docker-compose.yaml 中,seafile 容器的 volumes 配置,就是把 seafile 配置文件和数据存储挂到机器上的。 在 /host/dir/seafile 这个文件夹下面, seafile/conf/seafdav.conf 这个配置文件就是 WebDAV 的配置文件, 改成:

[WEBDAV]
enabled = true
port = 8080
fastcgi = false
share_name = /seafdav

主要是:

  • enabled: 开关
  • port: 端口
  • fastcgi: 使用进程/线程池来处理多个请求的协议,看起来我没用应该是不应该的
  • share_name: http 的 uri,就是端口号后面的路径。

修改配置文件之后,重启一下容器,就可以了:

docker-compose restart seafile

HTTPS

全民 HTTPS 时代,当时不能落后,考虑到我机器上有一个 Nginx 做网关, 所以我决定在 Nginx 做 HTTPS 卸载,再把服务以 HTTP 挂到 Nginx 后面,就是这样:

申请泛域名证书

Let's Encrypt 支持泛域名证书,可真是太方便了,如果域名托管在有插件支持的托管商,就更方便了, 就像我现在放在 Cloudflare,几个命令就能申请下来。

官方教程这里选择用的软件,如 Nginx ,和系统,如 ArchLinux ,就能看到详细教程, 当然,下面还要选一下 wildcard ,就是通配符证书。

  1. 检查 DNS 托管商是否支持,cloudflare, cloudxns, linode, google 都是支持的,不支持的就得另找,或者手配了。

  2. 安装 certbot: sudo pacman -S certbot certbot-nginx

  3. 安装 DNS 修改插件: sudo pacman -S certbot-dns-cloudflare ,其他家的,把插件名的 cloudflare 换了就可以。

  4. 配置 key, 这个可以在插件的说明上看到方法,如 certbot-dns-cloudflare,注意,由于 Cloudflare API 不够灵活,必须要所有 Zone 的 Zone:Zone:ReadZone:DNS:Edit 权限才行。

    1. API Token 页面,点 新建 Token
    2. 输入名字
    3. 选择权限 Zone:Zone:ReadZone:DNS:Edit
    4. 选择所有 Zone
    5. 下一步,确定,就可以了
  5. 把 Token 按下面格式放到文件里

    # Cloudflare API token used by Certbot
    dns_cloudflare_api_token = 0123456789abcdef0123456789abcdef01234567
    
  6. 修改一下 token 文件的权限: chmod 600 token

  7. 申请证书,注意 *.example.com* 就是泛域名

    certbot certonly \
      --dns-cloudflare \
      --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \
      -d *.example.com
    

配置 Nginx

上文中,已经申请到了泛域名证书,我们配置到 Nginx 上:

# seafile
upstream seafile {
    server  127.0.0.1:10080;
}

server {
    listen       10088 ssl;
    #       listen       [::]:443 ssl http2 default_server;
    server_name  seafile.example.com;

    ssl_certificate "/etc/letsencrypt/live/example.com-0001/fullchain.pem";
    ssl_certificate_key "/etc/letsencrypt/live/example.com-0001/privkey.pem";
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout  10m;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    client_max_body_size 10000m;

    location / {
        proxy_pass http://seafile;
        add_header Real-Server $upstream_addr;
        proxy_set_header Host            $host;
        proxy_set_header X-Forwarded-For $remote_addr;
    }
}

配置中,有几个地方是需要注意一下:

  • listen 10088 ssl; 中的 ssl 参数标志这是个 HTTPS 端口。
  • ssl_certificatessl_certificate_key : letsencrypt 生成的证书对
  • client_max_body_size 客户端请求 body 大小,这个参数限制了上传文件的大小,直接配置成 10G 了。

配置域名解析

目前我只在局域网里用,所以我直接把域名解析成内网地址了,简单直接, 如果家里有公网地址,seafile 需要公网访问,可以配置成 DDNS,动态配置域名地址。