1. 部署前哨:先把Sakai 20.0的老底摸清楚
先聊点实在的。Sakai这个名字,国内很多高校老师和做在线教育的同行应该不陌生,它是一个开源的在线协作与学习平台,说白了就是一套帮学校、培训机构搭网络教学环境的系统。20.0这个版本,核心变化之一是把底层架构往新方向推了推,不再强行依赖老旧的那套运行环境,对部署者来说,最直接的好处是依赖关系更清爽、组件升级的余地更大。
很多刚接触Sakai的人容易有个误解:以为它是个像WordPress那样装上就能用的现成站点。实际上它更接近一套需要自己组装的服务:底层用Java技术栈,数据存数据库,文件走存储系统,前面还要挂一层代理做请求分发。部署Sakai 20.0,本质上是在服务器上把这些上下游组件按正确姿势拼起来。
我这次部署用的是常规的Linux服务器环境(以CentOS系为例),数据库选用MySQL 5.7以上版本,JDK要求是1.8或11(20.0对JDK 11的支持已经比较成熟了)。如果你手头是Ubuntu/Debian系,命令上做对应替换即可,核心逻辑完全一致。整个部署过程如果一切顺利、网络带宽也正常,大约需要两个小时左右;但如果你跟我一样中途踩了版本兼容的坑,预留半天比较稳妥。
这个部署方案适合谁参考?一类是想在内部服务器上自建在线教学平台的学校IT老师,另一类是想基于Sakai做二次开发的研发同学,还有一类就是单纯被领导安排“把Sakai跑起来”的运维朋友。不管你是哪一类,这篇梳理都会尽量把部署链路讲透,让它从“能跑”变成“跑得稳”。
2. 部署架构拆解:Sakai 20.0凭什么这样搭
2.1 先搞懂Sakai 20.0运行时的“三驾马车”
Sakai 20.0的部署不是单进程操作,它运行时依托三条核心链路,我习惯叫它“三驾马车”。第一驾是应用服务器,Sakai本身是一个Java Web应用,打包成WAR文件放在应用服务器里跑,20.0版本官方默认支持Apache Tomcat 9,这个版本选型很关键,因为Tomcat 9对应Servlet 4.0规范,能跟Sakai 20.0的新组件兼容;第二驾是数据库,Sakai的所有课程、用户、权限、作业、论坛帖子都存在关系型数据库里,官方推荐MySQL,20.0开始对MySQL 8.0的原生支持也变好了;第三驾是文件存储,课程上传的附件、用户头像这类二进制文件不会进数据库,而是落到服务器磁盘或对象存储,Sakai 20.0默认走本地文件系统,路径通常在/usr/local/sakai/files或者你自定义的目录。
三条链路的关系可以类比成一个餐厅:应用服务器是前台服务员,接收顾客(浏览器用户)的点单;数据库是后厨的账本,记录每桌客人点了什么;文件存储则是冷藏库,放着那些不用写进账本但必须保鲜的食材。三者缺一不可,任何一个环节没对齐,Sakai就会出现奇奇怪怪的问题——最常见的就是“页面能开但头像加载失败”或者“附件传不上来”,多半是文件存储权限或路径配置出了岔子。
2.2 为什么推荐用源码包而不是发行版自带的包管理工具安装
有些朋友图省事,直接用系统自带的yum install sakai之类的命令装,结果往往会遇到版本过旧、依赖冲突、配置文件分散的问题。Sakai 20.0我强烈建议从官方发布的二进制包或源码包走,原因有三点。首先,Sakai官方对版本的发布节奏不是跟着Linux发行版走的,你用系统的包管理器装到的很可能还是老版本,功能差异大且已知漏洞多;其次,用源码包你能看到完整的目录结构和配置文件,出问题时知道去哪里排查;第三,Sakai部署随意性很强,不同学校有不同的域名、端口、数据库前缀,包管理器装完你还得手动改一堆地方,跟直接解压源码包再改配置没本质区别,反倒多了一层包管理器的干扰。
个人经验是下载sakai-20.0的二进制分发包(一般是.tar.gz格式),解压到/usr/local/sakai目录下,然后以/usr/local/sakai作为CATALINA_HOME来运行。这样后续所有配置、日志、应用包都集中在一个根目录下,排查问题的时候非常省心。
2.3 服务器配置的底线要求
Sakai 20.0对服务器配置的要求不算夸张,但也没法寒酸。根据我自己的压测经验,如果是给一个几百人规模的高校做内部教学平台,最低配建议2核CPU + 4GB内存 + 40GB SSD磁盘;如果是上千人同时在线的高峰场景,4核CPU + 8GB内存会更从容,磁盘根据附件量做弹性扩展。
这里要特别提醒一句:Sakai 20.0启动时JVM堆内存的默认配置往往偏保守,在/usr/local/sakai/bin/setenv.sh或catalina.sh里务必把JAVA_OPTS的-Xms和-Xmx调大,我自己的生产环境设置的是-Xms2048m -Xmx4096m。如果不调,高并发时你会频繁看到OutOfMemoryError,这个坑我踩过不止一次。
3. 数据库与基础环境准备:细到每一步的实操
3.1 JDK 11安装与验证
Sakai 20.0在JDK版本上,官方给的选项是JDK 1.8或JDK 11。JDK 8目前虽然还在支撑很多老项目,但Sakai 20.0的某些新特性在JDK 11下表现更稳,我用的是OpenJDK 11。安装没有什么花哨的:
# CentOS / RHEL 系 sudo yum install -y java-11-openjdk-devel # Ubuntu / Debian 系 sudo apt-get install -y openjdk-11-jdk装完务必验证一下版本:
java -version如果显示的是openjdk version "11.0.x"这类信息,说明Java环境已就绪。这里有个细节容易忽略:安装完OpenJDK后,系统里可能还残留着旧版本的Java,用alternatives --config java把默认Java版本切到11,否则后面启动Tomcat时会莫名报UnsupportedClassVersionError,那大概率就是JDK版本不对。
3.2 MySQL 5.7的安装与字符集陷阱
Sakai 20.0的数据库我用的是MySQL 5.7,这也是官方文档里测试比较充分的组合。安装方式照旧:
# CentOS 7 sudo yum install -y https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm sudo yum install -y mysql-community-server # Ubuntu 18.04+ sudo apt-get install -y mysql-server启动服务并设为开机自启:
sudo systemctl enable mysqld sudo systemctl start mysqldMySQL 5.7首次启动会生成一个临时root密码,在/var/log/mysqld.log里可以找到。用临时密码登录后,第一件事就是改密码并创建一个Sakai专用账号:
ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourStrongPassword'; CREATE DATABASE sakai CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; CREATE USER 'sakai'@'localhost' IDENTIFIED BY 'SakaiDBPassword'; GRANT ALL PRIVILEGES ON sakai.* TO 'sakai'@'localhost'; FLUSH PRIVILEGES;字符集这里必须展开说。Sakai 20.0默认建表时会使用utf8mb4字符集,如果数据库实例的默认字符集不是utf8mb4,后面导入SQL脚本时可能出现乱码、索引过长甚至直接报错。所以你在my.cnf里最好显式加上:
[mysqld] character-set-server=utf8mb4 collation-server=utf8mb4_binutf8mb4_bin这个排序规则是二进制比较,适合Sakai内部对代码表、资源标识这类字段的精确匹配需求。我曾经因为偷懒用了默认的utf8mb4_general_ci,虽然大部分功能正常,但Sakai的权限模块在某些场景下会出现“明明赋了权限却不生效”的怪问题,后来改成utf8mb4_bin重建库就解决了。
3.3 上传Sakai 20.0安装包并解压
到Sakai官网的下载页面找Sakai 20.0对应的二进制包,一般文件名类似sakai-20.0-2021-xx-xx.tar.gz。放到服务器后,解压到目标目录:
sudo mkdir -p /usr/local/sakai sudo tar -xzf sakai-20.0-2021-xx-xx.tar.gz -C /usr/local/sakai --strip-components=1注意这一步要充分理解--strip-components=1的作用:解压出来的第一层目录名通常带版本号(类似sakai-20.0),如果不剥离这一层,你的CATALINA_HOME就变成了/usr/local/sakai/sakai-20.0,后续所有配置路径都要多套一层,非常麻烦。
4. 核心配置文件逐项解析:这些参数缺一不可
4.1sakai.properties的必改项
Sakai 20.0的核心配置集中在/usr/local/sakai/sakai/sakai.properties这个文件里。与其说是“配置文件”,不如说它是Sakai全部运行时行为的“总开关”。从头到尾过一遍最关键的几项,缺一不可。
首先确定你的站点地址:
server.name=learn.youruniversity.edu.cn server.port=8080 server.url=http://learn.youruniversity.edu.cn:8080这三个参数决定了Sakai生成页面链接时使用的域名和端口。如果你后面用Nginx做反向代理对外提供443端口服务,这里的server.url要写成对外域名,否则用户在浏览器里看到的部分链接会指向内网端口,直接打不开。
然后是数据库连接配置:
username@sakai@org.sakaiproject.db.user=sakai password@sakai@org.sakaiproject.db.password=SakaiDBPassword url@sakai@org.sakaiproject.db.vendor=mysql url@sakai@org.sakaiproject.db.driver=com.mysql.jdbc.Driver url@sakai@org.sakaiproject.db.url=jdbc:mysql://localhost:3306/sakai?useUnicode=true&characterEncoding=utf8mb4&useSSL=false&allowPublicKeyRetrieval=trueurl@sakai@org.sakaiproject.db.url这项特别关键,我加上了useUnicode=true&characterEncoding=utf8mb4&useSSL=false&allowPublicKeyRetrieval=true这些参数,其中allowPublicKeyRetrieval=true是为了应对MySQL 8.0以上版本在使用caching_sha2_password认证时可能出现的连接报错;但你现在用的是MySQL 5.7,useSSL=false可以免去证书配置的麻烦,characterEncoding=utf8mb4则确保数据库读写不乱码。
文件存储路径也不可忽视:
sakai.home=/usr/local/sakai/sakai privatePath@sakai@org.sakaiproject.content.types...=/usr/local/sakai/filesprivatePath是Content Hosting的根目录,如果你用NFS或对象存储做共享,这里就填挂载路径。
4.2server.xml的关键调优
Tomcat的server.xml在/usr/local/sakai/conf目录下。需要改的地方不多,但必改的是端口和编码:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" />URIEncoding="UTF-8"这一项建议手动加上,否则URL里带中文文件名时会出现乱码,Sakai的附件下载功能直接受影响。还有一处容易被忽视:默认的maxThreads="200"在生产环境偏低,建议调整为400左右(根据服务器CPU核数动态调,8核以内建议不超过400)。
4.3 日志配置:排错时最依赖的朋友
Sakai日志默认输出到/usr/local/sakai/logs/目录。sakai.log和catalina.out是最常看的两个文件,前者记录Sakai业务逻辑的日志,后者是Tomcat运行日志。如果启动时卡住不报错,先看catalina.out;如果某个功能报500,去翻sakai.log。
我习惯启动后用这个命令实时盯日志:
tail -f /usr/local/sakai/logs/catalina.out结合grep按时间点过滤关键错误,排查效率高很多。
5. 数据库初始化与Sakai启动:从空白到第一个页面
5.1 导入Sakai的初始SQL脚本
Sakai 20.0的安装包里自带数据库初始化脚本,一般放在/usr/local/sakai/docs/sql/mysql/目录下。这个脚本会创建一组初始表结构和默认数据(比如管理员账号、默认站点类型),导入前先把Sakai服务停掉,避免抢资源或表锁冲突:
cd /usr/local/sakai/docs/sql/mysql mysql -u sakai -p'YourStrongPassword' sakai < sakai_20.0.sql导入过程根据服务器性能不同,可能耗时几分钟到十几分钟,耐心等待,不要中途打断。导入完成后可以用mysql -u sakai -p'YourStrongPassword' -e "USE sakai; SHOW TABLES;"验证一下,看到类似SAKAI_USER、SAKAI_SITE、SAKAI_REALM这些表都建出来了,说明数据库初始化成功。
这里有件特别容易踩坑的事:如果你的MySQL版本是8.0,导入时可能会因为旧版SQL脚本里的TYPE=MyISAM之类语法而报错,需要先做语法修正。Sakai 20.0的官方脚本对MySQL 5.7和8.0都做了适配,但如果你用的第三方整理的脚本,还是留个心眼。
5.2 设置JVM内存与启动参数
启动Sakai前,务必把内存参数调到位。编辑/usr/local/sakai/bin/setenv.sh:
JAVA_OPTS="-Xms2048m -Xmx4096m -Djava.awt.headless=true"-Djava.awt.headless=true这个参数在生成验证码图片、图表时会用到,不加在某些环境里会报HeadlessException。-Xms和-Xmx要结合服务器物理内存调整,我的机器是8GB物理内存,-Xms2048m保证启动时快速分配好堆内存,-Xmx4096m给Sakai足够的高峰期缓冲。
5.3 首次启动与初始化
执行启动命令:
cd /usr/local/sakai/bin ./startup.sh第一次启动因为有大量初始化工作(建索引、缓存预热),可能会慢一些,一两分钟没输出完全正常。看日志确认启动成功的标志是类似这样的行:
INFO: Server startup in [xxxxx] milliseconds出现Server startup且没有ERROR,就可以打开浏览器访问http://你的服务器IP:8080了。第一次访问会看到Sakai的默认首页,用系统默认管理员账号(一般是admin,初始密码在导入SQL脚本中定义了,通常是admin,但强烈建议登录后立刻修改)登录。
6. Nginx反向代理与HTTPS:让Sakai真正对外可用
6.1 为什么必须要加一层反向代理
Sakai 20.0的Tomcat默认裸露在8080端口,直接用IP和端口访问虽然能通,但存在三个问题:一是浏览器会提示不安全(没有HTTPS);二是学校网络环境下防火墙通常只放行80和443端口,8080在外部不可达;三是Tomcat对大量静态资源的并发处理能力不如Nginx。所以外层加一个Nginx反向代理是生产部署的标准姿势。
6.2 Nginx配置实战
安装Nginx之后,在/etc/nginx/conf.d/sakai.conf里新增如下配置:
server { listen 80; server_name learn.youruniversity.edu.cn; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name learn.youruniversity.edu.cn; ssl_certificate /etc/nginx/ssl/your_cert.pem; ssl_certificate_key /etc/nginx/ssl/your_cert.key; client_max_body_size 1000m; location / { proxy_pass http://127.0.0.1:8080; 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-Proto $scheme; proxy_connect_timeout 60s; proxy_read_timeout 300s; proxy_send_timeout 300s; } }client_max_body_size这条要特别留意。Sakai里学生上传大附件是常态,默认Nginx只允许1MB左右的上传体积,不调大这个参数,用户一传稍大点的文件就会收到413错误。我这里设置成1000m,实际根据你服务器的存储和带宽调整。
proxy_read_timeout设成300秒是为了防止长时间请求(比如导入课程备份)被Nginx提前掐断。Sakai里某些管理操作耗时较长,默认60秒的代理超时会造成前端“操作中心”的任务在后台执行完成后,页面却报504的假失败,排查起来非常迷惑。
配置完成后记得:
nginx -t systemctl reload nginx同时在sakai.properties里把server.url改成HTTPS开头的对外域名,避免页面上出现混合内容提示。
7. 部署中高频踩坑与排查方法:直接照单抓药
7.1 “页面转圈半天,最后报500”的排查套路
Sakai部署完成打开首页,最常遇到的就是白屏转圈然后500。你先分清是“前端无法到达服务”还是“后端抛异常”。方法很简单,直接访问http://IP:8080(绕过Nginx),看能不能出页面。如果直接访问也不通,就是Tomcat没起来或端口被占用;如果直连能通但经Nginx不通,问题在Nginx配置。
Tomcat端口占用有一个独家排查技巧:
lsof -i:8080如果有大量TIME_WAIT连接占着端口,稍微等一下或者重启Tomcat都能解决;如果是LISTEN状态但不是java进程,那就说明有别的服务抢占了8080,直接改掉server.xml端口更省心。
7.2 数据库连接失败:一篇分清是驱动、账号还是网络问题
数据库连接失败是Sakai部署里出现频率最高的报错之一,日志里常见的几种提示要会区分。
第一种:Access denied for user 'sakai'@'localhost'——这是账号权限或密码不对,重新用mysql -u sakai -p'YourStrongPassword' -e "USE sakai; SELECT 1;"验证一遍即可。
第二种:Could not create connection to database server——这种通常是MySQL服务没启动,systemctl status mysqld看一眼就知道。
第三种:Unknown database 'sakai'——这是初始化脚本没导入,返回5.1节把SQL脚本跑一遍。
第四种值得单独提:Public Key Retrieval is not allowed。这个报错在MySQL 8.0及以上版本常见,因为默认用了caching_sha2_password认证。解决方案就是在JDBC URL里加allowPublicKeyRetrieval=true&useSSL=false,5.7一般遇不到,但如果你后面升级数据库版本,这个经验直接用得上。
7.3 文件上传/下载异常的定位思路
Sakai里附件功能出问题,大部分是privatePath指向的目录没有写权限。用ps aux | grep tomcat查看当前进程的运行用户,然后用chown -R sakaiUser:sakaiUser /usr/local/sakai/files把目录属主改对,顺便确认目录磁盘空间。
另外,Nginx层如果报413,那是client_max_body_size不够大;如果报504,多半是proxy_read_timeout太短。这些错误在Nginx的error.log里都会有记录,看日志比猜快得多。
7.4 启动卡在“Deploying web application archive”的终极耐心方案
Tomcat第一次启动Sakai时,因为要解压并部署整个WAR包(体积通常在几百MB),日志会长时间停在Deploying web application archive sakai-tomcat...这一行。很多朋友这时候以为卡死了,其实只是慢。我的建议是不要反复startup.sh和shutdown.sh来回折腾,否则极易把部署锁搞坏,出现“undeploy失败”的异常。
判断是否真卡死,看CPU:用top看java进程的CPU占用率,如果是持续高CPU,说明还在解压部署,耐心等;如果CPU完全闲着日志也不动,那可能是锁了,关掉进程后删除/usr/local/sakai/work/Catalina/localhost下的缓存目录再重启。
8. 安全加固与日常维护经验
8.1 修掉默认密码和管理后台的暴露
Sakai 20.0部署完,第一件要紧事就是改掉默认管理员密码。默认admin账号的初始密码在官方文档里都有,不换等于把大门敞开。另外,Sakai的管理员操作入口和普通用户登录页面虽然走同一套路径,但强烈建议对/admin这类管理路径做额外的Nginx访问控制,比如限定只能从校园网内网IP访问,外人一律403。
8.2 数据库定时备份方案
Sakai里存量数据就是学校的教学资产,一旦丢了非常麻烦。我建议用系统定时任务每天做一次逻辑备份:
mysqldump -u sakai -p'YourStrongPassword' sakai --default-character-set=utf8mb4 > /backup/sakai_$(date +%Y%m%d).sql配合日志轮转,保留最近7天的备份文件即可。恢复的话也很直接:
mysql -u sakai -p'YourStrongPassword' sakai < /backup/sakai_20250204.sql8.3 升级路线与版本兼容提醒
目前Sakai 20.0之后已经迭代出更高的版本,如果后续要升级,务必先读对应版本的升级说明。多数情况需要先停服务、备份数据库、替换安装包,再执行增量升级脚本。唯一要提醒的是——别跨大版本直接跳,比如从20.0一步跨到很新的版本,其中间可能有数据结构变动,一次性跨越大概率出问题,按官方给的路径一步步走才稳。
9. 部署完成后的自测清单:这几件事没做等于白装
部署不能以页面能打开作为成功标准。我习惯按下面这份清单逐项过一遍,全部通过才算收工。
首先是用户登录链路。用管理员账号登录后台,再创建测试账号走一遍完整登录流程,确认权限分配、首页布局没问题。
其次是核心功能链路。创建一门测试课程,加入测试学生账号,上传一份附件,再以学生视角下载附件,同时发一篇论坛帖子、提交一次作业,看整条学习路径是否顺畅。
第三是多媒体与文件上传。传一个稍大点的文件(比如20MB以上的视频或压缩包),确认Nginx和Tomcat两层都没有超时或413错误。
第四是重启自恢复。执行一次/usr/local/sakai/bin/shutdown.sh,然后startup.sh,确认服务能正常拉起,数据库连接、文件目录权限这些都自动就位。这一步能提前暴露很多“开机自启服务没配好”的坑。
最后是访问日志抽查。打开/usr/local/sakai/logs/sakai.log,看有没有周期性刷出的异常堆栈。很多问题不是部署时爆发,而是运行一两天才出现,提前把日志看住,后面能少熬夜。
10. 写在最后的小经验
Sakai 20.0的部署,本质上是一个“把Java应用、数据库、文件系统、反向代理四样东西理顺”的过程。我在实际部署中最大的体会是:Sakai的部署难点不在某个单点,而在组件之间的协作细节——字符集、内存参数、路径权限、代理超时,任何一环出了偏差,都会让你在用户端看到一个莫名其妙的问题。
如果你也是第一次部署Sakai,我的建议是:先在一台测试机上完整走通一遍,把每一步的日志、参数、报错都记录清楚,再上生产。不要试图跳过数据库初始化直接启动,不要省掉Nginx那一层,更不要用默认密码上线。按照前面这些步骤一步步来,Sakai 20.0是可以做到“装好即稳”的。后面如果遇到具体的报错,欢迎在评论区把日志贴出来,我也很乐意一起分析。