New releases
Recipe version compared with the latest known upstream release. A version number, not a reading of what changed.
Seafile syncs files as deduplicated blocks rather than as a mirrored directory, which is what makes large collections and interrupted transfers fast. Each library syncs separately to desktop, mobile, and the browser, can be shared by link or account, and can be encrypted client-side so the server never sees its contents.
Seafile is file sync and share built around libraries: each library is a separate versioned repository that syncs to a desktop client, a phone, or a web browser, and can be shared by link or by account. Files are stored as deduplicated blocks rather than as a mirrored directory tree, which is what makes syncing large collections and resuming interrupted transfers fast. A library can be encrypted client-side, so the server never sees its contents.
This recipe runs pinned Seafile Community Edition 13.0.25 with MariaDB 10.11 and a Valkey cache. The server keeps its configuration, logs, and the whole object store in one volume; the three databases hold accounts, libraries, and metadata. The web port binds to localhost, the SeaDoc editor, the notification server, and the AI module are switched off because they are separate containers this recipe does not ship.
The full application smoke test and practical backup and restore have passed on
amd64. The published image
supports amd64 only — the ARM builds upstream offers are marked testing — so the
manifest declares one architecture rather than promising a Raspberry Pi. The
administrator account, the MariaDB root password, the database password, the
cache password, and the JWT key all come from .env: give it mode 600, keep it
out of Git, and encrypt every archive, because the same file also decrypts the
backup. SEAFILE_SERVER_HOSTNAME and SEAFILE_SERVER_PROTOCOL are baked into
links, invitation e-mail, and client configuration at first start; changing the
domain later means editing the generated configuration inside the volume.
SAML and the advanced administration features belong to the Professional
Edition and are not part of this recipe.
These are stored results of separate checks, not real-time data. An unknown status means the check has not been performed yet.
Recipe version compared with the latest known upstream release. A version number, not a reading of what changed.
Result of a dedicated Docker image scan, not a Compose configuration check.
A new major version is found by comparing version numbers. A compatibility verdict is entered by hand after reading the release notes and the migration steps.
Upstream Compose changes relative to the verified recipe.
Pinned image tags checked for newer versions.
From observation to action
The recipe already pins the latest known release. The steps below show the evidence retained for that version.
13.0.2513.0.25There is no exact release-notes URL for this manually tracked source. Start with the project sources below.
The version numbers do not cross a major compatibility boundary. No compatibility verdict has been recorded.
No image-tag change is currently planned.
Migration, majors cannot be skipped. Release-specific migration steps still come from the release notes and installation guide.
No version change is currently planned. The recipe includes a backup procedure. Restore has been tested.
An exact Fully verified check for this target was recorded on 2026-09-03.
The status shows how fully the published recipe meets each level's requirements.
A minimal setup for a local network or access through a VPN.
You still need to add: single server, local access, minimum components.
A public deployment with protected access and backups.
You still need to add: domain, https via reverse proxy, off-server backup.
A setup designed for predictable operations and observability.
You still need to add: external monitoring, cpu and memory limits.
Tailored to your server
Answer five questions and download a ready-to-run Seafile bundle.
Screenshots have not been added yet.
Read the full guide first: it explains external access, backups, and data locations.
cp .env.example .envdocker compose up -ddocker compose psUse Ubuntu 22.04+ or Debian 12+ with Docker Engine and Compose v2.24+. Upstream asks for at least 2 CPU cores and 2 GB RAM; plan 4 GB and disk for the whole library collection plus the file history each library keeps. The published image is amd64 only, so an ARM board is not a supported target for this recipe.
docker --version
docker compose version
mkdir -p ~/services/seafile
cd ~/services/seafile
cp .env.example .env
chmod 600 .env
admin_password="$(openssl rand -hex 24)"
db_root_password="$(openssl rand -hex 32)"
db_password="$(openssl rand -hex 32)"
jwt_key="$(openssl rand -hex 32)"
cache_password="$(openssl rand -hex 32)"
sed -i "s|^SEAFILE_ADMIN_PASSWORD=.*|SEAFILE_ADMIN_PASSWORD=$admin_password|" .env
sed -i "s|^SEAFILE_DB_ROOT_PASSWORD=.*|SEAFILE_DB_ROOT_PASSWORD=$db_root_password|" .env
sed -i "s|^SEAFILE_DB_PASSWORD=.*|SEAFILE_DB_PASSWORD=$db_password|" .env
sed -i "s|^SEAFILE_JWT_PRIVATE_KEY=.*|SEAFILE_JWT_PRIVATE_KEY=$jwt_key|" .env
sed -i "s|^SEAFILE_CACHE_PASSWORD=.*|SEAFILE_CACHE_PASSWORD=$cache_password|" .env
echo "administrator password: $admin_password"
unset admin_password db_root_password db_password jwt_key cache_password
The JWT key must be at least 32 characters. All five values must differ and must stay stable: the server stores its generated configuration inside the data volume and expects the same database and cache credentials on every start.
Set the public name before the first start:
sed -i "s|^SEAFILE_SERVER_HOSTNAME=.*|SEAFILE_SERVER_HOSTNAME=files.example.com|" .env
sed -i "s|^SEAFILE_ADMIN_EMAIL=.*|SEAFILE_ADMIN_EMAIL=you@example.com|" .env
Every .env variable:
SEAFILE_PORT is the local web port, default 8000;SEAFILE_SERVER_HOSTNAME is the public host name without scheme or slash, and the setup script rejects localhost;SEAFILE_SERVER_PROTOCOL is the scheme the service is reached by, https behind the proxy examples;SEAFILE_ADMIN_EMAIL and SEAFILE_ADMIN_PASSWORD create the first account on the first start only;SEAFILE_DB_ROOT_PASSWORD is the MariaDB root password, used for setup and for dumps;SEAFILE_DB_PASSWORD is the password of the seafile database role;SEAFILE_JWT_PRIVATE_KEY signs internal service tokens and must be 32 characters or longer;SEAFILE_CACHE_PASSWORD protects the Valkey cache, which is not published to the network;SEAFILE_DB_USER is the database role name, changed only before the first start;SEAFILE_TIME_ZONE is an IANA time zone;SEAFILE_DATA_VOLUME and SEAFILE_DB_VOLUME name the object-store and database volumes;SEAFILE_BACKUP_DIR selects the host backup directory.docker compose config
docker compose pull
docker compose up -d --wait --wait-timeout 900
docker compose ps
curl --fail --silent --output /dev/null http://127.0.0.1:8000/accounts/login/
The first start is slow: the container creates ccnet_db, seafile_db, and
seahub_db, generates the configuration into the data volume, and only then
starts Seahub behind its own nginx. Sign in at the public address with
SEAFILE_ADMIN_EMAIL, then install the desktop or mobile client and connect it
to the same address.
Keep 127.0.0.1:${SEAFILE_PORT}:80; only an HTTPS proxy on the host can reach
the server. MariaDB and the cache have no published ports. Allow SSH, HTTP, and
HTTPS through the firewall. Set SEAFILE_SERVER_PROTOCOL=https and create the
DNS record before the first start: the value is written into the generated
configuration, and clients that were configured with the wrong scheme keep using
it.
Prefer ssh -L 8000:127.0.0.1:8000 user@server. A permanent LAN deployment needs
a resolvable host name — the setup script refuses localhost, so use a name
your LAN DNS answers for, set SEAFILE_SERVER_PROTOCOL=http, replace the
localhost bind with one specific private IP, and restrict the port with a
firewall. Client-side encrypted libraries still protect their contents, but
everything else, including session cookies, travels in clear text on that route.
Set SEAFILE_SERVER_HOSTNAME=files.example.com and
SEAFILE_SERVER_PROTOCOL=https, then replace the host in the Caddy, Nginx, or
Traefik example. The proxy must not cap the request body — file blocks travel
through the same origin, which is why the Nginx sample sets
client_max_body_size 0 and disables request buffering — and must allow long
transfers, so keep the read and send timeouts high. Changing the host name after
the first start requires editing conf/ccnet.conf, conf/seahub_settings.py,
and conf/seafile.conf inside the data volume.
chmod +x backup.sh restore.sh
./backup.sh
The script stops Seafile, dumps all three databases with mariadb-dump, archives
the whole /shared volume with the object store, and stores .env and
compose.yaml next to them. Both halves are needed: a database dump alone
restores an index that points at file blocks that are no longer there. The
archive contains every file and every secret; encrypt it and copy it off the
server.
Restore irreversibly replaces the object store and all three databases. Use the
same Seafile and MariaDB versions with the active .env:
./restore.sh ./backups/seafile-YYYYMMDDTHHMMSSZ.tar
curl --fail --silent --output /dev/null http://127.0.0.1:8000/accounts/login/
The script first backs up the state being replaced, recreates both volumes, unpacks the object store, imports the dump, and starts the server. Desktop clients that synced after the backup will re-upload their local changes; check one client before letting the rest reconnect. This procedure has not passed a practical restore test; rehearse it on a separate server first.
Back up first and read the upstream upgrade notes for the exact version pair. Minor updates inside one major series are a tag change:
./backup.sh
docker compose pull
docker compose up -d --wait --wait-timeout 900
docker compose logs --tail=200 seafile
A major upgrade is not: Seafile runs versioned upgrade scripts and expects you
to move one major version at a time, from the latest minor of the current
series. Do not jump from 12.x to 14.x, and never change MariaDB in the same
step. Replace the exact seafileltd/seafile-mc:13.0.25 tag with a reviewed
version, never a -latest or -testing tag.
Never start an older Seafile over databases a newer version has already upgraded. Restore the previous exact tag together with the pre-update archive:
docker compose down --timeout 120
./restore.sh ./backups/seafile-BEFORE-UPDATE.tar
After a failed MariaDB change, attach the old image to its preserved old volume, or import a compatible dump into an empty volume.
docker compose down preserves both volumes. After verifying an off-server
backup, remove everything irreversibly:
docker compose down
docker volume rm seafile-data seafile-database
rm -rf ~/services/seafile
Substitute actual names when the volume variables differ. Desktop clients keep their own local copies of every synced library; remove them separately if the data must be gone everywhere.
Sources: Seafile CE with Docker, upstream compose file, backup and recovery, and OAuth authentication.
The setup script validates SEAFILE_SERVER_HOSTNAME and rejects localhost and
anything without a dot. Set a real host name — the public domain, or a name your
LAN DNS resolves — then remove the half-initialised volume and start again:
docker compose down --timeout 120
docker volume rm seafile-data seafile-database
docker compose up -d --wait --wait-timeout 900
Only do this while the installation is empty; on a working instance the same command destroys every library.
The first start creates three databases, generates the configuration into the data volume, and then starts Seahub, which is why the health check allows a five minute start period. Watch the progress instead of restarting:
docker compose logs --follow seafile
docker compose ps
docker inspect --format '{{json .State.Health}}' "$(docker compose ps -q seafile)"
502 from the published port during that window is normal: nginx is up before
Seahub is.
docker compose logs --tail=200 db cache
docker compose exec db mariadb --user=root --password="$SEAFILE_DB_ROOT_PASSWORD" -e "SHOW DATABASES;"
The credentials are written into conf/seafile.conf and conf/seahub_settings.py
inside the data volume during setup. Changing SEAFILE_DB_PASSWORD or
SEAFILE_CACHE_PASSWORD in .env afterwards does not rewrite those files, so
either restore the old value or edit the generated configuration to match.
SEAFILE_SERVER_HOSTNAME and SEAFILE_SERVER_PROTOCOL are baked into the
generated configuration at first start. To move to another domain, edit
conf/ccnet.conf (SERVICE_URL), conf/seahub_settings.py
(FILE_SERVER_ROOT, SERVICE_URL), and conf/seafile.conf inside the volume,
then restart:
docker compose exec seafile grep -R "example.com" /shared/seafile/conf
docker compose restart seafile
The proxy is the usual cause: the samples set client_max_body_size 0, disable
request buffering, and raise the read and send timeouts because file blocks pass
through the same origin. A 413 comes from the proxy, a 500 after several
minutes usually means the timeout fired mid-transfer.
That path is the Go file server behind the same nginx, and it answers only with
a valid token, so a bare request returning 400 is expected. A real failure
shows in the logs:
docker compose exec seafile tail -n 100 /shared/logs/seafile/seafile.log
docker compose exec seafile tail -n 100 /shared/logs/seahub/seahub.log
Client-side encrypted libraries are decrypted with a password the server never stores. There is no administrative recovery: a lost library password means the data stays encrypted, even though the blocks are present in the backup.
On the host, run curl -I http://127.0.0.1:8000/accounts/login/. If that
answers, the proxy is looking at the wrong upstream: inside a proxy container
127.0.0.1 is the proxy itself, so use a host gateway address or a shared
Docker network. If it does not answer, start from the health-check section above.
Fossary is an independent informational catalog and is not affiliated with the developers of the listed applications. We collect information from public sources and verify published recipes, but we do not develop, distribute, or control these applications.
A listing or validation status is not a requirement, endorsement, or personal recommendation to use an application. You decide whether it is suitable and use it at your own risk. We do not warrant an application's security, availability, or fitness for purpose and, to the extent permitted by law, are not liable for resulting loss or damage. Review its license, security settings, data processing, and backup procedures before installation.