TL;DR

Official Docker image (Community Edition):

1
docker exec seafile /scripts/gc.sh        # stops Seafile, runs the GC, starts it again

Binary install, or a container with the manual sequence:

1
2
3
4
5
cd /opt/seafile/seafile-server-latest
./seafile.sh stop
./seaf-gc.sh --dry-run        # how many blocks would go, deleting nothing
./seaf-gc.sh                  # delete
./seafile.sh start

On Kubernetes, the same inside the pod: kubectl -n seafile exec -it deploy/seafile -- bash and the sequence above (or /scripts/gc.sh if it is the official image).

Before anything else: System Admin → Libraries → Trash → clean. A library sitting in the trash keeps all of its blocks and the GC will not touch it.

Why the disk does not shrink by itself

Seafile stores files chunked into content-addressed blocks under seafile-data/storage/ (blocks/, fs/, commits/). Deleting a file or a library only writes a new commit; the blocks stay because the library’s history still references them, and because another library or an older version might use them. The only thing that removes them is seaf-gc, which walks the live commits and deletes everything nobody references anymore.

Two things decide what “nobody” means:

  • The library trash in the admin panel: a library deleted by a user is not removed, it is moved there. Until you clean it, its blocks count as alive.
  • Each library’s history (History settings: days to keep). The GC honors that window; with unlimited history, blocks from old versions are never freed.

Requirements

  • Community Edition: Seafile stopped. Blocks written while the GC runs could be deleted by mistake. The official image’s /scripts/gc.sh stops and starts it for you; by hand, seafile.sh stop before and seafile.sh start after. Pro has online GC.
  • Maintenance window. Runtime grows with storage size; on big installs it is hours.
  • Backup or snapshot of seafile-data (on ZFS, a zfs snapshot is instant). It is the first time something will actually delete blocks.

seaf-gc.sh options

OptionWhat it does
--dry-runCounts what would be deleted and deletes nothing. Always start here
-rOnly blocks from deleted libraries (the ones already purged from the trash), without checking history. The fastest for “I deleted a 500 GB library”
--rm-fsAlso deletes orphaned fs objects. Buggy before CE 11.0.7 / Pro 10.0.15; upgrade before using it
-t NThreads. Only helps with object backends (S3, etc.); with a local filesystem leave it at 1
--id-prefix abOnly libraries whose ID starts with that prefix (to split a long pass)
<id> [<id>…]Only those libraries

Single-library dry run:

1
./seaf-gc.sh --dry-run 3f5a1c2e-7b9d-4e21-8c44-0a6d9e7f1b23

Full procedure

  1. Admin panel → Libraries → Trash → clean (or Clean per library). Without this step the GC reports zero blocks and you wonder why.
  2. Review the history of the big libraries (History settings); if they keep everything forever, decide on a number of days.
  3. Snapshot or backup of seafile-data.
  4. docker exec seafile /scripts/gc.sh, or the manual sequence with --dry-run first. The output ends with the per-library block summary.
  5. Check: du -sh /opt/seafile-data/seafile/storage/blocks and df -h.

To avoid doing it by hand, a weekly overnight cron with the same docker exec is enough on CE.

Traps

  • “GC frees nothing”: trash not emptied, unlimited history, or blocks held by filesystem snapshots (on ZFS, zfs list -t snapshot and its USED).
  • Never with Seafile up on CE. If the container runs seafile-server as its main process, seafile.sh stop inside can take the container down; with the official image use /scripts/gc.sh, which accounts for it.
  • --rm-fs on old versions can delete objects that are in use; only from CE 11.0.7.
  • Nginx in front and clients showing Server error when syncing after the GC: it is usually client_max_body_size too low, not the GC; set it to 0 in Seafile’s server block.
  • Encrypted libraries are collected the same way; the GC does not need the password.

Reference: Seafile GC in the admin manual.