因需要部署生产服务器,所以我是先在个人虚拟机上验证,再将相关操作重新在生产服务器上操作,因此多了一个本地安装操作系统与上传服务器文件和加载镜像的步骤。部署结果,在个人虚拟机上按以上步骤,在kylin v10 sp2上成功部署seafile13,并替换80端口为8099,解决头像问题。但是在服务器上部署失败,确认是由于cpu过旧不支持X86_V2指令集,引发Seafile 事件系统(seafevents)加载 NumPy 时崩溃,seafile服务无法正常启动,因此最终放弃在服务器环境部署seafile13,但在我本机vm虚拟机部署正常。经测试seafile12与seafile11版本均有numpy问题,无法在服务器上正常服务。改部署seafile10版本后可正常服务。
1. 环境说明
(1) 操作系统
麒麟v10 sp2系统
下载地址:
安装后确认版本信息
[root@localhost ~]# uname -a
Linux localhost.localdomain 4.19.90-24.4.v2101.ky10.x86_64 #1 SMP Mon May 24 12:14:55 CST 2021 x86_64 x86_64 x86_64 GNU/Linux
[root@localhost ~]# cat /etc/os-release
NAME=“Kylin Linux Advanced Server”
VERSION=“V10 (Sword)”
ID=“kylin”
VERSION_ID=“V10”
PRETTY_NAME=“Kylin Linux Advanced Server V10 (Sword)”
ANSI_COLOR=“0;31”
(2) 关闭selinux,关闭防火墙
2. 相关软件包准备
(1) docker安装
Kylin自己的docker太低,因此安装的是26.1.4版本
网上下载docker-26.1.4.tgz,并上传到服务器安装
下载地址:https://download.docker.com/linux/static/stable/x86_64/docker-26.1.4.tgz
执行以下命令完成docker安装
在当前目录直接下载安装包:
wget https://download.docker.com/linux/static/stable/x86_64/docker-26.1.4.tgz
解压安装包:
sudo tar -xvf docker-26.1.4.tgz
移动到/usr/bin目录下:
sudo mv docker/* /usr/bin/
创建/etc/systemd/system/docker.service文件:
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s
[Install]
WantedBy=multi-user.target
开机自动启动docker服务:
sudo systemctl daemon-reload
sudo systemctl enable docker
sudo systemctl start docker
验证docker服务是否正常:
systemctl status docker
docker ps -a
docker run hello-world
(2) docker-compose安装
Kylin自己的docker-compose版本过低,安装v2.20.2版本,个人虚拟机上直接下载:
sudo curl -L https://github.com/docker/compose/releases/download/v2.20.2/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
如果是服务器,则直接上传已下载的文件到指定位置:
sudo scp /usr/local/bin/docker-compose 服务器用户名@服务器IP:/home/seafile/uploads/
sudo mv /home/seafile/uploads/docker-compose /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
验证docker-compose是否安装成功,执行以下命令显示Docker Compose version v2.20.2则为成功
sudo docker-compose version
3. 安装seafile13
(1) seafile用户
创建seafile用户:
sudo useradd -m -s /bin/bash seafile
设置密码:
sudo passwd seafile
加入到docker组(因为需要使用seafile用户执行docker与docker-compose):
usermod -aG docker seafile
设置sudo免密
echo “seafile ALL=(ALL) NOPASSWD:ALL” | sudo tee /etc/sudoers.d/seafile
chmod 440 /etc/sudoers.d/seafile
重新登录 seafile 用户,退出当前终端,再登录:
su - seafile
验证 docker 权限是否生效:
docker ps
验证免密是否生效:
sudo ls /
(2) 创建/opt/seafile目录
创建目录:
mkdir -p /opt/seafile
赋予 seafile 用户权限
chown -R seafile:seafile /opt/seafile
(3) 创建/opt/seafile目录和data目录
/opt/seafile目录用来放yml文件和env文件
/opt/seafile/data目录用来保存seafile相关数据
(4) 下载yml文件和env文件
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
(5) 修改env文件
更改Images部分,修改docker镜像版本为kylin v10适用版本
SEAFILE_DB_IMAGE=mariadb:10.5
SEAFILE_REDIS_IMAGE=redis:5.0
更改Persistent Storage持久化数据文件位置
BASIC_STORAGE_PATH=./data
更改Startup parameters启动参数
SEAFILE_SERVER_HOSTNAME=你的IP:端口
SEAFILE_SERVER_PROTOCOL=http
TIME_ZONE=Asia/Shanghai
JWT_PRIVATE_KEY=自己生成的key
更改Database数据库参数,这里用户名是seafile,密码是Seafile0228
SEAFILE_MYSQL_DB_USER=seafile
SEAFILE_MYSQL_DB_PASSWORD=Seafile0228
更改数据库root用户初始密码
INIT_SEAFILE_MYSQL_ROOT_PASSWORD=Seafile0228
更改seafile平台的管理员初始账号与密码
INIT_SEAFILE_ADMIN_EMAIL=seafile@126.com
INIT_SEAFILE_ADMIN_PASSWORD=Seafile0228
(6) 修改seafile-server.yml 内容
在每个服务里,在 restart: unless-stopped这行下面增加以下内容:
security_opt:
- seccomp=unconfined
作用:关闭 Docker 的 seccomp 沙箱,让容器可以使用所有系统调用(syscall),不再被限制。
在seafile服务volumes标签下增加setup-seafile-mysql.sh文件映射
- /opt/seafile-patch/setup-seafile-mysql.sh:/opt/seafile/seafile-server-13.0.18/setup-seafile-mysql.sh
作用:解决mariadb容器在启动时找不到python3的问题
(7) 启动容器
在服务器的/opt/seafile目录下,以seafile用户执行以下命令,会直接启动容器
docker-compose up -d
(8) 验证服务是否正常
查看日志
docker logs seafile
查看网页,我虚拟机ip是192.168.119.130
显示登录页代表正常启动了。
4. 集成onlyoffice.yml
(1) 下载onlyoffice.yml文件
在/opt/seafile目录下执行以下命令下载:
wget https://manual.seafile.com/13.0/repo/docker/onlyoffice.yml
(2) 修改.env文件
增加加载的yml文件
COMPOSE_FILE=‘seafile-server.yml,caddy.yml,seadoc.yml,onlyoffice.yml’
(3) 重新启动容器服务即可
停止
docker-compose down
启动
docker-compose up -d
5. Seafile平台访问端口号80变为8099
由于大部分生产环境不允许开放80端口,因此我在此改为8099端口。修改方法参照了这位网友的方法,参照地址为:https://bbs.seafile.com/t/topic/22333
seafile主服务不使用caddy,使用了nginx,不过仍然保留caddy做为seadoc的代理。
因为要用nginx代理seafile,所以这里的80端口先注释掉
(1) 修改seafile-server.yml内容
seafile服务下端口配置为:
ports:
- "8000:8000"
- "8080:8080"
- "8082:8082"
Seafile服务下删除或注释掉label标签,不使用caddy
# labels:
# caddy: ${SEAFILE_SERVER_PROTOCOL:-http}://${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty}
# caddy.reverse_proxy: “{{upstreams 80}}”
(2) 修改seadoc.yml 内容
seadoc服务的端口配置为
ports:
- 8089:80
labels标签更改为
labels:
caddy: ${SEAFILE_SERVER_PROTOCOL:-http}://${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty}
(3) 修改caddy.yml 内容
caddy服务端口配置为
ports:
# - 80:80
- 443:443
(4) 修改onlyoffice.yml 内容
修改labbels标签内容,原SEAFILE_SERVER_HOSTNAME替换成了ONLYOFFICE_HOSTNAME。因为在.env文件里已经配置了EAFILE_SERVER_HOSTNAME为带端口号的地址,直接使用会报错,因此在.env文件配置ONLYOFFICE_HOSTNAME变量为不带端口号的地址,在这里引用此变量
labels:
caddy: ${SEAFILE_SERVER_PROTOCOL:-http}://${ONLYOFFICE_HOSTNAME:?Variable is not set or empty}:${ONLYOFFICE_PORT:-6233}
(5) Nginx配置文件
新建文件/etc/nginx/conf.d/seafile-8099.conf,文件内容在后文贴出。
另外在/etc/nginx/nginx.conf文件中做了全局加固,在http{}块中加固,位置在
default_type application/octet-stream;
这行下面,增加以下内容:
# 全局限流区定义(必须在 http{} 里)
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=100r/s;
最后注释掉该文件默认开启80端口的servers配置
(6) 验证是否成功
在/opt/seafile目录下,以seafile用户执行以下命令,会直接启动容器
docker-compose up -d
查看日志
docker logs seafile
查看网页,我虚拟机ip是192.168.119.130
显示登录页代表正常启动了。
(7) 增加防火墙配置
因为是服务器正式使用时需要开启防火墙,因此需要放行端口
开启防火墙
sudo systemctl start firwalld
放行8099和6233端口
sudo firewall-cmd --zone=public --add-port=8099/tcp --permanent
sudo firewall-cmd --zone=public --add-port=6233/tcp --permanent
开启 masquerade(NAT 转发),不开启无法转发到容器端口
sudo firewall-cmd --zone=public --add-masquerade --permanent
重新加载生效配置信息
sudo firewall-cmd --reload
(8) 整理部署过程中遇到的问题如下:
问题1:seafile-mysql没有启动成功,查看seafile-mysql容器日志,发现报错信息Can’t initialize timers
原因是MariaDB 10.11 在银河麒麟 V10(国产内核)上无法初始化定时器(timer)。需将镜像换成10.5即可解决,修改docker-compose.yml文件,将image:mariadb:10.11更改为image: mariadb:10.5。
问题2:seafile-mysql启动成功,但是拒绝连接。docker logs seafile-mysql日志中最后提到[Warning] Access denied for user ‘seafile’@‘192.168.0.4’ (using password: YES)
原因是MariaDB 初始化时没有使用配置文件中提供的 root 密码,而是自动生成了一个随机密码。MariaDB 初始化日志里有这一段[Entrypoint]: Securing system users (equivalent to running mysql_secure_installation)
MariaDB 在初始化时执行了类似 mysql_secure_installation 的逻辑。这个逻辑会自动生成 root 密码(而不是使用.env里提供的密码),这就是现在无法登录 root 用户的原因,为了保险起见,root用户与seafile用户密码,都重置一下
跳过权限模式启动 MariaDB(临时模式)
docker run --rm -it \
-v /opt/seafile-mysql/db:/var/lib/mysql \
mariadb:10.5 \
mysqld --skip-grant-tables --user=mysql
打开另一个终端,进入临时 MySQL
docker exec -it $(docker ps -q --filter ancestor=mariadb:10.5) mysql -uroot
FLUSH PRIVILEGES;
ALTER USER ‘root’@‘localhost’ IDENTIFIED BY ‘你的root密码’;
ALTER USER ‘root’@‘%’ IDENTIFIED BY ‘你的root密码’;
ALTER USER ‘root’@‘localhost’ IDENTIFIED BY ‘你的seafile密码’;
ALTER USER ‘seafile’@‘%’ IDENTIFIED BY ‘你的seafile密码’;
FLUSH PRIVILEGES;
退出 MySQL,关闭临时容器,启动正式 MariaDB 容器
docker start seafile-mysql
测试 root 密码
docker exec -it seafile-mysql mysql -uroot -p
输入你刚刚设置的密码。如果成功,代表root 密码已修复
问题3:seafile容器启动失败,报错提示
[WARNING] ../common/seaf-db.c(266): Failed to create mysql connection keepalive thread.
[WARNING] ../common/seaf-utils.c(237): Failed to start mysql db.
[WARNING] seafile-session.c(243): Failed to load database config.
[WARNING] seaf-server.c(1353): Failed to create seafile session.
因上面提示有数据库问题,因此在seafile容器内测试到mysql的连接
root@d92f5b7998d9:/opt/seafile# curl seafile-mysql:3306
curl: (6) getaddrinfo() thread failed to start
原因是 glibc 在创建解析线程时失败,做了个小测试验证此问题,在容器内执行pthread_create(&t, NULL, f, NULL),返回结果ret = 1,说明容器环境本身无法创建线程,开始怀疑 seccomp / glibc / clone() 被拦截,执行以下命令测试grep Seccomp /proc/1/status,看到结果是Seccomp: 2,说明容器处于严格 seccomp 模式。然后在seafile-server.yml文件中增加以下内容
security_opt:
- seccomp=unconfined
重启容器后测试pthread_create(&t, NULL, f, NULL),返回结果ret = 0
问题4:seadoc容器启动失败,报错提示
Assertion failed: (0) == (uv_thread_create(t.get(), start_thread, this))
Aborted (core dumped)及RuntimeError: can’t start new thread
原因与问题3相同,因此同样在seadoc.yml文件内容中增加以下内容:
security_opt:
- seccomp=unconfined
为了保险起见,后来在其他服务里也均增加了这个内容
问题5:seafile容器启动失败,docker logs seafile日志中提示The current version of python is not 3.x.x, please use Python 3.x.x .
这可能是seafile 官方脚本在国产系统上的兼容性 bug,我在centos7.2上没有此问题。解决方法是需要显示指定python3位置。
将容器内setup-seafile-mysql.sh文件复制到宿主机上,放在data目录里是方便将来一起做数据备份
sudo mkdir /opt/seafile/data/seafile-patch/
docker cp seafile:/opt/seafile/seafile-server-13.0.18/setup-seafile-mysql.sh /opt/seafile/data/seafile-patch/
修改setup-seafile-mysql.sh文件内容,拦截后续判断,显示指定python位置。在check_python_executable()函数中增加了以下判断,增加位置在function check_python_executable() {这行代码下方,也就是函数内容的最前面。
if [ -f /usr/bin/python3 ]; then
PYTHON=/usr/bin/python3
return 0
fi
同时在seafile-sever.yml文件中,在seafile服务的volumes标签下增加了宿主机文件到容器文件的映射。
/opt/seafile/data/seafile-patch/setup-seafile-mysql.sh:/opt/seafile/seafile-server-13.0.18/setup-seafile-mysql.sh
问题6:默认头像不能正常显示,但是上传新头像成功后,新头像还是不能正常显示。 修改方法参照了这位网友的方法,参照地址为:https://bbs.seafile.com/t/topic/22333,并有一小差别
从容器内复制 media 目录到宿主机
docker cp seafile:/shared/seafile-data/seafile/media /opt/seafile/data/seafile-data/seafile/
修复宿主机 media 目录的软链接
rm -f /opt/seafile/data/seafile-data/seafile/media/avatars
ln -s /opt/seafile/data/seafile-data/seafile/media/avatars /opt/seafile/data/seafile-data/seafile/media/avatars
rm -f /opt/seafile/data/seafile-data/seafile/media/custom
ln -s /opt/seafile/data/seafile-data/seafile/media/custom /opt/seafile/data/seafile-data/seafile/media/custom
宿主机nginx配置修正,这里我按网友的方法没成功,改为如下配置成功显示头像
location /media/ {
alias /opt/seafile/data/seafile-data/seafile/media/;
}
问题7:Redis容器启动报错,提示Fatal: Can’t initialize Background Jobs. Error message: Operation not permitted
默认的seafile-server.yml文件里拉取的是Redis 8.x镜像,而Redis 8.x是 2024 年之后的新版本,它启用了新的后台任务线程模型,需要内核支持 clone3、io_uring、cgroup v2 等特性。银河麒麟 V10(基于 FreeBSD/DragonFly 衍生内核 + 国产补丁)不支持这些特性。
但是换redis6.2仍然有问题,日志中有以下提示
Fatal: Can’t initialize Background Jobs.
其原因是银河麒麟 V10 内核不支持 Redis 的后台任务机制(fork + background save + AOF rewrite)
换成redis5.0解决
更换方法是修改.env文件的redis镜像版本
SEAFILE_REDIS_IMAGE=redis:5.0
并重新拉取镜像
问题8:执行docker-compose -f seafile-server.yml pull直接报错ERROR: Invalid interpolation format for “db” option in service “services”: “${SEAFILE_DB_IMAGE:-mariadb:10.11}”
说明 docker‑compose 1.22.0(你当前使用的版本)不支持这种变量默认值语法:${VAR:-default}
这是 Compose v2 才支持的语法,因此重新安装v2.20.2版本
问题9:本地跑通后,在服务器部署,访问8099端口,页面提示Internal Server Error
检查seahub容器情况docker logs seahub,提示
Error response from daemon: No such container: seahub
RuntimeError: NumPy was built with baseline optimizations:
(X86_V2) but your machine doesn’t support:
(X86_V2).
Seafile 事件系统(seafevents)加载 NumPy 时崩溃:CPU 不支持 X86_V2 指令集
使用以下命令查看当前虚拟上支持的指令集与宿主机的cpu信息
cat /proc/cpuinfo | grep flags
cat /proc/cpuinfo | grep -E “model name|flags” | head -4
确认是cpu过旧不支持该指令集。因此放弃在服务器环境部署seafile13。
后面附上各个配置文件内容:
.env文件内容
#################################
# Docker compose configurations #
#################################
COMPOSE_FILE=‘seafile-server.yml,caddy.yml,seadoc.yml,onlyoffice.yml’
COMPOSE_PATH_SEPARATOR=‘,’
## Images
SEAFILE_IMAGE=seafileltd/seafile-mc:13.0-latest
SEAFILE_DB_IMAGE=mariadb:10.5
SEAFILE_REDIS_IMAGE=redis:5.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
MD_IMAGE=seafileltd/seafile-md-server:13.0-latest
## Persistent Storage
BASIC_STORAGE_PATH=./data
SEAFILE_VOLUME=$BASIC_STORAGE_PATH/seafile-data
SEAFILE_MYSQL_VOLUME=$BASIC_STORAGE_PATH/seafile-mysql/db
SEAFILE_CADDY_VOLUME=$BASIC_STORAGE_PATH/seafile-caddy
SEADOC_VOLUME=$BASIC_STORAGE_PATH/seadoc-data
#################################
# Startup parameters #
#################################
SEAFILE_SERVER_HOSTNAME=192.168.119.130:8099
SEAFILE_SERVER_PROTOCOL=http
TIME_ZONE=Asia/Shanghai
JWT_PRIVATE_KEY=3f8c2e9b4a0d7f1c9e2b8d4f6a1c3e7f9b2d4c6e8a0b1c3d5e7f9a1b3c5d7e9
#####################################
# Third-party service configuration #
#####################################
## Database
SEAFILE_MYSQL_DB_HOST=db
SEAFILE_MYSQL_DB_USER=seafile
SEAFILE_MYSQL_DB_PASSWORD=Seafile0228
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 # or 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=Seafile0228
## Seafile admin user
INIT_SEAFILE_ADMIN_EMAIL=seafile@126.com
INIT_SEAFILE_ADMIN_PASSWORD=Seafile0228
############################################
# Additional configurations for extensions #
############################################
## SeaDoc service
ENABLE_SEADOC=true
## Notification
ENABLE_NOTIFICATION_SERVER=false
NOTIFICATION_SERVER_URL=
## Seafile AI
ENABLE_SEAFILE_AI=false
ENABLE_FACE_RECOGNITION=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
## add onlyoffice
# OnlyOffice 镜像
ONLYOFFICE_IMAGE=onlyoffice/documentserver:8.1.0.1
# OnlyOffice 地址
ONLYOFFICE_HOSTNAME=192.168.119.130
# OnlyOffice 的持久化存储目录
ONLYOFFICE_VOLUME=/opt/seafile/data/onlyoffice
# OnlyOffice 文档服务器端口
ONLYOFFICE_PORT=6233
# jwt 密钥,通过 `pwgen -s 40 1` 生成
ONLYOFFICE_JWT_SECRET=Q9tFz3WmA8rLk2VhS7pXc4JbN1yR0eTgH5uPqZs
seafile-sever.yml内容
services:
db:
image: ${SEAFILE_DB_IMAGE:-mariadb:10.11}
container_name: seafile-mysql
restart: unless-stopped
security_opt:
- seccomp=unconfined
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
security_opt:
- seccomp=unconfined
command:
- /bin/sh
- -c
- redis-server --requirepass "$$REDIS_PASSWORD"
environment:
- REDIS_PASSWORD=${REDIS_PASSWORD:-}
networks:
- seafile-net
seafile:
image: ${SEAFILE_IMAGE:-seafileltd/seafile-mc:13.0-latest}
container_name: seafile
restart: unless-stopped
ports:
- "8000:8000"
- "8080:8080"
- "8082:8082"
security_opt:
- seccomp=unconfined
- apparmor=unconfined
volumes:
- ${SEAFILE_VOLUME:-/opt/seafile-data}:/shared
- /opt/seafile/data/seafile-patch/setup-seafile-mysql.sh:/opt/seafile/seafile-server-13.0.18/setup-seafile-mysql.sh
environment:
- 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}
- 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:-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_GO_FILESERVER=${ENABLE_GO_FILESERVER:-true}
- 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}
- 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}
- ENABLE_FACE_RECOGNITION=${ENABLE_FACE_RECOGNITION:-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
caddy.yml内容
services:
caddy:
image: ${SEAFILE_CADDY_IMAGE:-lucaslorentz/caddy-docker-proxy:2.9-alpine}
restart: unless-stopped
container_name: seafile-caddy
security_opt:
- seccomp=unconfined
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
seadoc.yml内容
services:
seadoc:
image: ${SEADOC_IMAGE:-seafileltd/sdoc-server:2.0-latest}
container_name: seadoc
restart: unless-stopped
security_opt:
- seccomp=unconfined
volumes:
- ${SEADOC_VOLUME:-/opt/seadoc-data/}:/shared
ports:
- 8089: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
onlyoffic.yml内容
services:
caddy:
ports:
- ${ONLYOFFICE_PORT:-6233}:${ONLYOFFICE_PORT:-6233}
onlyoffice:
image: ${ONLYOFFICE_IMAGE:-onlyoffice/documentserver:8.1.0.1}
restart: unless-stopped
security_opt:
- seccomp=unconfined
container_name: seafile-onlyoffice
environment:
#- 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}
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}://${ONLYOFFICE_HOSTNAME:?Variable is not set or empty}:${ONLYOFFICE_PORT:-6233}
caddy.reverse_proxy: "{{upstreams}}"
networks:
- seafile-net
networks:
seafile-net:
name: seafile-net
nginx文件内容:
server {
listen 8099;
\# -------------------------
\# 全局安全加固(server 级)
\# -------------------------
server_tokens off;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
\# 限制请求方法(不影响 Seafile / OnlyOffice / Seadoc)
if ($request_method !\~ ^(GET|POST|HEAD|OPTIONS)$) {
return 405;
}
\# 简单防扫描(正常浏览器不会命中)
if ($http_user_agent \~\* (sqlmap|nmap|nikto|fimap|nessus|acunetix)) {
return 403;
}
\# 如需限制 Host,可按需打开并改成你的域名/IP
\# if ($host !\~\* ^(yourdomain\\.com|你的IP)$) {
\# return 403;
\# }
\# 使用在 http{} 里定义好的 zone
limit_conn addr 20;
\# 禁止访问敏感隐藏文件
location \~ /\\.(git|svn|hg|env|htaccess|bash|ssh) {
deny all;
}
\# -------------------------
\# Seafile 主站点(8000)
\# -------------------------
location / {
\# 每 IP 限制请求速率(使用 http{} 里定义的 zone)
limit_req zone=req_limit_per_ip burst=20 nodelay;
proxy_pass http://127.0.0.1:8000/;
proxy_read_timeout 1200s;
proxy_set_header Host $http_host;
proxy_set_header Forwarded "for=$remote_addr;proto=$scheme";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Connection "";
proxy_http_version 1.1;
client_max_body_size 0;
}
\# -------------------------
\# Seafile 文件上传(8082)
\# -------------------------
location /seafhttp {
rewrite ^/seafhttp(.\*)$ $1 break;
proxy_pass http://127.0.0.1:8082;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 0;
proxy_connect_timeout 36000s;
proxy_read_timeout 36000s;
proxy_request_buffering off;
}
\# -------------------------
\# WebDAV(8080)
\# -------------------------
location /seafdav {
proxy_pass http://127.0.0.1:8080/seafdav;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 1200s;
client_max_body_size 0;
}
\# -------------------------
\# 静态资源(头像、CSS、JS)
\# -------------------------
location /media/ {
alias /opt/seafile/data/seafile-data/seafile/media/;
}
\# -------------------------
\# Seadoc(8089)
\# -------------------------
location /sdoc-server/ {
add_header Access-Control-Allow-Origin \*;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
add_header Access-Control-Allow-Headers "deviceType,token, authorization, content-type";
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_pass http://127.0.0.1:8089/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 100m;
}
\# -------------------------
\# Seadoc WebSocket
\# -------------------------
location /socket.io {
proxy_pass http://127.0.0.1:8089;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
}
}