Use case · File sync and share

Seafile self-hosted on a dedicated server: Docker, HTTPS, GC and backups

A self-hosted Seafile server is the official Docker stack (Seafile, MariaDB, Redis, SeaDoc and Caddy) driven by one .env file, on a Linux machine; Community Edition sets a 2-core, 2 GB floor. Caddy answers on 80 and 443 and terminates TLS; everything else stays on a private Docker network. This page covers sizing, the .env values that matter, the first admin, the firewall, garbage collection, backups, upgrades and the licence question, from the Seafile 13.0 admin manual.

See the machines

What Seafile needs from the machine

Seafile's requirements are modest in CPU and memory and open-ended in disk. The manual lists them per edition for a Docker deployment, which bundles Seafile, Redis, MariaDB, SeaDoc and Caddy (Pro adds Elasticsearch):

EditionCPUMemoryDisk
Community (CE)2 cores, above 2 GHz recommended2 GB10 GB free, more than 50 GB recommended
Pro, default Elasticsearch4 cores4 GBmore than 50 GB recommended
Pro with SeaSearch, or Elasticsearch on another host2 cores2 GBmore than 50 GB recommended

The manual calls these minimums and says to add resources for extensions such as OnlyOffice. Disk is the number to size from your data, not from the table. Seafile splits every file into variable-length blocks with content-defined chunking (around 8 MB on average) and deduplicates blocks between versions, so frequently edited files cost less than their raw history would. Old blocks are only reclaimed by garbage collection, and library history you keep is space you pay for.

The images, including seafile-mc and seafile-pro-mc, are published for both x86 and ARM64.

Why a whole machine, and which one

Seafile stores its block store on local disk, keeps its metadata in MariaDB and serves sync traffic from the same box. On a dedicated server all three get all cores, all RAM and every disk to themselves, with root and no other tenant. The port is unmetered: no transfer allowance and no overage fee, which matters when a team's first full sync pulls every library at once.

  • Disks and RAID. The rack and blade lines carry a hardware RAID controller (HPE Smart Array with flash-backed cache, Smart HBA or Dell BOSS). No Moonshot cartridge has one; the m510, m710x and m750 run software RAID over NVMe. For a large file store, build one to order: up to 24 bays, RAID 0, 1, 5, 6 or 10, or JBOD, on SATA, SAS, SSD or NVMe, handed over 4 to 24 hours after the order clears review.
  • Console. Every racked single-, dual- and quad-socket server has an out-of-band console (iLO, iDRAC or a Supermicro BMC), so a bad firewall rule is recoverable without a ticket.
  • ARM. The Seafile images run on ARM64, so the ARM line on Ampere Altra is an option.
  • Delivery. A racked machine is handed over in about 30 minutes once payment is approved.

Pick the city nearest your users from the five locations; sync latency follows distance.

Deploying the Docker stack

Install Docker from its official guide, point a DNS record for your hostname at the server, then fetch the 13.0 files into /opt/seafile. As root:

mkdir /opt/seafile
cd /opt/seafile
wget -O .env https://manual.seafile.com/13.0/repo/docker/ce/env
wget https://manual.seafile.com/13.0/repo/docker/ce/seafile-server.yml
wget https://manual.seafile.com/13.0/repo/docker/seadoc.yml
wget https://manual.seafile.com/13.0/repo/docker/caddy.yml
chmod 600 .env          # it will hold every password of the stack
nano .env
docker compose up -d    # run it in the directory that holds .env
docker logs seafile -f  # wait for 'Successfully created seafile admin'

Data lands in /opt/seafile-data (Seafile's config, logs and blocks), /opt/seafile-mysql/db, /opt/seafile-caddy and, because SeaDoc is enabled as shipped, /opt/seadoc-data. The manual advises against moving these paths.

The .env values that matter

VariableSet it to
SEAFILE_SERVER_HOSTNAMEYour domain, e.g. files.example.com. Required.
SEAFILE_SERVER_PROTOCOLhttps (the default is http)
JWT_PRIVATE_KEYA random string of at least 32 characters; the manual generates one with pwgen -s 40 1
SEAFILE_MYSQL_DB_PASSWORDThe seafile database user's password. Required.
INIT_SEAFILE_MYSQL_ROOT_PASSWORDMariaDB root password, needed on the first deployment
INIT_SEAFILE_ADMIN_EMAIL / INIT_SEAFILE_ADMIN_PASSWORDThe first admin account; the shipped defaults are me@example.com and asecret

There is no SERVICE_URL to set any more: the 12.0 release removed SERVICE_URL and FILE_SERVER_ROOT, and Seafile derives the URL from SEAFILE_SERVER_PROTOCOL and SEAFILE_SERVER_HOSTNAME.

The admin password is set in .env, never on a command line, so it stays out of ps and shell history. After you first sign in, change the admin password in the web interface, then replace the INIT_SEAFILE_ADMIN_PASSWORD value in .env with a long random string. A lost admin is recovered with docker exec -it seafile /opt/seafile/seafile-server-latest/reset-admin.sh, which prompts for the new credentials.

Do not leave either INIT_ admin value empty: in seafile-server.yml an empty INIT_SEAFILE_ADMIN_PASSWORD defaults to asecret and an empty INIT_SEAFILE_ADMIN_EMAIL to me@example.com, each on its own, and a stack started again from empty volumes would create an admin with those values. The env file files the INIT_ values under "Only valid in first-time startup"; our reading is that Seafile ignores them after setup.

HTTPS, published ports and ufw

Since Seafile Docker 12.0, Caddy handles HTTPS. With SEAFILE_SERVER_PROTOCOL=https and the hostname set, it obtains and renews the certificate itself and keeps it in /opt/seafile-caddy; a custom certificate goes in /opt/seafile-caddy/certs. Caddy is the only service that publishes ports (80 and 443); the Seafile container's own 80:80 mapping ships commented out, and MariaDB and Redis are reachable only on the seafile-net network.

Docker writes its own iptables rules for published ports, so ufw does not filter 80 and 443 here. That is acceptable because both must be public for TLS. Do not uncomment other port mappings; if you need one for testing, bind it to 127.0.0.1. Whether Docker also listens on IPv6 depends on the daemon's configuration, so check with ss -tlnp after start-up. ufw still guards everything else on the host, over IPv4 and IPv6:

grep IPV6 /etc/default/ufw    # must read IPV6=yes
ufw default deny incoming
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw --force enable    # no y/n prompt to swallow the next line
ufw status verbose

Garbage collection and integrity checks

Deleting a file or a library does not free its blocks, because other files may share them. seaf-gc.sh removes blocks of deleted libraries and history older than any limit you set per library. Libraries deleted by users wait in the admin trash first, and their blocks are not collected until the trash is cleared. Since 12.0, Community Edition can run GC while Seafile is running.

  • Preview: docker exec seafile bash -c 'cd /opt/seafile/seafile-server-latest && ./seaf-gc.sh --dry-run'
  • Collect: the same command without --dry-run; -r handles only deleted libraries, and on disk storage GC runs one thread unless you pass -t.
  • In cron, use docker exec without -it: there is no terminal to attach.
  • After a restore, run seaf-fsck.sh from the same directory to check library integrity.

Backup and restore

A backup is the three databases (ccnet_db, seafile_db, seahub_db) plus /opt/seafile-data/seafile (conf, seafile-data, seahub-data). The script also keeps /opt/seadoc-data, .env and the compose files; those three are our additions to the manual's list. Dump the databases first: the manual explains that a data copy taken before the dump can leave records pointing at blocks the copy missed, which corrupts libraries on restore. Keep each dump as a separate file for at least a week. We don't sell managed backups; point /backup at a mount on another machine or a disk you copy off-site.

# /root/seafile-backup.sh, run as: bash /root/seafile-backup.sh
set -euo pipefail
umask 077               # every file written below is root-only
STAMP=$(date +%F-%H%M)
mkdir -p /backup/databases /backup/data /backup/config
# read the DB password from .env (unquoted value) so it never sits in argv
export MYSQL_PWD=$(sed -n 's/^SEAFILE_MYSQL_DB_PASSWORD=//p' /opt/seafile/.env)
for db in ccnet_db seafile_db seahub_db; do
  docker exec -e MYSQL_PWD seafile-mysql mariadb-dump -u seafile --opt "$db" \
    > "/backup/databases/$db.sql.$STAMP"
done
rsync -az /opt/seafile-data/seafile /backup/data/
rsync -az /opt/seadoc-data /backup/data/
cp -a /opt/seafile/.env /opt/seafile/*.yml /backup/config/   # holds every secret

The manual's own examples pass -p[password] with docker exec -it; the script above swaps that for the MYSQL_PWD variable, which keeps the password off the process list, and drops -it so cron can run it. The config copy holds the database, JWT and admin secrets: keep /backup root-only, and keep the off-site copy root-only too. To restore, copy each dump into seafile-mysql with docker cp, load it with mariadb into the matching database, rsync the data back with rsync -aHAX (dry-run first), then run seaf-fsck.

Upgrades, editions and clients

  • Maintenance releases (10.0.1 to 10.0.4, say): pull the new image, stop the stack, set the image tag in .env if you pin one, and docker compose up -d.
  • Major releases: follow the version-specific section of the Docker upgrade guide and read the upgrade notes first. 12.0 to 13.0 means docker compose down, a fresh seafile-server.yml, plus notification-server.yml, elasticsearch.yml (Pro), seasearch.yml or seadoc.yml where you use them, the 13.0 image tags, the new cache variables in .env, and removing the obsolete cache settings from the old config files. Back up before you start.
  • Community Edition: Seafile Server core is AGPLv3, Seahub (the web UI) Apache 2.0. From 13.0 the binary package is no longer supported for CE; the manual recommends Docker.
  • Pro Edition: the manual states it can be used without a paid licence with up to three users; more users need a purchased licence. Images come from Docker Hub without a login since 12.0.
  • Clients: the desktop sync client (GPLv2), SeaDrive (a virtual drive with folders you can keep offline), Android (GPLv3) and iOS (Apache 2.0). Each signs in to https://your-hostname. The optional notification server pushes library changes, instead of polling, to the desktop client (8.0.11 or later), SeaDrive (3.0.1 or later) and the web interface; the mobile apps are not on its list.

Seafile does file sync, sharing and SeaDoc documents. If you want calendars, contacts and an app store on the same server, compare it with self-hosted Nextcloud.

Questions

How much RAM does a Seafile server need?

The manual's minimum for Community Edition is 2 GB with 2 cores above 2 GHz. Pro with its default Elasticsearch indexer needs 4 GB and 4 cores; with SeaSearch, or Elasticsearch on another host, 2 GB and 2 cores. Add more for extensions such as OnlyOffice.

Where did SERVICE_URL go in Seafile 12 and 13?

It was removed in 12.0 along with FILE_SERVER_ROOT. Seafile now builds the URL from SEAFILE_SERVER_PROTOCOL and SEAFILE_SERVER_HOSTNAME in .env, so set those two and nothing else.

Why does disk usage not drop after deleting files?

Blocks are shared between files and versions, so Seafile keeps them until garbage collection runs. Run seaf-gc.sh with --dry-run to see what can go, then without it. Libraries in the admin trash are not collected until the trash is cleared.

Is Seafile Pro free?

The manual says Pro can be used without a paid licence with up to three users. Beyond that you buy a licence. Community Edition has no user limit; its server core is AGPLv3.

Does Seafile run on ARM?

Yes. The seafile-mc and seafile-pro-mc images are published for x86 and ARM64, and the X.0-latest tag pulls the ARM build without a separate tag. Face embedding and the distributed index server are x86 only. Of our ARM machines, the Ampere Altra line suits it.

Put Seafile on its own machine

Pick a line with the disks your libraries need. Every line includes root access, and every port is unmetered.

See the machines

Related on Server Room

Other use cases