现在的网盘越来越辣鸡,倒不是说体验不好,天朝带宽这么贵的情况下,30 一个月也还算划算暗示,但天天扫描网盘上的文件就不能忍了😕,毕竟不是每个人都愿意用隐私换取便利再次暗示,因此剁手购入大盘独服,自己搭建一个网盘使用。在平台的选择过程中最后纠结于 Nextcloud 和 Seafile,都搭建体验之后最终选择了 Seafile,比较 PHP 的文件管理性能略显拉跨。

Seafile 是一款开源的企业云盘,注重可靠性和性能。支持 Windows, Mac, Linux, iOS, Android 多平台文件同步或者直接挂载到本地访问。专业版也免费支持最多三个用户,足以满足要求,顺便试一下用 Docker 部署,第一次使用 Docker 也遇到了一些坑,也作为记录。

安装 Docker

可以查看官方文档说明,推荐直接使用仓库安装。

添加 Docker 的仓库:

yum install -y yum-utils
yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

安装最新的版本 Docker:

yum install docker-ce docker-ce-cli containerd.io

运行 Docker,并用 helloworld 测试是否正确:

systemctl start docker
docker run hello-world

输入命令后将会自动运行测试镜像并打印退出

为了方便部署项目,再安装 docker-compose:

yum install docker-compose -y

部署 Seafile 专业版

从 Seafile 官网下载 docker-complse.yml 修改后上传到服务器上。

特别注意的是要修改以下几项配置:

  • MySQL root 用户的密码
  • 持久化存储 MySQL 数据的 volumes 目录
  • 持久化存储 Seafile 数据的 volumes 目录
  • 持久化存储 Elasticsearch 索引数据的 volumes 目录

接着在 docker-compose.yml 目录下使用以下命名启动 Seafile:

docker-compose up -d

按照官方文档的说法是现在就可以的输入地址访问了,可是却发现一直 502,最后使用 docker logs --since 30m [CONTAINER_ID] 查看日志,发现数据库一直连不上,连接一直被拒绝,研究了半天,这是因为在 CentOS7 上部署 Docker,网络模式采用的是 bridge 模式,启动 Docker 时,会创建一个名为 docker0 的虚拟网桥,用于宿主机与容器之间的通信。

如果 Docker 容器访问宿主机,那么 docker0 网桥将报文直接转发到本机,报文的源地址是 docker0 网段的地址。而如果 docker 容器访问宿主机以外的机器,docker 的 SNAT 网桥会将报文的源地址转换为宿主机的地址,通过宿主机的网卡向外发送。因此,当 Docker 容器访问宿主机时,如果宿主机服务端口会被防火墙拦截,那么就无法连通宿主机。

为了解决这个问题,首先使用 ifconfig 查看网络地址,编辑 /etc/firewalld/zones/public.xml 文件,添加 docker0 和使用 docker-compose 命令生成的地址段:

<rule family="ipv4">
  <source address="172.18.0.0/16"/>
  <accept/>
</rule>

之后使用 docker ps 查看安装的镜像,卸载 seafile 镜像重新运行 docker-comple up -d

docker stop [seafile ID]
docker rm [seafile ID]
docker rmi [seafile ID]
docker-comple up -d

等待安装完成之后就可以正常访问了

使用 https 访问

Seafile 自带了开启 https 的选项,用的是 Let’s encryption,这里选择使用自己的证书通过外部 Nginx 反代

server {
    listen 80;
    server_name domain.com;
    rewrite ^(.*)$  https://$host$1 permanent; 
}

server {
    listen 443 ssl http2;
    server_name domain.com;
    ssl_certificate /[path]/full_chain.pem; 
    ssl_certificate_key /[path]/private.key;
    #TLS 版本控制
    ssl_protocols   TLSv1.3;
    ssl_ciphers     TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256;
    ssl_prefer_server_ciphers   on;
    # 开启 1.3 0-RTT
    ssl_early_data  on;
    ssl_stapling on;
    ssl_stapling_verify on;

    location / {
        proxy_pass https://127.0.0.1:[port];  # 设置为docker seafile映射出来的https端口
        proxy_set_header  Host $host:$server_port;
        proxy_set_header  X-Real-IP  $remote_addr;
        client_max_body_size  10m;
    }
}

接下来修改 Docker 中 Nginx 的配置,如果持久化存储 Seafile 数据的目录为 /opt/seafile-data

创建 /opt/seafile-data/ssl 目录,然后拷贝证书文件和密钥文件到 ssl 目录下

接着修改配置文件 /opt/seafile-data/nginx/conf/seafile.nginx.conf 注意不要更改该配置文件的文件名:

server {
    listen 80;
    server_name domain;
    rewrite ^ https://$host$request_uri? permanent;
    server_tokens off;
}

server {
    listen 443 ssl http2;
    server_name domain;
    ssl on;
    ssl_session_timeout 5m;
    ssl_session_cache shared:SSL:5m;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_certificate      /shared/ssl/full_chain.pem;
    ssl_certificate_key  /shared/ssl/private.key;
    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-CAMELLIA256-SHA:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-SEED-SHA:DHE-RSA-CAMELLIA128-SHA:HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS';
    ssl_prefer_server_ciphers on;

    proxy_set_header X-Forwarded-For $remote_addr;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
    server_tokens off;

    location / {
        proxy_pass http://127.0.0.1:8000/;
        proxy_read_timeout 310s;
        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-Forwarded-Host $server_name;
        proxy_set_header   X-Forwarded-Proto $scheme;

        client_max_body_size 0;
        access_log      /var/log/nginx/seahub.access.log seafileformat;
        error_log       /var/log/nginx/seahub.error.log;
    }

    location /seafhttp {
        rewrite ^/seafhttp(.*)$ $1 break;
        proxy_pass http://127.0.0.1:8082;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        client_max_body_size 0;
        proxy_connect_timeout  36000s;
        proxy_read_timeout  36000s;
        proxy_request_buffering off;
        access_log      /var/log/nginx/seafhttp.access.log seafileformat;
        error_log       /var/log/nginx/seafhttp.error.log;
    }

    location /seafdav {
        proxy_pass         http://127.0.0.1:8080;
        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-Forwarded-Host $server_name;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_read_timeout  1200s;
        client_max_body_size 0;

        access_log      /var/log/nginx/seafdav.access.log seafileformat;
        error_log       /var/log/nginx/seafdav.error.log;
    }

    location /media {
        root /opt/seafile/seafile-server-latest/seahub;
    }

    # For letsencrypt
    location /.well-known/acme-challenge/ {
        alias /var/www/challenges/;
        try_files $uri =404;
    }
}

重启两处 Nginx:

systemctl restart nginx.service
docker exec -it seafile /usr/sbin/nginx -s reload

之后就可以通过 https 访问了,然后发现上传不了文件,又研究了半天,需要修改 系统管理 -> 设置 页面中的两个 url 设置的地址才行。

然后又发现登陆后就提示不安全,证书正常加载,Chrome 中查看发现引用了错误的 http 地址导致,试了很多方法都不行,最后试了下使用 rm -rf /tmp/seahub_cache 删除 seahub 的缓存文件才解决,然后又发现头像一直无法加载,发现头像的地址为 https://domian:8080,又回头看设置中的 home-url 后面多了 8080。。去掉之后重启 docker-compose restart 后终于正常了QAQ

最后值得一提的是在 Seafile 中,当文件被删除时,组成这些文件的块数据不会立即删除,因为可能有其他文件也会引用这些块数据(用于去重功能的实现)。为了真正删除无用的块数据,还需要额外运行 “GC” 程序。GC 会自动检测到哪些数据块不再被任何文件所引用,并清除它们。

docker exec seafile /scripts/gc.sh

如果你认为这篇文章还不错,可以考虑为我充电 ⚡️