有馬総一郎のブログ

(彼氏の事情)

2025年06月28日 18:29:45 JST - 5 minute read - Linux

Seafileはfuse対応していてLinuxでも仮想ファイル機能が使えるのでNextcloudから乗り換える

以前、 Nextcloudより同期が速いと言われるSeafileをDocker+Non-Root Domain Subdirectory構成で試してみるSeafileのインストールを紹介したが、このまま使い続けることにした。

というのも、Nextcloudデスクトップアプリで仮想ファイルに対応しているのが、Windows版[^1]だけだからだ。

ストレジージを消費することなく同期ファイルを使いたい

NextCloud Desktopで仮想ファイル機能を使う にあるとおり、Windows版はストレージを消費することなくNextcloudと同期することができる。

Linu版でもMac版でも nextcloud.cfguseNewBigFolderSizeLimit=trueを追記すれば使えるらしいのだけど VFS on Linux · Issue #3668 · nextcloud/desktop実験的状態に留まっている。2021年から実装が続けられているのだけど、どうも進捗が鈍い気がする。

GNOMEデスクトップのオンラインアカウントによるNextcloudとファイルマネージャのFiles(Nautilux)の統合もあるのだけど、それはWebDAVクライアントとして動作する。WebDAVはやはり遅すぎて常用するのは辛い。しかもデスクトップ環境が限定されるのは困る。

Nextcloudで同期したファイルは、Chromebookでも気軽にアクセスして読み書きしたいんだよね。GoogleDriveを GitHub - astrada/google-drive-ocamlfuse: FUSE filesystem over Google Driveを使っていてfuseの方が速いのは体感済み。

改めてサブドメインを割り当ててSeafileサーバーを構築

ちなみに最新は 13。構築したのは 12 。公式のだと、分割されたcompose.ymlを env ファイルから読み込んでDockerを設定しているけど、何か起動・停止に失敗するときがあるのと、起動させているDockerはSeafileだけではないので、一つのcompose.yamlにまとめて起動させる形に変えた(意味のない修正かも知れないが)。そして、docker compose --env-file seafile/.env -f seafile/seafile_compose.yaml startenv ファイルを指定して、他のdockerのcompose.yamlとは別指定して起動してる。

env ファイルがいるからか?restart: unless-stoppedとしても、自動起動はしてくれない。また、ネットワークを別扱いにしてcaddy用のdocker起動させればホスト側のnginxと共存できるかと思ったが、知識が足らなくて上手くいかなかったので断念した。seadocも上手くいってない…駄目駄目状態だが、まあやりかたいことは同期なので良し。

seafile/seafile_compose.yml

version: '3'

services:
  mariadb:
    image: ${SEAFILE_DB_IMAGE:-mariadb:10.11}
    container_name: seafile-mysql
    restart: unless-stopped
    environment:
      - MYSQL_ROOT_PASSWORD=${INIT_SEAFILE_MYSQL_ROOT_PASSWORD:?Variable is not set or empty}
      - MYSQL_LOG_CONSOLE=true
      - MARIADB_AUTO_UPGRADE=1
    volumes:
      - "${SEAFILE_MYSQL_VOLUME:-/opt/seafile-mysql/db}:/var/lib/mysql"
    networks:
      - seafile-net
    healthcheck:
      test:
        [
          "CMD",
          "/usr/local/bin/healthcheck.sh",
          "--connect",
          "--mariadbupgrade",
          "--innodb_initialized",
        ]
      interval: 20s
      start_period: 30s
      timeout: 5s
      retries: 10

  memcached:
    image: ${SEAFILE_MEMCACHED_IMAGE:-memcached:1.6.29}
    container_name: seafile-memcached
    restart: unless-stopped
    entrypoint: memcached -m 256
    networks:
      - seafile-net

  seafile:
    image: ${SEAFILE_IMAGE:-seafileltd/seafile-mc:12.0-latest}
    container_name: seafile
    restart: unless-stopped
    volumes:
      - ${SEAFILE_VOLUME:-/opt/seafile-data}:/shared
    ## fuse start
      - type: bind
        source: /opt/seafile-fuse
        target: /seafile-fuse
        bind:
          propagation: rshared
    privileged: true
    cap_add:
      - SYS_ADMIN
    ## fuse end
    ports:
      - "8000:80"
      - "18888:80"
      - "8082:8082"
      - "8083:8083"
    environment:
      - DB_HOST=${SEAFILE_MYSQL_DB_HOST:-db}
      - DB_PORT=${SEAFILE_MYSQL_DB_PORT:-3306}
      - DB_USER=${SEAFILE_MYSQL_DB_USER:-seafile}
      - DB_ROOT_PASSWD=${INIT_SEAFILE_MYSQL_ROOT_PASSWORD:-}
      - DB_PASSWORD=${SEAFILE_MYSQL_DB_PASSWORD:?Variable is not set or empty}
      - SEAFILE_MYSQL_DB_CCNET_DB_NAME=${SEAFILE_MYSQL_DB_CCNET_DB_NAME:-ccnet_db}
      - SEAFILE_MYSQL_DB_SEAFILE_DB_NAME=${SEAFILE_MYSQL_DB_SEAFILE_DB_NAME:-seafile_db}
      - SEAFILE_MYSQL_DB_SEAHUB_DB_NAME=${SEAFILE_MYSQL_DB_SEAHUB_DB_NAME:-seahub_db}
      - TIME_ZONE=${TIME_ZONE:-Etc/UTC}
      - INIT_SEAFILE_ADMIN_EMAIL=${INIT_SEAFILE_ADMIN_EMAIL:-me@example.com}
      - INIT_SEAFILE_ADMIN_PASSWORD=${INIT_SEAFILE_ADMIN_PASSWORD:-asecret}
      - SEAFILE_SERVER_HOSTNAME=${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty}
      - SEAFILE_SERVER_PROTOCOL=${SEAFILE_SERVER_PROTOCOL:-http}
      - SITE_ROOT=${SITE_ROOT:-/}
      - NON_ROOT=${NON_ROOT:-false}
      - JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY:?Variable is not set or empty}
      - SEAFILE_LOG_TO_STDOUT=${SEAFILE_LOG_TO_STDOUT:-false}
      - ENABLE_SEADOC=${ENABLE_SEADOC:-false}
      - SEADOC_SERVER_URL=${SEADOC_SERVER_URL:-http://example.example.com/sdoc-server}
    depends_on:
      - mariadb
      - memcached
    networks:
      - seafile-net

networks:
  seafile-net:
    name: seafile-net

seafile.nginx.conf

    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 Connection "";
        proxy_http_version 1.1;

        client_max_body_size 0;
    }
    location /seafhttp {
        rewrite ^/seafhttp(.*)$ $1 break;
        proxy_pass http://127.0.0.1:8082/seafhttp;
        client_max_body_size 0;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_connect_timeout  36000s;
        proxy_read_timeout  36000s;
    }
        
    location /seafmedia {
        rewrite ^/seafmedia(.*)$ /media$1 break;
        proxy_pass http://127.0.0.1:8000/seafmedia;
    }

.env

SEAFILE_IMAGE=seafileltd/seafile-mc:12.0-latest
SEAFILE_DB_IMAGE=mariadb:10.11
SEAFILE_MEMCACHED_IMAGE=memcached:1.6.29
SEAFILE_CADDY_IMAGE=lucaslorentz/caddy-docker-proxy:2.9

SEAFILE_VOLUME=/mnt/hdd1/Public/seafile-data
SEAFILE_MYSQL_VOLUME=/home/arimasou16/seafile/db
SEAFILE_CADDY_VOLUME=/home/arimasou16/seafile/seafile-caddy

SEAFILE_MYSQL_DB_HOST=mariadb
INIT_SEAFILE_MYSQL_ROOT_PASSWORD=初期MySQL rootパスワード
SEAFILE_MYSQL_DB_USER=seafile
SEAFILE_MYSQL_DB_PASSWORD=seafileパウワード

TIME_ZONE=Asia/Tokyo

JWT_PRIVATE_KEY=JWTプライベートキー

SEAFILE_SERVER_HOSTNAME=seafileホスト名
SEAFILE_SERVER_PROTOCOL=https

INIT_SEAFILE_ADMIN_EMAIL=管理者メールアドレス
INIT_SEAFILE_ADMIN_PASSWORD=管理者パスワード

SEADOC_IMAGE=seafileltd/sdoc-server:1.0-latest
SEADOC_VOLUME=/home/arimasou16/seafile/seadoc-data

ENABLE_SEADOC=false
SEADOC_SERVER_URL=sdoc-serverのURL


NON_ROOT=false

そして、fuseを有効にするには FUSE extension - Seafile Admin Manualにあるとおり、 yml ファイルにfuseの設定を追加する。

seafile/seafile_compose.yml

version: '3'

services:

  seafile:
    image: ${SEAFILE_IMAGE:-seafileltd/seafile-mc:12.0-latest}
    container_name: seafile
    restart: unless-stopped
    volumes:
      - ${SEAFILE_VOLUME:-/opt/seafile-data}:/shared
+      - type: bind
+        source: /opt/seafile-fuse
+        target: /seafile-fuse
+        bind:
+          propagation: rshared
+    privileged: true
+    cap_add:
+      - SYS_ADMIN
    ports:
      - "8000:80"

docker compose up -ddocker compose --env-file seafile/.env -f seafile/seafile_compose.yaml startなどでコンテナを起動する。そして、docker exec -it seafile bashで、コンテナにログインする。

arimasou16@ubuntu:~$ docker exec -it seafile bash
root@0cdc083e6daf:/opt/seafile# ls -l
total 8
lrwxrwxrwx 1 root root   21 Jun 17 07:40 ccnet -> /shared/seafile/ccnet
lrwxrwxrwx 1 root root   20 Jun 17 07:40 conf -> /shared/seafile/conf
lrwxrwxrwx 1 root root   20 Jun 17 07:40 logs -> /shared/seafile/logs
drwxr-xr-x 2 root root 4096 Jun 27 23:55 pids
lrwxrwxrwx 1 root root   24 Jun 17 07:40 pro-data -> /shared/seafile/pro-data
lrwxrwxrwx 1 root root   28 Jun 17 07:40 seafile-data -> /shared/seafile/seafile-data
drwxr-xr-x 1 root root 4096 Jan  8 13:00 seafile-server-12.0.7
lrwxrwxrwx 1 root root   34 Apr 20 10:33 seafile-server-latest -> /opt/seafile/seafile-server-12.0.7
lrwxrwxrwx 1 root root   27 Jun 17 07:40 seahub-data -> /shared/seafile/seahub-data

cd /opt/seafile/seafile-server-latest/と、/seaf-fuse.sh のあるディレクトリに移動して ./seaf-fuse.sh start /seafile-fuseシェルを実行する。

root@0cdc083e6daf:/opt/seafile# cd /opt/seafile/seafile-server-latest/
root@0cdc083e6daf:/opt/seafile/seafile-server-latest# ls -l
total 176
-rw-r--r-- 1 root root 10899 Jan  8 12:52 check_init_admin.py
-rw-r--r-- 1 root root  1675 Jan  8 12:52 migrate_ldapusers.py
drwxr-xr-x 1 root root  4096 Jan  8 13:00 pro
-rwxr-xr-x 1 root root  2418 Jan  8 12:52 reset-admin.sh
drwxr-xr-x 1 root root  4096 Jun 17 07:40 runtime
-rwxr-xr-x 1 root root  2676 Jan  8 12:52 seaf-fsck.sh
-rwxr-xr-x 1 root root  3915 Jan  8 12:52 seaf-fuse.sh
-rwxr-xr-x 1 root root  4526 Jan  8 12:52 seaf-gc.sh
drwxr-xr-x 6 root root  4096 Jan  7 18:48 seafile
-rwxr-xr-x 1 root root  7719 Jan  8 12:52 seafile-monitor.sh
-rwxr-xr-x 1 root root  7089 Jan  8 12:52 seafile.sh
drwxr-xr-x 1 root root  4096 Dec 17  2024 seahub
-rwxr-xr-x 1 root root  8695 Jan  8 12:52 seahub.sh
-rw-r--r-- 1 root root 57704 Jan  8 12:52 setup-seafile-mysql.py
-rwxr-xr-x 1 root root  1543 Jan  8 12:52 setup-seafile-mysql.sh
-rwxr-xr-x 1 root root 22513 Jan  8 12:52 setup-seafile.sh
drwxr-xr-x 4 root root  4096 Dec  9  2024 sql
drwxr-xr-x 3 root root  4096 Dec 11  2024 upgrade
root@0cdc083e6daf:/opt/seafile/seafile-server-latest# ./seaf-fuse.sh start /seafile-fuse
seaf-fuse is already running, pid 2334221
2334225

上のメッセージは一度起動してるため、起動中ということで終了している。1回目は以下のようなメッセージが表示される。

Starting seaf-fuse, please wait ...
seaf-fuse started

Failed to start seaf-fuseというメッセージが表示してなければ、無事、起動出来ているはず。

seaf-fuse.sh の使い方は以下のとおり。

usage : 
seaf-fuse.sh { start <mount-point> | stop | restart <mount-point> } 

一度、実行すれば意図的に止めたりしないかぎりはfuseは有効、実行されたまま。というか、stoprestart /seafile-fuseしても止まらないような…まあ、動いているから良いんだけど。

root@0cdc083e6daf:/opt/seafile/seafile-server-latest# ./seaf-fuse.sh stop

Stopping seaf-fuse ...
Terminated

そして、Chromebookで SeaDriveを起動する。個人的にはローカルにファイルがあるかと思うぐらいアクセスして開く・起動するまでが速い! RcloneでもSeafileは対応しているので、GUIとか拘りがないなら、こちらを常用していくのも良いかも。

SeaDrive
SeaDrive
SeaDrive
SeaDrive

以上。