Seafile is a lightweight, fast self-hosted file sync tool — a real alternative to OneDrive/ Dropbox for your own files. Here's the deployment, a genuine security incident worth learning from, a Cloudflare gotcha that only broke one specific client app, and the honest truth about what "automatic sync" can and can't mean on an iPhone.
Nextcloud can do file sync too, but it's a much heavier all-in-one suite if all you actually want is sync + share — same reasoning that applies any time you're picking a focused tool over a do-everything platform. Syncthing is lighter and fully peer-to-peer, but its story on iOS is weaker: it fights the same background execution restrictions covered below, without even the benefit of a proper client-server model. Seafile sits in the middle — a real server, a real desktop sync client on macOS/Linux/Windows, and a proper (if limited) iOS app.
Standard Docker Compose: the official seafileltd/seafile-mc image, plus MariaDB and memcached.
Point it at a reverse proxy (Caddy, nginx, whatever you're already running) with a real TLS cert if you want
it reachable outside your LAN.
services:
db:
image: mariadb:10.11
environment:
- MYSQL_ROOT_PASSWORD=<generated>
volumes:
- /data/mysql:/var/lib/mysql
memcached:
image: memcached:1.6.29
entrypoint: memcached -m 256
seafile:
image: seafileltd/seafile-mc:12.0-latest
ports:
- "80:80"
volumes:
- /data/seafile:/shared
environment:
- DB_HOST=db
- DB_ROOT_PASSWD=<generated>
- [email protected]
- INIT_SEAFILE_ADMIN_PASSWORD=<generated>
- SEAFILE_SERVER_HOSTNAME=files.example.com
- SEAFILE_SERVER_PROTOCOL=https
- JWT_PRIVATE_KEY=<generated>
SEAFILE_ADMIN_EMAIL/SEAFILE_ADMIN_PASSWORD — a completely reasonable guess, and the
convention plenty of other self-hosted apps actually use. This image doesn't. It wants
INIT_SEAFILE_ADMIN_EMAIL/INIT_SEAFILE_ADMIN_PASSWORD (only found by reading
/scripts/start.py inside the container directly — not obvious from the image's own docs).
Because the wrong env vars matched nothing the entrypoint script checked for, Docker did exactly what
Docker always does with an env var nothing reads: silently ignored it. The container came up completely
healthy, logged a normal-looking "Successfully created seafile admin" line, and fell back to its own
hardcoded default account instead — [email protected] / asecret, a well-known,
publicly documented default. Since this instance was reachable from the open internet (not LAN-gated), that
meant a real admin panel sat on a public default credential from the moment it deployed, until a login
attempt with the intended password failed and that's what actually surfaced the problem.
curl -X POST https://files.example.com/api2/auth-token/ \
-d "[email protected]&password=yourpassword"
# should return a real token — if it doesn't, don't assume "close enough"
Seafile 12 introduced a privacy feature where any account created through the normal admin API gets an
opaque, randomly-generated login (<random>@auth.local), with your real email stored only
as a separate "contact email" — not the actual login. Creating a fresh account expecting a normal login
produces an unusable random ID instead. The account created by the container's own first-boot init script
doesn't go through this path, though — its literal email is the real login. If you hit this, don't fight the
Virtual ID system; instead, link your real email as the contact email of the account that already
works, and Seafile's own login flow will resolve it automatically.
If you're behind Cloudflare and your iOS app reports something like "no available cert" or "no available certificates" when logging in — even with fully valid credentials and a properly-chained public TLS certificate — check whether your Cloudflare zone has a client certificate (mTLS) configured, even one you don't remember setting up on purpose.
CertificateRequest during the handshake —
most clients (browsers, curl, other iOS apps like Bitwarden or Immich) handle an optional request
fine, connecting without ever presenting one. Seafile's iOS app apparently doesn't, and fails outright
instead.
Fix: in Cloudflare, SSL/TLS → Client Certificates → find the certificate covering your domain → Edit its Hosts → remove the hostname (or the whole wildcard, if nothing else actually needs it). Verify the fix with a raw TLS handshake check rather than just retrying the app:
echo | openssl s_client -connect files.example.com:443 -servername files.example.com 2>&1 \
| grep -i "client certificate"
# should show: No client certificate CA names sent
If what you actually want is OneDrive-style invisible, continuous, background sync on an iPhone — the straightforward answer is: no third-party app achieves that, and this isn't a Seafile limitation specifically. Apple doesn't grant third-party apps the background execution privileges needed for continuous bidirectional file sync the way a desktop OS allows. This applies equally to OneDrive, Dropbox, and Google Drive's own iOS apps — what makes those feel automatic is Apple's own File Provider framework, a first-party integration point with elevated, system-coordinated background privileges a regular background task simply doesn't get.
Seafile's iOS app does implement a File Provider extension (so the iOS Files app can browse your Seafile libraries directly), but with a real limitation: non-encrypted libraries show up read-only in the Files app — fine for opening existing files from other apps, not a substitute for drag-and-drop uploads.
Practical takeaway: use the desktop client on Mac/Linux/Windows for real always-on sync (no iOS restrictions apply there), and treat the iPhone app as something you open when you need it rather than something running invisibly in the background — that's the actual ceiling, not a configuration you're missing.