From 41d53e45ebefa99c5c73f93567b129b7fd17f3ca Mon Sep 17 00:00:00 2001 From: Travis Vasceannie Date: Sun, 21 Dec 2025 16:51:12 -0500 Subject: [PATCH] Add Docker Compose and environment configuration files for Seafile stack --- docker-compose.yml | 186 ++++++++++++++++++++++++++ originals/.env | 128 ++++++++++++++++++ caddy.yml => originals/caddy.yml | 0 originals/elasticsearch.yml | 23 ++++ originals/seadoc.yml | 40 ++++++ originals/seafile-server.yml | 113 ++++++++++++++++ stack.env | 128 ++++++++++++++++++ swarm-compose.yml | 223 +++++++++++++++++++++++++++++++ 8 files changed, 841 insertions(+) create mode 100644 docker-compose.yml create mode 100644 originals/.env rename caddy.yml => originals/caddy.yml (100%) create mode 100644 originals/elasticsearch.yml create mode 100644 originals/seadoc.yml create mode 100644 originals/seafile-server.yml create mode 100644 stack.env create mode 100644 swarm-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..3ffbea4 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,186 @@ +version: "3.8" + +services: + caddy: + image: ${SEAFILE_CADDY_IMAGE:-lucaslorentz/caddy-docker-proxy:2.9-alpine} + container_name: seafile-caddy + restart: unless-stopped + 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 + + elasticsearch: + image: ${SEAFILE_ELASTICSEARCH_IMAGE:-elasticsearch:8.15.0} + container_name: seafile-elasticsearch + restart: unless-stopped + environment: + - discovery.type=single-node + - bootstrap.memory_lock=true + - "ES_JAVA_OPTS=-Xms2g -Xmx2g" + - "xpack.security.enabled=false" + ulimits: + memlock: + soft: -1 + hard: -1 + mem_limit: 4g + volumes: + - "${SEAFILE_ELASTICSEARCH_VOLUME:-/opt/seafile-elasticsearch/data}:/usr/share/elasticsearch/data" + networks: + - seafile-net + + 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:-/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 + + redis: + image: ${SEAFILE_REDIS_IMAGE:-redis} + container_name: seafile-redis + restart: unless-stopped + command: + - /bin/sh + - -c + - redis-server --requirepass "$$REDIS_PASSWORD" + environment: + - REDIS_PASSWORD=${REDIS_PASSWORD:-} + networks: + - seafile-net + + seafile: + image: ${SEAFILE_IMAGE:-seafileltd/seafile-pro-mc:13.0-latest} + container_name: seafile + restart: unless-stopped + volumes: + - ${SEAFILE_VOLUME:-/opt/seafile-data}:/shared + environment: + - INIT_SEAFILE_MYSQL_ROOT_PASSWORD=${INIT_SEAFILE_MYSQL_ROOT_PASSWORD:-} + - SEAFILE_MYSQL_DB_HOST=${SEAFILE_MYSQL_DB_HOST:-db} + - SEAFILE_MYSQL_DB_PORT=${SEAFILE_MYSQL_DB_PORT:-3306} + - SEAFILE_MYSQL_DB_USER=${SEAFILE_MYSQL_DB_USER:-seafile} + - SEAFILE_MYSQL_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 + - CACHE_PROVIDER=${CACHE_PROVIDER:-redis} + - REDIS_HOST=${REDIS_HOST:-redis} + - REDIS_PORT=${REDIS_PORT:-6379} + - REDIS_PASSWORD=${REDIS_PASSWORD:-} + - MEMCACHED_HOST=${MEMCACHED_HOST:-memcached} + - MEMCACHED_PORT=${MEMCACHED_PORT:-11211} + - SEAF_SERVER_STORAGE_TYPE=${SEAF_SERVER_STORAGE_TYPE:-} + - S3_COMMIT_BUCKET=${S3_COMMIT_BUCKET:-} + - S3_FS_BUCKET=${S3_FS_BUCKET:-} + - S3_BLOCK_BUCKET=${S3_BLOCK_BUCKET:-} + - S3_KEY_ID=${S3_KEY_ID:-} + - S3_SECRET_KEY=${S3_SECRET_KEY:-} + - S3_USE_V4_SIGNATURE=${S3_USE_V4_SIGNATURE:-true} + - S3_AWS_REGION=${S3_AWS_REGION:-us-east-1} + - S3_HOST=${S3_HOST:-} + - S3_USE_HTTPS=${S3_USE_HTTPS:-true} + - S3_PATH_STYLE_REQUEST=${S3_PATH_STYLE_REQUEST:-false} + - S3_SSE_C_KEY=${S3_SSE_C_KEY:-} + - ENABLE_NOTIFICATION_SERVER=${ENABLE_NOTIFICATION_SERVER:-false} + - INNER_NOTIFICATION_SERVER_URL=${INNER_NOTIFICATION_SERVER_URL:-http://notification-server:8083} + - NOTIFICATION_SERVER_URL=${NOTIFICATION_SERVER_URL:-${SEAFILE_SERVER_PROTOCOL:-http}://${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty}/notification} + - ENABLE_SEAFILE_AI=${ENABLE_SEAFILE_AI:-false} + - SEAFILE_AI_SERVER_URL=${SEAFILE_AI_SERVER_URL:-http://seafile-ai:8888} + - SEAFILE_AI_SECRET_KEY=${JWT_PRIVATE_KEY:?Variable is not set or empty} + - MD_FILE_COUNT_LIMIT=${MD_FILE_COUNT_LIMIT:-100000} + labels: + caddy: ${SEAFILE_SERVER_PROTOCOL:-http}://${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty} + caddy.reverse_proxy: "{{upstreams 80}}" + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:80 || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + depends_on: + db: + condition: service_healthy + redis: + condition: service_started + networks: + - seafile-net + + seadoc: + image: ${SEADOC_IMAGE:-seafileltd/sdoc-server:2.0-latest} + container_name: seadoc + restart: unless-stopped + volumes: + - ${SEADOC_VOLUME:-/opt/seadoc-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_PASSWORD=${SEAFILE_MYSQL_DB_PASSWORD:?Variable is not set or empty} + - DB_NAME=${SEADOC_MYSQL_DB_NAME:-${SEAFILE_MYSQL_DB_SEAHUB_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_SERVICE_URL:-http://seafile} + 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 diff --git a/originals/.env b/originals/.env new file mode 100644 index 0000000..6e3059d --- /dev/null +++ b/originals/.env @@ -0,0 +1,128 @@ +################################# +# Docker compose configurations # +################################# +COMPOSE_FILE='seafile-server.yml,caddy.yml,seadoc.yml,elasticsearch.yml' +COMPOSE_PATH_SEPARATOR=',' + +## Images +SEAFILE_IMAGE=seafileltd/seafile-pro-mc:13.0-latest +SEAFILE_DB_IMAGE=mariadb:10.11 +SEAFILE_REDIS_IMAGE=redis +SEAFILE_ELASTICSEARCH_IMAGE=elasticsearch:8.15.0 +SEAFILE_CADDY_IMAGE=lucaslorentz/caddy-docker-proxy:2.9-alpine +SEADOC_IMAGE=seafileltd/sdoc-server:2.0-latest +NOTIFICATION_SERVER_IMAGE=seafileltd/notification-server:13.0-latest +#SEASEARCH_IMAGE=seafileltd/seasearch-nomkl:1.0-latest # Apple's Chip for SeaSearch +SEASEARCH_IMAGE=seafileltd/seasearch:1.0-latest +MD_IMAGE=seafileltd/seafile-md-server:13.0-latest + +## Storage + +### Storage type +SEAF_SERVER_STORAGE_TYPE=disk # disk, s3, multiple +MD_STORAGE_TYPE=$SEAF_SERVER_STORAGE_TYPE # disk, s3 +SS_STORAGE_TYPE=$SEAF_SERVER_STORAGE_TYPE # disk, s3 + +### Local storage path +BASIC_STORAGE_PATH=/opt +SEAFILE_VOLUME=$BASIC_STORAGE_PATH/seafile-data +SEAFILE_MYSQL_VOLUME=$BASIC_STORAGE_PATH/seafile-mysql/db +SEAFILE_ELASTICSEARCH_VOLUME=$BASIC_STORAGE_PATH/seafile-elasticsearch/data +SEAFILE_CADDY_VOLUME=$BASIC_STORAGE_PATH/seafile-caddy +SS_DATA_PATH=$BASIC_STORAGE_PATH/seasearch-data +SEADOC_VOLUME=$BASIC_STORAGE_PATH/seadoc-data + +### Storage configurations for S3 (only valid in XXX_STORAGE_TYPE=s3) +S3_COMMIT_BUCKET= +S3_FS_BUCKET= +S3_BLOCK_BUCKET= +S3_SS_BUCKET= # for seasearch +S3_MD_BUCKET= # for metadata-server +S3_KEY_ID= +S3_SECRET_KEY= +S3_USE_V4_SIGNATURE=true +S3_PATH_STYLE_REQUEST=false +S3_AWS_REGION=us-east-1 +S3_HOST= +S3_USE_HTTPS=true +S3_SSE_C_KEY= + +################################# +# Startup parameters # +################################# +SEAFILE_SERVER_HOSTNAME=seafile.example.com +SEAFILE_SERVER_PROTOCOL=http +TIME_ZONE=Etc/UTC +JWT_PRIVATE_KEY= + +##################################### +# Third-party service configuration # +##################################### + +## Database +SEAFILE_MYSQL_DB_HOST=db +SEAFILE_MYSQL_DB_USER=seafile +SEAFILE_MYSQL_DB_PASSWORD=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 +CACHE_PROVIDER=redis # options: redis (recommend), memcached + +### Redis +REDIS_HOST=redis +REDIS_PORT=6379 +REDIS_PASSWORD= + +### Memcached +MEMCACHED_HOST=memcached +MEMCACHED_PORT=11211 + +###################################### +# Initial variables # +# (Only valid in first-time startup) # +###################################### + +## Database root password, Used to create Seafile users +INIT_SEAFILE_MYSQL_ROOT_PASSWORD=ROOT_PASSWORD + +## Seafile admin user +INIT_SEAFILE_ADMIN_EMAIL=me@example.com +INIT_SEAFILE_ADMIN_PASSWORD=asecret + +## SeaSearch admin user +## (valid in enabling SeaSearch and use Seafile admin by default) +INIT_SS_ADMIN_USER=$INIT_SEAFILE_ADMIN_EMAIL +INIT_SS_ADMIN_PASSWORD=$INIT_SEAFILE_ADMIN_PASSWORD + +############################################ +# Additional configurations for extensions # +############################################ + +## SeaDoc service +ENABLE_SEADOC=true + +## SeaSearch + +### Local cache +SS_MAX_OBJ_CACHE_SIZE=10GB + +### Log +SS_LOG_TO_STDOUT=false +SS_LOG_OUTPUT=true +SS_LOG_LEVEL=info + +## Notification +ENABLE_NOTIFICATION_SERVER=false +NOTIFICATION_SERVER_URL= + +## Seafile AI +ENABLE_SEAFILE_AI=false +SEAFILE_AI_LLM_TYPE=openai +SEAFILE_AI_LLM_URL= +SEAFILE_AI_LLM_KEY= # your llm key +SEAFILE_AI_LLM_MODEL=gpt-4o-mini + +## Metadata server +MD_FILE_COUNT_LIMIT=100000 diff --git a/caddy.yml b/originals/caddy.yml similarity index 100% rename from caddy.yml rename to originals/caddy.yml diff --git a/originals/elasticsearch.yml b/originals/elasticsearch.yml new file mode 100644 index 0000000..5c1ac50 --- /dev/null +++ b/originals/elasticsearch.yml @@ -0,0 +1,23 @@ +services: + elasticsearch: + image: ${SEAFILE_ELASTICSEARCH_IMAGE:-elasticsearch:8.15.0} + container_name: seafile-elasticsearch + restart: unless-stopped + environment: + - discovery.type=single-node + - bootstrap.memory_lock=true + - "ES_JAVA_OPTS=-Xms2g -Xmx2g" + - "xpack.security.enabled=false" + ulimits: + memlock: + soft: -1 + hard: -1 + mem_limit: 4g + volumes: + - "${SEAFILE_ELASTICSEARCH_VOLUME:-/opt/seafile-elasticsearch/data}:/usr/share/elasticsearch/data" + networks: + - seafile-net + +networks: + seafile-net: + name: seafile-net diff --git a/originals/seadoc.yml b/originals/seadoc.yml new file mode 100644 index 0000000..c261cf8 --- /dev/null +++ b/originals/seadoc.yml @@ -0,0 +1,40 @@ +services: + + seadoc: + image: ${SEADOC_IMAGE:-seafileltd/sdoc-server:2.0-latest} + container_name: seadoc + restart: unless-stopped + 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:-${SEAFILE_MYSQL_DB_SEAHUB_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_SERVICE_URL:-http://seafile} + 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 diff --git a/originals/seafile-server.yml b/originals/seafile-server.yml new file mode 100644 index 0000000..b574a52 --- /dev/null +++ b/originals/seafile-server.yml @@ -0,0 +1,113 @@ +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:-/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 + + redis: + image: ${SEAFILE_REDIS_IMAGE:-redis} + container_name: seafile-redis + restart: unless-stopped + command: + - /bin/sh + - -c + - redis-server --requirepass "$$REDIS_PASSWORD" + environment: + - REDIS_PASSWORD=${REDIS_PASSWORD:-} + networks: + - seafile-net + + seafile: + image: ${SEAFILE_IMAGE:-seafileltd/seafile-pro-mc:13.0-latest} + container_name: seafile + restart: unless-stopped + # ports: + # - "80:80" + volumes: + - ${SEAFILE_VOLUME:-/opt/seafile-data}:/shared + environment: + - INIT_SEAFILE_MYSQL_ROOT_PASSWORD=${INIT_SEAFILE_MYSQL_ROOT_PASSWORD:-} + - SEAFILE_MYSQL_DB_HOST=${SEAFILE_MYSQL_DB_HOST:-db} + - SEAFILE_MYSQL_DB_PORT=${SEAFILE_MYSQL_DB_PORT:-3306} + - SEAFILE_MYSQL_DB_USER=${SEAFILE_MYSQL_DB_USER:-seafile} + - SEAFILE_MYSQL_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 + - CACHE_PROVIDER=${CACHE_PROVIDER:-redis} + - REDIS_HOST=${REDIS_HOST:-redis} + - REDIS_PORT=${REDIS_PORT:-6379} + - REDIS_PASSWORD=${REDIS_PASSWORD:-} + - MEMCACHED_HOST=${MEMCACHED_HOST:-memcached} + - MEMCACHED_PORT=${MEMCACHED_PORT:-11211} + - SEAF_SERVER_STORAGE_TYPE=${SEAF_SERVER_STORAGE_TYPE:-} + - S3_COMMIT_BUCKET=${S3_COMMIT_BUCKET:-} + - S3_FS_BUCKET=${S3_FS_BUCKET:-} + - S3_BLOCK_BUCKET=${S3_BLOCK_BUCKET:-} + - S3_KEY_ID=${S3_KEY_ID:-} + - S3_SECRET_KEY=${S3_SECRET_KEY:-} + - S3_USE_V4_SIGNATURE=${S3_USE_V4_SIGNATURE:-true} + - S3_AWS_REGION=${S3_AWS_REGION:-us-east-1} + - S3_HOST=${S3_HOST:-} + - S3_USE_HTTPS=${S3_USE_HTTPS:-true} + - S3_PATH_STYLE_REQUEST=${S3_PATH_STYLE_REQUEST:-false} + - S3_SSE_C_KEY=${S3_SSE_C_KEY:-} + - ENABLE_NOTIFICATION_SERVER=${ENABLE_NOTIFICATION_SERVER:-false} + - INNER_NOTIFICATION_SERVER_URL=${INNER_NOTIFICATION_SERVER_URL:-http://notification-server:8083} + - NOTIFICATION_SERVER_URL=${NOTIFICATION_SERVER_URL:-${SEAFILE_SERVER_PROTOCOL:-http}://${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty}/notification} + - ENABLE_SEAFILE_AI=${ENABLE_SEAFILE_AI:-false} + - SEAFILE_AI_SERVER_URL=${SEAFILE_AI_SERVER_URL:-http://seafile-ai:8888} + - SEAFILE_AI_SECRET_KEY=${JWT_PRIVATE_KEY:?Variable is not set or empty} + - MD_FILE_COUNT_LIMIT=${MD_FILE_COUNT_LIMIT:-100000} + labels: + caddy: ${SEAFILE_SERVER_PROTOCOL:-http}://${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty} + caddy.reverse_proxy: "{{upstreams 80}}" + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:80 || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + depends_on: + db: + condition: service_healthy + redis: + condition: service_started + networks: + - seafile-net + +networks: + seafile-net: + name: seafile-net diff --git a/stack.env b/stack.env new file mode 100644 index 0000000..6e3059d --- /dev/null +++ b/stack.env @@ -0,0 +1,128 @@ +################################# +# Docker compose configurations # +################################# +COMPOSE_FILE='seafile-server.yml,caddy.yml,seadoc.yml,elasticsearch.yml' +COMPOSE_PATH_SEPARATOR=',' + +## Images +SEAFILE_IMAGE=seafileltd/seafile-pro-mc:13.0-latest +SEAFILE_DB_IMAGE=mariadb:10.11 +SEAFILE_REDIS_IMAGE=redis +SEAFILE_ELASTICSEARCH_IMAGE=elasticsearch:8.15.0 +SEAFILE_CADDY_IMAGE=lucaslorentz/caddy-docker-proxy:2.9-alpine +SEADOC_IMAGE=seafileltd/sdoc-server:2.0-latest +NOTIFICATION_SERVER_IMAGE=seafileltd/notification-server:13.0-latest +#SEASEARCH_IMAGE=seafileltd/seasearch-nomkl:1.0-latest # Apple's Chip for SeaSearch +SEASEARCH_IMAGE=seafileltd/seasearch:1.0-latest +MD_IMAGE=seafileltd/seafile-md-server:13.0-latest + +## Storage + +### Storage type +SEAF_SERVER_STORAGE_TYPE=disk # disk, s3, multiple +MD_STORAGE_TYPE=$SEAF_SERVER_STORAGE_TYPE # disk, s3 +SS_STORAGE_TYPE=$SEAF_SERVER_STORAGE_TYPE # disk, s3 + +### Local storage path +BASIC_STORAGE_PATH=/opt +SEAFILE_VOLUME=$BASIC_STORAGE_PATH/seafile-data +SEAFILE_MYSQL_VOLUME=$BASIC_STORAGE_PATH/seafile-mysql/db +SEAFILE_ELASTICSEARCH_VOLUME=$BASIC_STORAGE_PATH/seafile-elasticsearch/data +SEAFILE_CADDY_VOLUME=$BASIC_STORAGE_PATH/seafile-caddy +SS_DATA_PATH=$BASIC_STORAGE_PATH/seasearch-data +SEADOC_VOLUME=$BASIC_STORAGE_PATH/seadoc-data + +### Storage configurations for S3 (only valid in XXX_STORAGE_TYPE=s3) +S3_COMMIT_BUCKET= +S3_FS_BUCKET= +S3_BLOCK_BUCKET= +S3_SS_BUCKET= # for seasearch +S3_MD_BUCKET= # for metadata-server +S3_KEY_ID= +S3_SECRET_KEY= +S3_USE_V4_SIGNATURE=true +S3_PATH_STYLE_REQUEST=false +S3_AWS_REGION=us-east-1 +S3_HOST= +S3_USE_HTTPS=true +S3_SSE_C_KEY= + +################################# +# Startup parameters # +################################# +SEAFILE_SERVER_HOSTNAME=seafile.example.com +SEAFILE_SERVER_PROTOCOL=http +TIME_ZONE=Etc/UTC +JWT_PRIVATE_KEY= + +##################################### +# Third-party service configuration # +##################################### + +## Database +SEAFILE_MYSQL_DB_HOST=db +SEAFILE_MYSQL_DB_USER=seafile +SEAFILE_MYSQL_DB_PASSWORD=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 +CACHE_PROVIDER=redis # options: redis (recommend), memcached + +### Redis +REDIS_HOST=redis +REDIS_PORT=6379 +REDIS_PASSWORD= + +### Memcached +MEMCACHED_HOST=memcached +MEMCACHED_PORT=11211 + +###################################### +# Initial variables # +# (Only valid in first-time startup) # +###################################### + +## Database root password, Used to create Seafile users +INIT_SEAFILE_MYSQL_ROOT_PASSWORD=ROOT_PASSWORD + +## Seafile admin user +INIT_SEAFILE_ADMIN_EMAIL=me@example.com +INIT_SEAFILE_ADMIN_PASSWORD=asecret + +## SeaSearch admin user +## (valid in enabling SeaSearch and use Seafile admin by default) +INIT_SS_ADMIN_USER=$INIT_SEAFILE_ADMIN_EMAIL +INIT_SS_ADMIN_PASSWORD=$INIT_SEAFILE_ADMIN_PASSWORD + +############################################ +# Additional configurations for extensions # +############################################ + +## SeaDoc service +ENABLE_SEADOC=true + +## SeaSearch + +### Local cache +SS_MAX_OBJ_CACHE_SIZE=10GB + +### Log +SS_LOG_TO_STDOUT=false +SS_LOG_OUTPUT=true +SS_LOG_LEVEL=info + +## Notification +ENABLE_NOTIFICATION_SERVER=false +NOTIFICATION_SERVER_URL= + +## Seafile AI +ENABLE_SEAFILE_AI=false +SEAFILE_AI_LLM_TYPE=openai +SEAFILE_AI_LLM_URL= +SEAFILE_AI_LLM_KEY= # your llm key +SEAFILE_AI_LLM_MODEL=gpt-4o-mini + +## Metadata server +MD_FILE_COUNT_LIMIT=100000 diff --git a/swarm-compose.yml b/swarm-compose.yml new file mode 100644 index 0000000..cef2cba --- /dev/null +++ b/swarm-compose.yml @@ -0,0 +1,223 @@ +version: "3.8" + +x-deploy-default: &deploy_default + replicas: 1 + restart_policy: + condition: any + delay: 5s + max_attempts: 3 + window: 30s + placement: + constraints: + # IMPORTANT: because these are bind-backed volumes, keep services on the node that has the data paths. + - node.hostname == ${SEAFILE_NODE:-crackbox} + +services: + elasticsearch: + image: ${SEAFILE_ELASTICSEARCH_IMAGE:-elasticsearch:8.15.0} + environment: + - discovery.type=single-node + - bootstrap.memory_lock=true + - "ES_JAVA_OPTS=-Xms2g -Xmx2g" + - "xpack.security.enabled=false" + ulimits: + memlock: + soft: -1 + hard: -1 + volumes: + - seafile_elasticsearch_data:/usr/share/elasticsearch/data + networks: + - net + deploy: + <<: *deploy_default + resources: + limits: + memory: 4G + + db: + image: ${SEAFILE_DB_IMAGE:-mariadb:10.11} + environment: + - MYSQL_ROOT_PASSWORD=${INIT_SEAFILE_MYSQL_ROOT_PASSWORD:-} + - MYSQL_LOG_CONSOLE=true + - MARIADB_AUTO_UPGRADE=1 + volumes: + - seafile_mysql_data:/var/lib/mysql + networks: + - net + healthcheck: + test: + [ + "CMD", + "/usr/local/bin/healthcheck.sh", + "--connect", + "--mariadbupgrade", + "--innodb_initialized", + ] + interval: 20s + start_period: 30s + timeout: 5s + retries: 10 + deploy: + <<: *deploy_default + + redis: + image: ${SEAFILE_REDIS_IMAGE:-redis} + command: + - /bin/sh + - -c + - redis-server --requirepass "$$REDIS_PASSWORD" + environment: + - REDIS_PASSWORD=${REDIS_PASSWORD:-} + networks: + - net + deploy: + <<: *deploy_default + + seafile: + image: ${SEAFILE_IMAGE:-seafileltd/seafile-pro-mc:13.0-latest} + volumes: + - seafile_shared:/shared + environment: + - INIT_SEAFILE_MYSQL_ROOT_PASSWORD=${INIT_SEAFILE_MYSQL_ROOT_PASSWORD:-} + - SEAFILE_MYSQL_DB_HOST=${SEAFILE_MYSQL_DB_HOST:-db} + - SEAFILE_MYSQL_DB_PORT=${SEAFILE_MYSQL_DB_PORT:-3306} + - SEAFILE_MYSQL_DB_USER=${SEAFILE_MYSQL_DB_USER:-seafile} + - SEAFILE_MYSQL_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 + - CACHE_PROVIDER=${CACHE_PROVIDER:-redis} + - REDIS_HOST=${REDIS_HOST:-redis} + - REDIS_PORT=${REDIS_PORT:-6379} + - REDIS_PASSWORD=${REDIS_PASSWORD:-} + - MEMCACHED_HOST=${MEMCACHED_HOST:-memcached} + - MEMCACHED_PORT=${MEMCACHED_PORT:-11211} + - SEAF_SERVER_STORAGE_TYPE=${SEAF_SERVER_STORAGE_TYPE:-} + - S3_COMMIT_BUCKET=${S3_COMMIT_BUCKET:-} + - S3_FS_BUCKET=${S3_FS_BUCKET:-} + - S3_BLOCK_BUCKET=${S3_BLOCK_BUCKET:-} + - S3_KEY_ID=${S3_KEY_ID:-} + - S3_SECRET_KEY=${S3_SECRET_KEY:-} + - S3_USE_V4_SIGNATURE=${S3_USE_V4_SIGNATURE:-true} + - S3_AWS_REGION=${S3_AWS_REGION:-us-east-1} + - S3_HOST=${S3_HOST:-} + - S3_USE_HTTPS=${S3_USE_HTTPS:-true} + - S3_PATH_STYLE_REQUEST=${S3_PATH_STYLE_REQUEST:-false} + - S3_SSE_C_KEY=${S3_SSE_C_KEY:-} + - ENABLE_NOTIFICATION_SERVER=${ENABLE_NOTIFICATION_SERVER:-false} + - INNER_NOTIFICATION_SERVER_URL=${INNER_NOTIFICATION_SERVER_URL:-http://notification-server:8083} + - NOTIFICATION_SERVER_URL=${NOTIFICATION_SERVER_URL:-${SEAFILE_SERVER_PROTOCOL:-http}://${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty}/notification} + - ENABLE_SEAFILE_AI=${ENABLE_SEAFILE_AI:-false} + - SEAFILE_AI_SERVER_URL=${SEAFILE_AI_SERVER_URL:-http://seafile-ai:8888} + - SEAFILE_AI_SECRET_KEY=${JWT_PRIVATE_KEY:?Variable is not set or empty} + - MD_FILE_COUNT_LIMIT=${MD_FILE_COUNT_LIMIT:-100000} + networks: + - net + - public + - badge-net + expose: + - "80" + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:80 || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + deploy: + <<: *deploy_default + labels: + - "traefik.enable=true" + - "traefik.docker.network=public" + - "traefik.http.routers.seafile.rule=Host(`${SEAFILE_SERVER_HOSTNAME}`)" + - "traefik.http.routers.seafile.entrypoints=web" + - "traefik.http.services.seafile.loadbalancer.server.port=80" + # Ensure Seadoc path routers win + - "traefik.http.routers.seafile.priority=10" + + seadoc: + image: ${SEADOC_IMAGE:-seafileltd/sdoc-server:2.0-latest} + volumes: + - seadoc_shared:/shared + 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:-${SEAFILE_MYSQL_DB_SEAHUB_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_SERVICE_URL:-http://seafile} + networks: + - net + - public + - badge-net + expose: + - "80" + deploy: + <<: *deploy_default + labels: + - "traefik.enable=true" + - "traefik.docker.network=public" + # Route Seadoc endpoints on the same host: + - "traefik.http.routers.seadoc.rule=Host(`${SEAFILE_SERVER_HOSTNAME}`) && (PathPrefix(`/socket.io`) || PathPrefix(`/sdoc-server`))" + - "traefik.http.routers.seadoc.entrypoints=web" + - "traefik.http.routers.seadoc.priority=100" + - "traefik.http.services.seadoc.loadbalancer.server.port=80" + +volumes: + seafile_elasticsearch_data: + name: seafile_elasticsearch_data + driver: local + driver_opts: + type: none + o: bind + device: ${SEAFILE_ELASTICSEARCH_VOLUME:-/opt/seafile-elasticsearch/data} + + seafile_mysql_data: + name: seafile_mysql_data + driver: local + driver_opts: + type: none + o: bind + device: ${SEAFILE_MYSQL_VOLUME:-/opt/seafile-mysql/db} + + seafile_shared: + name: seafile_shared + driver: local + driver_opts: + type: none + o: bind + device: ${SEAFILE_VOLUME:-/opt/seafile-data} + + seadoc_shared: + name: seadoc_shared + driver: local + driver_opts: + type: none + o: bind + device: ${SEADOC_VOLUME:-/opt/seadoc-data/} + +networks: + net: + driver: overlay + attachable: true + + public: + external: true + name: public + + badge-net: + external: true + name: badge-net