oimaster
2022-06-27 11:23:16
声明:在洛谷博客中,shell
、 yml
、mysql
的高亮支持并不好。美元符号因为有 Bug 所以无法显示,于是在本文中所有的美元符号被换成了人民币¥(日元也行,同样符号)。
我支持洛谷。遗憾的是,洛谷在写这篇文章的时候还没有开源,于是,我们无法搭建以洛谷驱动的 OJ。
欢迎大家在评论区中留下文章的勘误等问题。我会挑选一些放在正文中。
以下是正文。
最近,想要在自己的服务器上搭建一个 OJ。在 Github 上搜索一下,各种各样的 OJ 到处都是。
最终,我选择了 SYZOJ。上过 LOJ 的应该都知道,SYZOJ 的 UI 特别好看。如果有时间的话,的确可以自己挑别的 OJ 系统二次开发一个 Semantic UI(SYZOJ 的 UI 框架)的界面,不过直接装 SYZOJ 肯定更让人舒服。
另外,虽然 HUSTOJ 最近推出了 SYZOJ 的主题,但是我认为还是有少些地方(提交记录)不太像。
很高兴看到您们的评论。
LOJ 曾经由 SYZOJ 驱动,现在由 Lyrio(aka. SYZOJ-NG,大概是指 SYZOJ New Generation?) 驱动。对于 LOJ 的老用户,能知道 SYZOJ 的 UI。
实际上,Lyrio 和 SYZOJ 均使用了 Semantic UI 框架,整体感官没多大区别。不过,从组件的位置以及一些新功能来看,区别还是蛮大的(例如题目页面)。
SYZOJ 的部署指南曾经十分详细,但是大概一年前突然又删掉了很多。那么为了方便大家部署,我就在这片博客里写一点指南。
我会尽可能将文章写得易懂,傻瓜也能部署的级别。
这一步实际上对于大部分人来说是最困难的
很高兴看到您的评论 @planet_over_for_ever。
由于 Freenom 不稳定,时间会导致具体方法变化。请您自行搜索。
SYZOJ 的 docker 容器不知道为什么,我的服务器安装出现了错误。我认为自己配置一步一步安装更加保守,且易于开发。
让我们开始吧。以下所有命令都需要使用 root
权限执行。您可以在每条命令前面加上 sudo
,也可以使用 sudo su
来切换到 root
账户。
很高兴看到您的评论。@HelloOS
您也可以使用
su
命令切换到root
。这两条命令的区别在于,sudo su
是当前用户暂时切换到root
,需要输入当前用户密码。su
是切换到root
账号,需要输入root
密码。
首先,您需要运行下面的命令来安装 Node.js 16、Yarn 1、MariaDB 10.3 与 Redis 5 等工具。这些可以在文档中找到。
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
curl -fsSL https://deb.nodesource.com/setup_current.x | bash -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
apt install -y software-properties-common
add-apt-repository 'deb [arch=amd64,arm64,ppc64el] http://mirrors.tuna.tsinghua.edu.cn/mariadb/repo/10.3/ubuntu focal main'
add-apt-repository ppa:chris-lea/redis-server # Ubuntu 20.04(22.04) 不需要执行这条
apt update
apt install -y git mariadb-server redis-server nodejs yarn p7zip-full clang-format
基于文章发布时已经有了 Ubuntu 22.04,我专门做了一次测试。没有问题。如果有疑问可以私信我或者评论。
注意:安装时会出现让您填写数据库初始密码的界面,请直接按回车跳过。
接下来,下载文件。境内的服务器可能会略微有点慢,不过速度总体还行。
rm -rf /opt/syzoj /etc/systemd/system/syzoj*
mkdir -p /opt/syzoj
cd /opt/syzoj
git clone https://github.com/syzoj/syzoj web
cd web
yarn
接下来,我们要创建配置。
mkdir -p /opt/syzoj/config
cp /opt/syzoj/web/config-example.json /opt/syzoj/config/web.json
ln -s ../config/web.json /opt/syzoj/web/config.json
接下来,您需要编辑一下配置。首先,让我们打开这个文件。
vim /opt/syzoj/web/config.json
打开后,您需要修改的有:
title
:这个我认为大部分人都自己会改(^-^);session_secret
:这个请填一个随机字符串;judge_token
:这个也填一个随机字符串,但是以后部署评测机时候要用,所以请记下来;db
:在其中 password
的地方填一个随机字符串,这个马上安装数据库的时候也要用,请记录下来。另外,生成随机字符串的快捷指令是 echo ¥(dd if=/dev/urandom | base64 -w0 | dd bs=1 count=20 2>/dev/null)
,如果遇到了困难可以请服务器随机生成。
接下来,要创建一些存储临时文件(如 session)和数据(如上传的文件)的文件夹。
mv /opt/syzoj/web/uploads /opt/syzoj/data
ln -s ../data /opt/syzoj/web/uploads
mkdir /opt/syzoj/sessions
ln -s ../sessions /opt/syzoj/web/sessions
因为以 root
账户运行网页端特别不安全,所以我们需要创建 syzoj 账户。
adduser --disabled-password --gecos "" syzoj # 以用户名 syzoj 为例
但是此时的网页端还无法读取到我们刚才创建的几个目录,我们要加上权限。
chown -R syzoj:syzoj /opt/syzoj/data /opt/syzoj/sessions /opt/syzoj/config/web.json
从这里开始,SYZOJ 的官方 Wiki 就开始省略了……不过没关系。
首先,让我们进入数据库。请运行 mysql
。如果您第一步时使用了密码,那么请自己修改命令连接数据库。
然后创建数据库。
CREATE DATABASE `syzoj` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
接下来,我们要赋予权限。请把 <password>
替换成您在配置文件步骤中填在 db
的随机字符串。
GRANT ALL PRIVILEGES ON `syzoj`.* TO "syzoj"@"localhost" IDENTIFIED BY "<password>";
FLUSH PRIVILEGES;
现在,我们已经完成了配置,让我们启动服务!这一段的官方文档写得及其简陋,也是卡掉了大部分安装 SYZOJ 的玩家。
首先,让我们创建并编辑服务文件。请使用您喜欢的编辑器。我在这里使用 Vim。
vim /etc/systemd/system/syzoj-web.service
如果是 Vim 的话,按下 i
键进入插入模式,然后粘贴这些内容。
[Unit]
Description=SYZOJ web service
After=network.target mysql.service rc-local.service
Requires=mysql.service rc-local.service
[Service]
Type=simple
WorkingDirectory=/opt/syzoj/web
User=syzoj
Group=syzoj
ExecStart=/usr/bin/env NODE_ENV=production /usr/bin/node /opt/syzoj/web/app.js -c /opt/syzoj/config/web.json
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
按下 ESC
,输入 :wq
,按下 Enter
,退出,启动它。
systemctl start syzoj-web.service
记得设为开机自启。
systemctl enable syzoj-web.service
此时,访问网站是没有作用的。我们需要 Nginx 反向代理。
在配置 Nginx 之前,请保证您的域名通过 A 解析到了您的服务器。
不要急!先安装 Nginx。
apt install -y nginx
然后创建并编辑配置文件。
vim /etc/nginx/sites-enabled/syzoj
请输入以下内容。
map ¥http_upgrade ¥connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name oimasterakioi.com;
location / {
proxy_http_version 1.1;
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 Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header Connection ¥connection_upgrade;
proxy_pass http://127.0.0.1:5283;
}
}
请将 oimasterakioi.com
替换成您自己的域名。
接下来,启动服务。
systemctl reload nginx
等待一小会儿,如果之前的步骤全都正确的话,现在应该已经能看到界面了!请立即注册一个账号。
接下来,如果不出意外的话,您应该能看到您的账号 ID 为 1。我们要给它管理员权限。
全站管理员的权限是最高的,为了安全,不能在网页端进行设置。让我们进入数据库。
mysql
然后,赋予其全站管理员权限。
UPDATE `syzoj`.`user` SET `is_admin` = 1 WHERE `id` = 1;
因为 SYZOJ 运行时有缓存(cache),所以修改后的结果并不能直接显现出来。我们需要重启网页端。
systemctl restart syzoj-web.service
接下来,您应该可以进入后台了!现在一切功能都是可以用的,除了——评测机。
跟大部分的 OJ 一样,我们需要打开一些 Linux 内核中不默认开启的特性。首先,请打开 Ubuntu 的默认引导器——Grub 的配置文件。
vim /etc/default/grub
找到 GRUB_CMDLINE_LINUX_DEFAULT
一行,在原有的字符串后面添加 cgroup_enable=memory swapaccount=1 systemd.unified_cgroup_hierarchy=0 syscall.x32=y
。例如,修改完后的结果可能是:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash cgroup_enable=memory swapaccount=1 systemd.unified_cgroup_hierarchy=0 syscall.x32=y"
然后重启修改配置。部分云服务器可能修改完后 VNC 连接很卡,但是 ssh 功能应该是正常的。
update-grub && reboot
这一步境内的服务器很慢,因为包含 SYZOJ 网站端所有的语言支持和 Ubuntu 18.04。境外的服务器大约需要 1-2 分钟左右,国内的服务器可能消耗时间较长。
wget -O /sandbox-rootfs.tar.xz https://github.com/syzoj/sandbox-rootfs/releases/download/210521/sandbox-rootfs-210521.tar.xz
如果服务器在国内,又不愿意卡在这一步,不如使用 screen
或者别的方法进行后台下载。
下载完成后,解压文件。
mkdir -p /opt/syzoj/sandbox/rootfs
cd /opt/syzoj/sandbox/
tar xvf /sandbox-rootfs.tar.xz
然后建立沙箱所需文件夹。
mkdir -p /opt/syzoj/sandbox/{bin,tmp1}
这一段也比较困难,官方文档中描述较少。
先安装几个软件。
apt install build-essential libboost-all-dev
apt install rabbitmq-server redis-server
装 Node.js 10。
mkdir -p /opt/syzoj
wget -O /tmp/node-v10.24.1-linux-x64.tar.xz https://nodejs.org/dist/latest-v10.x/node-v10.24.1-linux-x64.tar.xz
tar xf /tmp/node-v10.24.1-linux-x64.tar.xz -C /tmp
mv /tmp/node-v10.24.1-linux-x64 /opt/syzoj/node10
# 如果没有部署过网站端,则安装 yarn,但是我们刚才部署过了,所以可以跳
PATH=/opt/syzoj/node10/bin:¥PATH /opt/syzoj/node10/bin/npm install yarn -g
没什么好说的。
cd /opt/syzoj
git clone https://github.com/syzoj/judge-v3
mv judge-v3 judge
cd judge
PATH=/opt/syzoj/node10/bin:$PATH yarn
PATH=/opt/syzoj/node10/bin:$PATH yarn build
cd /opt/syzoj
cp judge/daemon-config-example.json config/daemon.json
cp judge/runner-shared-config-example.json config/runner-shared.json
cp judge/runner-instance-config-example.json config/runner-instance.json
然后这里配置文件需要编辑一下。
vim config/daemon.json
其中,ServerToken
请改成在配置网页端时的 judge_token
。
vim /etc/systemd/system/syzoj-judge-daemon.service
填入以下内容。
[Unit]
Description=SYZOJ judge daemon service
After=network.target rabbitmq-server.service redis-server.service
Requires=rabbitmq-server.service redis-server.service
[Service]
Type=simple
WorkingDirectory=/opt/syzoj/judge
User=syzoj
Group=syzoj
ExecStart=/opt/syzoj/node10/bin/node /opt/syzoj/judge/lib/daemon/index.js -c /opt/syzoj/config/daemon.json
[Install]
WantedBy=multi-user.target
退出,注册另一个服务。
vim /etc/systemd/system/syzoj-judge-runner.service
[Unit]
Description=SYZOJ judge runner service
After=network.target rabbitmq-server.service redis-server.service
Requires=rabbitmq-server.service redis-server.service
[Service]
Type=simple
WorkingDirectory=/opt/syzoj/judge
User=root
Group=root
ExecStart=/opt/syzoj/node10/bin/node /opt/syzoj/judge/lib/runner/index.js -s /opt/syzoj/config/runner-shared.json -i /opt/syzoj/config/runner-instance.json
[Install]
WantedBy=multi-user.target
启动它们,并且设置为开机自启。
systemctl start syzoj-judge-runner.service
systemctl enable syzoj-judge-runner.service
systemctl start syzoj-judge-daemon.service
systemctl enable syzoj-judge-daemon.service
恭喜,完成!
从这里开始,就是一些奇奇怪怪、可有可无的功能了。如果想要您的 OJ 更好,不如看看。注意,下面几项难度逐渐增加。
同时因为这是可选功能,所以叙述将会更加简略。
当您公开后,没过多久,就总能看到有心智不成熟的人注册一大堆垃圾账号。
解决办法:邮箱验证。
请自行去您的邮箱平台上打开 SMTP 的功能,并且获取 SMTP 密码。对于部分国外邮箱,这些功能都是默认开启的,且可以直接拿邮箱登录密码进行操作。
以网易邮箱为例子:
进入后,点击新增授权密码,进行验证。其他邮箱同理。
完成后,记录下您的密码,进入网站的 后台管理 - 配置文件,找到 email
,改成
"email": {
"method": "smtp",
"options": {
"host": "smtp.163.com",
"port": 465,
"username": "[email protected]",
"password": "xxx",
"allowUnauthorizedTls": false
}
}
然后将上方 register_mail
改为 true
即可!
历时 3 年,花费 200 万人民币的 Logo 制作完成!现在如何把它摆上去?
简单,让我们上传到服务器,然后进行配置即可。
cd /opt/syzoj/web/static
这里是静态文件目录。将自己的 Logo 上传到这里。为了叙述方便,不妨假设该 Logo 为 xxx.png
接下来同样进入 后台管理 - 配置文件,找到 logo
,改成
"logo": {
"url": "/xxx.png",
"width": xxxxx,
"height": 36
}
为了显示正常,请把 height
改成 36,同时 width
可以等比例缩小。
今日运势的运势类型实在是太少了!我们需要自己添加。
vim /opt/syzoj/web/divine.json
然后用您的 JSON 知识进行添加。如果您不会 JSON,也可以仿照上面的格式。
完成后,重启 SYZOJ web 服务。
对于大多数用户,界面我觉得不用二次开发了。
实际上,SYZOJ 的界面功能较少。您可以按照如下的方案自行开发。
进入 /opt/syzoj/web/views/
,找到对应的文件,进行修改。最后记得重启 web 服务端。
因为谷歌分析代码变化,想要谷歌分析功能的也需要二次开发。
对于一些新功能,您需要在 views
里提供 ejs,并在 modules
文件夹中编辑相应的路由。请自行学习相关语法。
对于部分内容,您需要修改 models
,请自行学习 TypeScript。记得在启动前先进行编译得到 models-built
。
玩砸技巧:新建题目,将题目 ID 设为 10000,然后删除它。接下来再创建一个新题,就会意外地发现新题的 ID 为 10001。
如果了解数据库,就知道显然是 AUTO_INCREMENT
的问题。
假设您现在有效的题目 ID 为
步骤:
delete
命令批量删除,或者是手动在网页端一个一个删alter table problem AUTO_INCREMENT=xxx
,将 xxx
替换成 如果 10000 后面的题目有用,只是想要消除空档,那么请自行学习相关语法。
不过,最好的解决方法是,不要删除题目。
实际上删除题目也是可以的。您可以看到文末的 BetaOJ,提供了一种效率低,但是可重复利用题号的方案。
BetaOJ。
BetaOJ 小黑板功能。
把 models
文件夹中管评测的重写,让它把一个提交记录设为 0
分并且 Skipped
状态(或者别的,您愿意就行)。
一个简单的方法是,把「重测」相关功能 copy 一下,然后在重置提交记录信息后删除「交给评测机评测」相关代码。
如果还有问题,例如如果分布式评测、配置静态资源 CDN 等,请上 官方 Wiki。相信这样的人应该可以读懂了。
BetaOJ 是我稍做了一些改动,仓促写好的。可惜的是,因为有些功能需要更改评测机代码,所以并未公开。
感谢大家的捧场。
特别感谢 & 拜一拜 piggy123 同学。感谢您对我的 OJ 作出的贡献!
感谢前排应援,@MarchKid_Joe @AIMEE11 @Emptyhanded!
为什么您会「泪目」@NotaKoala?应该是我因为您来观看而感动流泪才对。
我看到您的评论。@Milmon
我也算是 Hydro 的老用户了(?)我支持 Hydro 的开发。遗憾的是,在写这篇文章时,Hydro 的功能并不是很丰富。对于数据配置等功能,完全没有任何图形化的帮助。
我希望更多的人能将讨论中心放在 SYZOJ 的搭建上,而不是衡量、比较多个 OJ —— 这不是这里该干的事情。
如果您想要部署 Hydro,可以自行查阅他们的文档。