Storage

Install Seafile Server on Ubuntu 24.04 / 22.04 with Docker

Seafile gives you Dropbox-like file sync and sharing on your own server. Files are organized into libraries that can be synced across devices, shared with teams, and encrypted end-to-end. Unlike Nextcloud, Seafile focuses specifically on file storage rather than trying to be an entire collaboration suite, which keeps it fast and lightweight.

Original content from computingforgeeks.com - post 5234

Seafile 13.0 changed the deployment model significantly. The Community Edition is now Docker-only (binary installation was dropped in 13.0). The upside: deployment is simpler. A single docker compose up -d brings up MariaDB, Redis, the Seafile application server, Caddy as reverse proxy with automatic SSL, and SeaDoc for collaborative editing. This guide walks through the full deployment on Ubuntu 24.04 and 22.04 with Docker Compose.

Tested March 2026 on Ubuntu 24.04.4 LTS with Docker CE 29.3.1, Seafile CE 13.0.19, MariaDB 10.11, Redis, Caddy 2.12

Prerequisites

  • Ubuntu 24.04 LTS or Ubuntu 22.04 LTS
  • Docker Engine and Docker Compose plugin installed (install Docker on Ubuntu)
  • A domain name pointed to your server (for automatic SSL via Caddy)
  • Ports 80 and 443 open in your firewall
  • At least 2 GB RAM and 20 GB disk (more for file storage)

What Gets Deployed

The Docker Compose stack runs five containers:

ContainerImagePurpose
seafileseafileltd/seafile-mc:13.0-latestSeafile server (includes internal Nginx)
seafile-mysqlmariadb:10.11Database backend
seafile-redisredisCache (replaced memcached in v13)
seafile-caddylucaslorentz/caddy-docker-proxy:2.12-alpineReverse proxy with automatic Let’s Encrypt SSL
seadocseafileltd/sdoc-server:2.0-latestCollaborative document editor (SeaDoc 2.0)

Caddy handles SSL automatically. When you set the protocol to https, Caddy obtains and renews Let’s Encrypt certificates without any additional configuration. No certbot, no manual certificate management.

Create the Configuration Files

Create the Seafile directory:

sudo mkdir -p /opt/seafile && cd /opt/seafile

Generate a JWT secret key (used for internal authentication between services):

openssl rand -hex 20

Save the output. You will need it for the .env file.

Environment File (.env)

Create /opt/seafile/.env with your settings. Replace the placeholder values with your own domain, passwords, and JWT key:

COMPOSE_FILE=seafile-server.yml,caddy.yml,seadoc.yml
COMPOSE_PATH_SEPARATOR=,

SEAFILE_IMAGE=seafileltd/seafile-mc:13.0-latest
SEAFILE_DB_IMAGE=mariadb:10.11
SEAFILE_REDIS_IMAGE=redis
SEAFILE_CADDY_IMAGE=lucaslorentz/caddy-docker-proxy:2.12-alpine
SEADOC_IMAGE=seafileltd/sdoc-server:2.0-latest

SEAFILE_VOLUME=/opt/seafile-data
SEAFILE_MYSQL_VOLUME=/opt/seafile-mysql/db
SEAFILE_CADDY_VOLUME=/opt/seafile-caddy
SEADOC_VOLUME=/opt/seadoc-data

SEAFILE_SERVER_HOSTNAME=seafile.example.com
SEAFILE_SERVER_PROTOCOL=https
TIME_ZONE=Etc/UTC
JWT_PRIVATE_KEY=your_generated_jwt_key_here

SEAFILE_MYSQL_DB_HOST=db
SEAFILE_MYSQL_DB_USER=seafile
SEAFILE_MYSQL_DB_PASSWORD=change_this_db_password
SEAFILE_MYSQL_DB_CCNET_DB_NAME=ccnet_db
SEAFILE_MYSQL_DB_SEAFILE_DB_NAME=seafile_db
SEAFILE_MYSQL_DB_SEAHUB_DB_NAME=seahub_db

CACHE_PROVIDER=redis
REDIS_HOST=redis
REDIS_PORT=6379

INIT_SEAFILE_MYSQL_ROOT_PASSWORD=change_this_root_password
[email protected]
INIT_SEAFILE_ADMIN_PASSWORD=change_this_admin_password

ENABLE_SEADOC=true

Three values are critical: SEAFILE_SERVER_HOSTNAME must match your domain (Caddy uses it for SSL certificate requests), JWT_PRIVATE_KEY must be the value you generated, and all passwords should be strong. The INIT_* variables are only used on the first startup to create the database and admin account.

Docker Compose Files

Create three compose files. The main server file, seafile-server.yml:

services:
  db:
    image: ${SEAFILE_DB_IMAGE:-mariadb:10.11}
    container_name: seafile-mysql
    restart: unless-stopped
    environment:
      - MYSQL_ROOT_PASSWORD=${INIT_SEAFILE_MYSQL_ROOT_PASSWORD:-}
      - MYSQL_LOG_CONSOLE=true
      - MARIADB_AUTO_UPGRADE=1
    volumes:
      - "${SEAFILE_MYSQL_VOLUME}:/var/lib/mysql"
    networks:
      - seafile-net
    healthcheck:
      test: ["CMD", "/usr/local/bin/healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 20s
      start_period: 30s
      retries: 10

  redis:
    image: ${SEAFILE_REDIS_IMAGE:-redis}
    container_name: seafile-redis
    restart: unless-stopped
    networks:
      - seafile-net

  seafile:
    image: ${SEAFILE_IMAGE:-seafileltd/seafile-mc:13.0-latest}
    container_name: seafile
    restart: unless-stopped
    volumes:
      - ${SEAFILE_VOLUME}:/shared
    environment:
      - SEAFILE_MYSQL_DB_HOST=${SEAFILE_MYSQL_DB_HOST:-db}
      - SEAFILE_MYSQL_DB_USER=${SEAFILE_MYSQL_DB_USER:-seafile}
      - SEAFILE_MYSQL_DB_PASSWORD=${SEAFILE_MYSQL_DB_PASSWORD}
      - INIT_SEAFILE_MYSQL_ROOT_PASSWORD=${INIT_SEAFILE_MYSQL_ROOT_PASSWORD:-}
      - SEAFILE_MYSQL_DB_CCNET_DB_NAME=${SEAFILE_MYSQL_DB_CCNET_DB_NAME:-ccnet_db}
      - SEAFILE_MYSQL_DB_SEAFILE_DB_NAME=${SEAFILE_MYSQL_DB_SEAFILE_DB_NAME:-seafile_db}
      - SEAFILE_MYSQL_DB_SEAHUB_DB_NAME=${SEAFILE_MYSQL_DB_SEAHUB_DB_NAME:-seahub_db}
      - TIME_ZONE=${TIME_ZONE:-Etc/UTC}
      - INIT_SEAFILE_ADMIN_EMAIL=${INIT_SEAFILE_ADMIN_EMAIL:[email protected]}
      - INIT_SEAFILE_ADMIN_PASSWORD=${INIT_SEAFILE_ADMIN_PASSWORD:-asecret}
      - SEAFILE_SERVER_HOSTNAME=${SEAFILE_SERVER_HOSTNAME}
      - SEAFILE_SERVER_PROTOCOL=${SEAFILE_SERVER_PROTOCOL:-http}
      - JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY}
      - ENABLE_SEADOC=${ENABLE_SEADOC:-false}
      - SEADOC_SERVER_URL=${SEAFILE_SERVER_PROTOCOL}://${SEAFILE_SERVER_HOSTNAME}/sdoc-server
      - CACHE_PROVIDER=${CACHE_PROVIDER:-redis}
      - REDIS_HOST=${REDIS_HOST:-redis}
      - REDIS_PORT=${REDIS_PORT:-6379}
    labels:
      caddy: ${SEAFILE_SERVER_PROTOCOL}://${SEAFILE_SERVER_HOSTNAME}
      caddy.reverse_proxy: "{{upstreams 80}}"
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:80 || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    networks:
      - seafile-net

networks:
  seafile-net:
    name: seafile-net

The Caddy reverse proxy file, caddy.yml:

services:
  caddy:
    image: ${SEAFILE_CADDY_IMAGE:-lucaslorentz/caddy-docker-proxy:2.12-alpine}
    restart: unless-stopped
    container_name: seafile-caddy
    ports:
      - 80:80
      - 443:443
    environment:
      - CADDY_INGRESS_NETWORKS=seafile-net
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ${SEAFILE_CADDY_VOLUME}:/data/caddy
    networks:
      - seafile-net

networks:
  seafile-net:
    name: seafile-net

The SeaDoc collaborative editor, seadoc.yml:

services:
  seadoc:
    image: ${SEADOC_IMAGE:-seafileltd/sdoc-server:2.0-latest}
    container_name: seadoc
    restart: unless-stopped
    volumes:
      - ${SEADOC_VOLUME}:/shared
    environment:
      - DB_HOST=${SEAFILE_MYSQL_DB_HOST:-db}
      - DB_USER=${SEAFILE_MYSQL_DB_USER:-seafile}
      - DB_PASSWORD=${SEAFILE_MYSQL_DB_PASSWORD}
      - DB_NAME=${SEAFILE_MYSQL_DB_SEAHUB_DB_NAME:-seahub_db}
      - TIME_ZONE=${TIME_ZONE:-Etc/UTC}
      - JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY}
      - SEAHUB_SERVICE_URL=http://seafile
    labels:
      caddy: ${SEAFILE_SERVER_PROTOCOL}://${SEAFILE_SERVER_HOSTNAME}
      caddy.1_handle_path: "/socket.io/*"
      caddy.1_handle_path.0_rewrite: "* /socket.io{uri}"
      caddy.1_handle_path.1_reverse_proxy: "{{upstreams 80}}"
      caddy.2_handle_path: "/sdoc-server/*"
      caddy.2_handle_path.0_rewrite: "* {uri}"
      caddy.2_handle_path.1_reverse_proxy: "{{upstreams 80}}"
    depends_on:
      db:
        condition: service_healthy
    networks:
      - seafile-net

networks:
  seafile-net:
    name: seafile-net

Deploy Seafile

Start all services:

cd /opt/seafile
docker compose up -d

Docker pulls the images and starts the containers. The first startup takes a minute or two while MariaDB initializes the databases and Seafile creates its schema:

docker compose ps

All five containers should show as running, with seafile-mysql and seafile showing healthy:

NAME            STATUS
seadoc          Up 19 seconds
seafile         Up 19 seconds (healthy)
seafile-caddy   Up 35 seconds
seafile-mysql   Up 35 seconds (healthy)
seafile-redis   Up 35 seconds

If SEAFILE_SERVER_PROTOCOL is set to https and your domain’s DNS points to the server, Caddy automatically obtains a Let’s Encrypt certificate. Check the Caddy logs if SSL isn’t working:

docker logs seafile-caddy

Access the Web Interface

Open your domain in a browser. The Seafile 13 login page has a clean, modern design:

Seafile 13 login page with email and password fields

Log in with the admin email and password from your .env file (INIT_SEAFILE_ADMIN_EMAIL and INIT_SEAFILE_ADMIN_PASSWORD). The dashboard shows your libraries, shared files, and the sidebar navigation:

Seafile 13 dashboard showing welcome screen with libraries and file management

The admin panel at /sys/info/ confirms the version, edition, and system statistics:

Seafile 13.0.19 admin panel showing Community Edition system info with libraries, users, and storage stats

Manage the Deployment

View logs from all services:

docker compose logs -f --tail 50

View logs from a specific service:

docker compose logs seafile --tail 100

Stop all services:

docker compose down

Stop and remove all data (databases, files, certificates):

docker compose down -v

Reset the admin password if you forget it:

docker exec -it seafile /opt/seafile/seafile-server-latest/reset-admin.sh

Update Seafile

To update to a newer Seafile version, change the image tag in .env and recreate the containers:

cd /opt/seafile
docker compose pull
docker compose up -d

Docker pulls the new images and recreates only the containers that changed. Volumes persist across updates, so your files and database remain intact.

Troubleshooting

Caddy fails to obtain SSL certificate

Make sure your domain’s DNS A record points to the server’s public IP, and ports 80 and 443 are open. Caddy needs both ports for the ACME HTTP-01 challenge. Check the Caddy container logs for the exact error:

docker logs seafile-caddy 2>&1 | grep -i "error\|certificate"

Seafile container keeps restarting

Check if MariaDB is healthy first. Seafile depends on a healthy database before starting:

docker logs seafile-mysql 2>&1 | tail -20
docker logs seafile 2>&1 | tail -30

Common causes: wrong database password in .env, missing JWT_PRIVATE_KEY, or the database not yet initialized on first startup.

Blank page or “Page unavailable” after login

This typically means the internal Nginx proxy inside the Seafile container needs a reload. Restart the container:

docker restart seafile

If the issue persists, check that SEAFILE_SERVER_HOSTNAME in .env matches the domain you are accessing. A hostname mismatch causes Caddy to return empty responses.

Related Articles

CentOS Understanding and Working With BtrFS Filesystem in Linux Docker Install Outline Wiki with Docker on Ubuntu Monitoring Install Zabbix Server 7.0 LTS on Ubuntu 24.04 with PostgreSQL and Nginx Openstack How To resize or extend Cinder Volume in OpenStack

8 thoughts on “Install Seafile Server on Ubuntu 24.04 / 22.04 with Docker”

  1. Hello
    Thank you for the tutorial, I am at the end of the tutorial, Seafile works in my browser, but cannot add a file.
    I can add users, create libraries.
    Can you help me ?
    Thanks in advance.

    Reply
  2. Friend, thank you for the tutorial.

    Just an issue: in systemd configuration, the path to seafile.sh and seahub.sh are wrong. The folder is not “/srv/seafile-server-latest/”, , but “/srv/seafile/”

    Reply

Leave a Comment

Press ESC to close