Seafile
Seafile syncs files between devices and shares them with other people, with desktop and mobile clients and optional collaborative editing. Eight containers, split across five compose files so the optional parts can be switched off.
Last run on a host 8 Nov 2026 · data restored from a backup
Pinned at seafileltd/seafile-mc:13.0.29 (released 4 Nov 2026) · upstream has released 14.0.9 on 13 Oct 2026
In the upstream images: 3 CRITICAL · 103 HIGH with a published fix — per image
To try it: Docker, nothing else. See Try it locally.
To deploy it behind the proxy: Traefik running, a domain, and SMTP if the server should send invitations or reset links.
Try it locally
Section titled “Try it locally”On your own machine, with no proxy, domain or certificate. From apps/seafile/:
cp .env.local.example .env.local
# The secrets ship empty; generate the ones this stack needs{ echo "SEAFILE_DB_PASSWORD=$(openssl rand -base64 32 | tr -d '\n')" echo "DB_ROOT_PASSWORD=$(openssl rand -base64 32 | tr -d '\n')" echo "REDIS_PASSWORD=$(openssl rand -hex 32)" echo "SEAFILE_ADMIN_PASSWORD=$(openssl rand -base64 32 | tr -d '\n')" echo "JWT_PRIVATE_KEY=$(openssl rand -base64 48 | tr -d '\n')"} >> .env.local
mkdir -p volumes/local/mysql volumes/local/redis volumes/local/seafile-datasudo chown 999:999 volumes/local/mysql
docker compose -f docker-compose.local.yml --env-file .env.local up -dThen open http://127.0.0.1:8000. Stop it again with the same command and down.
What is in the stack
Section titled “What is in the stack”COMPOSE_FILE in .env decides which parts run. Removing a filename and running
docker compose up -d again switches that component off.
| File | Services | Required |
|---|---|---|
seafile-server.yml |
the server, MariaDB, memcached, Redis | yes |
seadoc.yml |
collaborative document editor | optional |
notification-server.yml |
push notifications for file changes | optional |
md-server.yml |
file metadata and extended properties | optional |
thumbnail-server.yml |
image and video thumbnails | optional |
onlyoffice-callback.yml |
no service: the two routes OnlyOffice calls back on | with OnlyOffice |
All of them are served under one hostname; Traefik routes by path.
Installation
Section titled “Installation”From apps/seafile/:
-
Copy the environment file and set
APP_TRAEFIK_HOST,SEAFILE_ADMIN_EMAILandTIMEZONE:Terminal window cp .env.example .env -
Generate the secrets:
Terminal window mkdir -p .secretsopenssl rand -base64 32 | tr -d '\n' > .secrets/db_root_pwd.txtopenssl rand -base64 32 | tr -d '\n' > .secrets/seafile_db_pwd.txtopenssl rand -base64 32 | tr -d '\n' > .secrets/seafile_admin_pwd.txtopenssl rand -base64 48 | tr -d '\n' > .secrets/jwt_key.txtopenssl rand -hex 32 | tr -d '\n' > .secrets/redis_pwd.txtThe Redis password is hex, not base64: Seafile builds its Redis URL from it without escaping, and a
/would end the URL early.The thumbnail server does not read Docker secrets; it takes two of these values from
.env. Left empty, every thumbnail fails while the container reports healthy:Terminal window sed -i "s|^JWT_PRIVATE_KEY=.*|JWT_PRIVATE_KEY=$(cat .secrets/jwt_key.txt)|" .envsed -i "s|^SEAFILE_MYSQL_DB_PASSWORD=.*|SEAFILE_MYSQL_DB_PASSWORD=$(cat .secrets/seafile_db_pwd.txt)|" .env -
Create the SMTP secret file even if mail stays off — compose mounts it unconditionally:
Terminal window touch .secrets/smtp_pwd.txt # mail disabled# printf '%s' 'SMTP-PASSWORD' > .secrets/smtp_pwd.txt # mail enabledThe OnlyOffice secret file is mounted unconditionally as well. An empty file keeps the integration off; with OnlyOffice, reuse its secret:
Terminal window touch .secrets/onlyoffice_jwt_secret.txt # no OnlyOffice# cp ../onlyoffice/.secrets/jwt_secret.txt .secrets/onlyoffice_jwt_secret.txt # with OnlyOffice -
Start it. The first boot initialises the databases and runs migrations, which takes two to four minutes:
Terminal window docker compose up -ddocker compose logs seafile --followWait for
Seafile server started. -
Recreate the server container once. On the first boot Seafile writes
seahub_settings.pyafter the entrypoint has already run, so the blueprint block — mail, document editing, metadata, thumbnails — is not in it yet:Terminal window docker compose up -d --force-recreate seafile -
Confirm the block arrived:
Terminal window docker compose exec seafile bash -lc \'grep -n "# --- Blueprint custom settings ---" /shared/seafile/conf/seahub_settings.py \|| echo "STILL MISSING — check entrypoint logs"' -
Open
https://<APP_TRAEFIK_HOST>and log in asSEAFILE_ADMIN_EMAILwith the password from.secrets/seafile_admin_pwd.txt.
Verify
Section titled “Verify”docker compose ps # eight services with the default COMPOSE_FILEThen upload a file through the web interface and sync it with a desktop client. Sync is what this stack exists for and it exercises paths the web interface does not.
If mail is enabled, invite a user and confirm the message arrives. Without the settings block from step 5, Seafile reports that the mail service is not configured.
Going further
Section titled “Going further”Private by default
Section titled “Private by default”The stack ships access-trusted-vpn, with limit-sync and headers-standard.
Seafile holds whatever people put in it, and the sync clients reach it over the
same hostname, so widening the access policy is a decision about every client at
once.
Document editing
Section titled “Document editing”seadoc.yml adds the collaborative editor for .sdoc files; it calls Seafile
over the internal network, so the closed route does not stand in its way.
OnlyOffice is a separate stack with its own hostname — see
OnlyOffice. It calls Seafile back at its public
name on two paths: the document fetch under /seafhttp/files/ and the save
callback /onlyoffice/editor-callback/. The stack ships closed
(access-trusted-vpn), which refuses a request from a container, so
onlyoffice-callback.yml opens exactly those two paths with access-public —
add it to COMPOSE_FILE when you run OnlyOffice; the rest of the instance stays
closed:
COMPOSE_FILE=seafile-server.yml,seadoc.yml,thumbnail-server.yml,onlyoffice-callback.ymlA Document Server on another host reaches a closed instance by its address in
TRUSTED_RANGES or over the VPN instead, with the file left out.
Backup
Section titled “Backup”| Databases | MariaDB, container seafile-db, three databases: ccnet_db, seafile_db, seahub_db, user seafile |
| Password | .secrets/seafile_db_pwd.txt |
| State | volumes/mysql · volumes/seafile-data (the file store) · volumes/seadoc-data |
| Rebuildable | volumes/redis · the log directory under volumes/seafile-data |
| Quiescing | Not needed. Seafile writes content-addressed blocks, so a file captured mid-write is a new block rather than a damaged one. |
For borgmatic:
mariadb_databases: - name: ccnet_db container: seafile-db username: seafile password: "{credential file /srv/docker/apps/seafile/.secrets/seafile_db_pwd.txt}" - name: seafile_db container: seafile-db username: seafile password: "{credential file /srv/docker/apps/seafile/.secrets/seafile_db_pwd.txt}" - name: seahub_db container: seafile-db username: seafile password: "{credential file /srv/docker/apps/seafile/.secrets/seafile_db_pwd.txt}"All three are required: seafile_db holds the file metadata, ccnet_db the
users and groups, seahub_db the web layer with shares and links. Any one of them
missing produces a restore that starts and is unusable.
Restore order: the three databases, then the file store, then the application.
Updates
Section titled “Updates”-
Read the release notes. Seafile’s major versions carry database migrations.
-
Back up all three databases and
volumes/seafile-datatogether. -
Raise the image variables in
.env, then:Terminal window docker compose pull && docker compose up -ddocker compose logs seafile --follow -
Log in and sync one file. A migration that touched the metadata tables shows up in the client rather than in the interface.
Troubleshooting
Section titled “Troubleshooting”“Email service is not properly configured” right after installing. The settings block is missing. Run installation step 5, then check with step 6.
Document editing, metadata or thumbnails are absent after a fresh install. Same cause, same fix.
A restored instance starts but shares and links are gone. Only some of the three databases came back. All three are required.
A component should be switched off. Remove its filename from COMPOSE_FILE
in .env and run docker compose up -d again.
Repository files
Section titled “Repository files”apps/seafile/README.md— setup, the five-file split, secret handlingapps/seafile/config/README.md— how the entrypoint injects settingsapps/seafile/UPSTREAM.md— source and upgrade checklistapps/seafile-pro/— the commercial edition, covered by its own guide
Official sources
Section titled “Official sources”© 2026 SecDockBlueCode Apache-2.0Site content CC BY-NC 4.0