Docker Install Seafile
1. Project Setup
Seafile is deployed in docker with integration of SeaDoc and OnlyOffice.
.
├── caddy.yml
├── .env
├── onlyoffice.yml
├── opt
│ ├── onlyoffice
│ ├── seafile-caddy
│ ├── seafile-data
│ └── seafile-mysql
├── seadoc.yml
└── seafile-server.yml
Folder Structure
- Seafile Server: main server with Nginx as web server and MySQL as database.
- Caddy is the reverse proxy.
- Seadoc is the Wiki component.
- OnlyOffice is the document server.
- Opt folder stores all the persistent files for the 4 components.
- .env stores the variables for different yml files.
2. Configs
COMPOSE_FILE='seafile-server.yml,caddy.yml,seadoc.yml,onlyoffice.yml'
COMPOSE_PATH_SEPARATOR=','
SEAFILE_IMAGE=seafileltd/seafile-mc:12.0-latest
SEAFILE_DB_IMAGE=mariadb:10.11
SEAFILE_MEMCACHED_IMAGE=memcached:1.6.29
SEAFILE_CADDY_IMAGE=lucaslorentz/caddy-docker-proxy:2.9-alpine
SEAFILE_VOLUME=./opt/seafile-data
SEAFILE_MYSQL_VOLUME=./opt/seafile-mysql/db
SEAFILE_CADDY_VOLUME=./opt/seafile-caddy
SEAFILE_MYSQL_DB_HOST=db
INIT_SEAFILE_MYSQL_ROOT_PASSWORD=ROOT_PASSWORD
SEAFILE_MYSQL_DB_USER=seafile
SEAFILE_MYSQL_DB_PASSWORD=PASSWORD
TIME_ZONE=Asia/Shanghai
JWT_PRIVATE_KEY=BdWciKsfuUT7fsxGN04N0pfxA6THpOqV2ShtFJzr
SEAFILE_SERVER_HOSTNAME=10.124.159.18
SEAFILE_SERVER_PROTOCOL=http
INIT_SEAFILE_ADMIN_EMAIL=me@example.com
INIT_SEAFILE_ADMIN_PASSWORD=asecret2025
SEADOC_IMAGE=seafileltd/sdoc-server:1.0-latest
SEADOC_VOLUME=/opt/seadoc-data
ENABLE_SEADOC=true
NOTIFICATION_SERVER_IMAGE=seafileltd/notification-server:12.0-latest
NOTIFICATION_SERVER_VOLUME=/opt/notification-data
# OnlyOffice image
ONLYOFFICE_IMAGE=onlyoffice/documentserver:8.1.0.1
# Persistent storage directory of OnlyOffice
ONLYOFFICE_VOLUME=./opt/onlyoffice
# OnlyOffice document server port
ONLYOFFICE_PORT=6233
# jwt secret, generated by `pwgen -s 40 1`
ONLYOFFICE_JWT_SECRET=BdWciKsfuUT7fsxGN04N0pfxA6THpOqV2ShtFJzr
services:
db:
image: ${SEAFILE_DB_IMAGE:-mariadb:10.11}
container_name: seafile-mysql
environment:
- MYSQL_ROOT_PASSWORD=${INIT_SEAFILE_MYSQL_ROOT_PASSWORD:-}
- MYSQL_LOG_CONSOLE=true
- MARIADB_AUTO_UPGRADE=1
volumes:
- "${SEAFILE_MYSQL_VOLUME:-/opt/seafile-mysql/db}:/var/lib/mysql"
networks:
- seafile-net
healthcheck:
test:
[
"CMD",
"/usr/local/bin/healthcheck.sh",
"--connect",
"--mariadbupgrade",
"--innodb_initialized",
]
interval: 20s
start_period: 30s
timeout: 5s
retries: 10
memcached:
image: ${SEAFILE_MEMCACHED_IMAGE:-memcached:1.6.29}
container_name: seafile-memcached
entrypoint: memcached -m 256
networks:
- seafile-net
seafile:
image: ${SEAFILE_IMAGE:-seafileltd/seafile-mc:12.0-latest}
container_name: seafile
# ports:
# - "80:80"
volumes:
- ${SEAFILE_VOLUME:-/opt/seafile-data}:/shared
environment:
- DB_HOST=${SEAFILE_MYSQL_DB_HOST:-db}
- DB_PORT=${SEAFILE_MYSQL_DB_PORT:-3306}
- DB_USER=${SEAFILE_MYSQL_DB_USER:-seafile}
- DB_ROOT_PASSWD=${INIT_SEAFILE_MYSQL_ROOT_PASSWORD:-}
- DB_PASSWORD=${SEAFILE_MYSQL_DB_PASSWORD:?Variable is not set or empty}
- 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:-me@example.com}
- INIT_SEAFILE_ADMIN_PASSWORD=${INIT_SEAFILE_ADMIN_PASSWORD:-asecret}
- SEAFILE_SERVER_HOSTNAME=${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty}
- SEAFILE_SERVER_PROTOCOL=${SEAFILE_SERVER_PROTOCOL:-http}
- SITE_ROOT=${SITE_ROOT:-/}
- NON_ROOT=${NON_ROOT:-false}
- JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY:?Variable is not set or empty}
- SEAFILE_LOG_TO_STDOUT=${SEAFILE_LOG_TO_STDOUT:-false}
- ENABLE_SEADOC=${ENABLE_SEADOC:-true}
- SEADOC_SERVER_URL=${SEAFILE_SERVER_PROTOCOL:-http}://${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty}/sdoc-server
labels:
caddy: ${SEAFILE_SERVER_PROTOCOL:-http}://${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty}
caddy.reverse_proxy: "{{upstreams 80}}"
depends_on:
db:
condition: service_healthy
memcached:
condition: service_started
networks:
- seafile-net
networks:
seafile-net:
name: seafile-net
services:
caddy:
image: ${SEAFILE_CADDY_IMAGE:-lucaslorentz/caddy-docker-proxy:2.9-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:-/opt/seafile-caddy}:/data/caddy
networks:
- seafile-net
healthcheck:
test: ["CMD-SHELL", "curl --fail http://localhost:2019/metrics || exit 1"]
start_period: 20s
interval: 20s
timeout: 5s
retries: 3
networks:
seafile-net:
name: seafile-net
services:
seadoc:
image: ${SEADOC_IMAGE:-seafileltd/sdoc-server:1.0-latest}
container_name: seadoc
volumes:
- ${SEADOC_VOLUME:-/opt/seadoc-data/}:/shared
# ports:
# - "80:80"
environment:
- DB_HOST=${SEAFILE_MYSQL_DB_HOST:-db}
- DB_PORT=${SEAFILE_MYSQL_DB_PORT:-3306}
- DB_USER=${SEAFILE_MYSQL_DB_USER:-seafile}
- DB_PASSWORD=${SEAFILE_MYSQL_DB_PASSWORD:?Variable is not set or empty}
- DB_NAME=${SEADOC_MYSQL_DB_NAME:-seahub_db}
- TIME_ZONE=${TIME_ZONE:-Etc/UTC}
- JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY:?Variable is not set or empty}
- NON_ROOT=${NON_ROOT:-false}
- SEAHUB_SERVICE_URL=${SEAFILE_SERVER_PROTOCOL:-http}://${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty}
labels:
caddy: ${SEAFILE_SERVER_PROTOCOL:-http}://${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty}
caddy.@ws.0_header: "Connection *Upgrade*"
caddy.@ws.1_header: "Upgrade websocket"
caddy.0_reverse_proxy: "@ws {{upstreams 80}}"
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
---
services:
caddy:
ports:
- ${ONLYOFFICE_PORT:-6233}:${ONLYOFFICE_PORT:-6233}
onlyoffice:
image: ${ONLYOFFICE_IMAGE:-onlyoffice/documentserver:8.1.0.1}
restart: unless-stopped
container_name: seafile-onlyoffice
environment:
# old environment config from .venv
# - DB_TYPE=${DB_TYPE:-mariadb}
# - DB_HOST=${SEAFILE_MYSQL_DB_HOST:-db}
# - DB_USER=${SEAFILE_MYSQL_DB_USER:-seafile}
# - DB_PWD=${SEAFILE_MYSQL_DB_PASSWORD:?Variable is not set or empty}
# - JWT_ENABLED=true
# - JWT_SECRET=${ONLYOFFICE_JWT_SECRET:?Variable is not set or empty}
# new environment config after creating new db, username and password in mysql.
- DB_TYPE=mariadb
- DB_HOST=db
- DB_NAME=onlyoffice
- DB_USER=onlyoffice
- DB_PWD=onlyofficepass
- JWT_ENABLED=true
- JWT_SECRET=${ONLYOFFICE_JWT_SECRET:?Variable is not set or empty}
volumes:
- ${ONLYOFFICE_VOLUME:-./opt/onlyoffice}/logs:/var/log/onlyoffice
- ${ONLYOFFICE_VOLUME:-./opt/onlyoffice}/data:/var/www/onlyoffice/Data
- ${ONLYOFFICE_VOLUME:-./opt/onlyoffice}/lib:/var/lib/onlyoffice
labels:
caddy: ${SEAFILE_SERVER_PROTOCOL:-http}://${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty}:${ONLYOFFICE_PORT:-6233}
caddy.reverse_proxy: "{{upstreams}}"
networks:
- seafile-net
networks:
seafile-net:
name: seafile-net
OnlyOffice configs needs to be added to Seafile server settings at opt/seafile-data/seafile/conf/seahub_settings.py
.
# -*- coding: utf-8 -*-
SECRET_KEY = "m_lxv&xre6kt4o+ss3)b1=q*tsl3ua3r7xe+%hxes%@952tezb"
SERVICE_URL = "http://10.124.159.18"
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'seahub_db',
'USER': 'seafile',
'PASSWORD': 'PASSWORD',
'HOST': 'db',
'PORT': '3306',
'OPTIONS': {'charset': 'utf8mb4'},
}
}
CACHES = {
'default': {
'BACKEND': 'django_pylibmc.memcached.PyLibMCCache',
'LOCATION': 'memcached:11211',
},
'locmem': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
},
}
COMPRESS_CACHE_BACKEND = 'locmem'
TIME_ZONE = 'Asia/Shanghai'
FILE_SERVER_ROOT = 'http://10.124.159.18/seafhttp'
ENABLE_ONLYOFFICE = True
ONLYOFFICE_APIJS_URL = 'http://10.124.159.18:6233/web-apps/apps/api/documents/api.js'
ONLYOFFICE_FILE_SERVER_ROOT = 'http://10.124.159.18:6233/'
ONLYOFFICE_FILE_EXTENSION = ('doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'odt', 'fodt', 'odp', 'fodp', 'ods', 'fods', 'csv', 'ppsx', 'pps')
ONLYOFFICE_EDIT_FILE_EXTENSION = ('docx', 'pptx', 'xlsx')
ONLYOFFICE_JWT_SECRET = 'BdWciKsfuUT7fsxGN04N0pfxA6THpOqV2ShtFJzr'
3. Troubleshoot
3.1 Database Issue
seafile-mysql | 2025-04-30 6:55:16 0 [Warning] You need to use --log-bin to make --expire-logs-days or --binlog-expire-logs-seconds work.
seafile-mysql | 2025-04-30 6:55:16 0 [Note] Server socket created on IP: '0.0.0.0'.
seafile-mysql | 2025-04-30 6:55:16 0 [Note] Server socket created on IP: '::'.
seafile-mysql | 2025-04-30 6:55:16 0 [Note] mariadbd: ready for connections.
seafile-mysql | Version: '10.11.10-MariaDB-ubu2204' socket: '/run/mysqld/mysqld.sock' port: 3306 mariadb.org binary distribution
seafile-mysql | 2025-04-30 6:55:16 0 [Note] InnoDB: Buffer pool(s) load completed at 250430 6:55:16
seafile-mysql | 2025-04-30 6:55:18 3 [Warning] Aborted connection 3 to db: 'unconnected' user: 'unauthenticated' host: '172.23.0.3' (This connection closed normally without authentication)
seafile-mysql | 2025-04-30 6:55:18 5 [Warning] Access denied for user 'seafile'@'%' to database 'onlyoffice'
seafile-mysql | 2025-04-30 6:55:33 8 [Warning] Aborted connection 8 to db: 'unconnected' user: 'unauthenticated' host: '172.23.0.3' (This connection closed normally without authentication)
seafile-mysql | 2025-04-30 6:55:41 11 [Warning] Access denied for user 'seafile'@'%' to database 'onlyoffice'
seafile-onlyoffice | Generating presentation themes, please wait...Done
seafile-onlyoffice | Generating js caches, please wait...Done
seafile-onlyoffice | ds:docservice: stopped
seafile-onlyoffice | ds:docservice: started
seafile-mysql | 2025-04-30 6:56:59 51 [Warning] Access denied for user 'seafile'@'%' to database 'onlyoffice'
This indicates user seafile
can’t access database onlyoffice
. However, in MySQL there is no database onlyoffice
.
The onlyoffice/documentserver image expects its own database, typically called onlyoffice, and it does not use Seafile’s seafile database user.
##### Go into MySQL container #####
docker exec -it seafile-mysql mysql -uroot -p
##### Add onlyoffice user and only office database #####
CREATE DATABASE onlyoffice;
CREATE USER 'onlyoffice'@'%' IDENTIFIED BY 'onlyofficepass';
GRANT ALL PRIVILEGES ON onlyoffice.* TO 'onlyoffice'@'%';
FLUSH PRIVILEGES;
##### Change the DB environment for ONLYOFFICE in onlyoffice.yml #####
environment:
- DB_TYPE=mariadb
- DB_HOST=db
- DB_NAME=onlyoffice
- DB_USER=onlyoffice
- DB_PWD=onlyofficepass
- JWT_ENABLED=true
- JWT_SECRET=${ONLYOFFICE_JWT_SECRET:?Variable is not set or empty}
##### Restart OnlyOffice container #####
docker compose -f onlyoffice.yml down
docker compose -f onlyoffice.yml up -d
3.2 OnlyOffice Document Server Issue
seafile-onlyoffice | 2025/04/30 06:46:22 [error] 8955#8955: *97 connect() failed (111: Unknown error) while connecting to upstream, client: 172.22.0.4, server: , request: "GET /8.1.0-169/doc/3c60f0640004930ae2a0/c/?shardkey=3c60f0640004930ae2a0&EIO=4&transport=polling&t=PQ5Sax0 HTTP/1.1", upstream: "http://127.0.0.1:8000/doc/3c60f0640004930ae2a0/c/?shardkey=3c60f0640004930ae2a0&EIO=4&transport=polling&t=PQ5Sax0", host: "10.124.159.18:6233", referrer: "http://10.124.159.18:6233/8.1.0-169/web-apps/apps/spreadsheeteditor/main/index.html?_dc=8.1.0-169&lang=en&customer=ONLYOFFICE&type=desktop&frameEditorId=placeholder&isForm=false&parentOrigin=http://10.124.159.18&fileType=xlsx"
ONLYOFFICE Document Server is not running inside the same container – the 127.0.0.1
address refers to localhost within the seafile-onlyoffice
container.
- ONLYOFFICE is a standalone service on its own.
- It runs the document server itself.
- Seafile communicates with it over the network, not via localhost inside the same container.
This issue typically arises when Seafile is misconfigured to use http://127.0.0.1:8000
as the ONLYOFFICE integration endpoint.
You must set the correct ONLYOFFICE integration URL in Seafile so it talks to the correct container via Docker network or external URL.
# add the following to 'opt/seafile-data/seafile/conf/seahub_settings.py'
ONLYOFFICE_FILE_SERVER_ROOT = 'http://10.124.159.18:6233/'
# restart seafile server
docker compose -f seafile-server.yml restart seafile