在Ubuntu建立已運作解題ZSOJ的備份系統

實作DMOJ(版本2.1.0)網站(http://203.68.236.9/)的備份系統

需要備份原來伺服器的資料夾site與資料庫,下方粗體字部分。

系統與Python版本如下

Ubuntu 20.04.1 LTS

Python  3.8

node v16.17.1


(一)安裝DMOJ

Step1)安裝必要套件

$ sudo apt update

$ sudo apt install git gcc g++ make python3-dev python3-pip libxml2-dev libxslt1-dev zlib1g-dev gettext curl redis-server

$ sudo curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -

$ sudo apt install nodejs

$ sudo npm install -g sass postcss-cli postcss autoprefixer


Step2)安裝Mysql資料庫

$ sudo apt install mariadb-server libmysqlclient-dev

設定Mysql資料庫,預設root密碼為空白,直接按下Enter,資料庫帳號為dmoj,需修改<password>為資料庫密碼。

$ mysql -uroot -p

mariadb> CREATE DATABASE dmoj DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;

mariadb> GRANT ALL PRIVILEGES ON dmoj.* to 'dmoj'@'localhost' IDENTIFIED BY '<password>';

mariadb> exit


Step3)建立與啟動Python3的虛擬環境

$  sudo apt install python3-venv

以下指令可以使用登入使用者權限進行安裝,建立在該使用者的家目錄下

$ python3 -m venv dmojsite

$ . dmojsite/bin/activate


Step4)下載程式與資源檔案

使用tar壓縮ZSOJ伺服器上的DMOJ資料夾site,並透過網路傳送到新機器。

(dmojsite) $ cd site

(dmojsite) $ git submodule init

(dmojsite) $ git submodule update


Step5)安裝python所需模組

在ZSOJ伺服器上使用指令「(dmojsite) $ pip freeze > requirements-zsoj.txt」可以備份目前所有套件的版本。

(dmojsite) $ pip3 install -r requirements-zsoj.txt    #安裝所需python套件

若安裝過程出現錯誤,則

(1)可以使用#去除安裝錯誤的套件,之後再補安裝。

(2)或者去除版本號碼,可能該版本已經無法使用。

(3)有時個別安裝可以,全部一起安裝無法安裝,例如dmoj與termcolor套件,最後獨立安裝dmoj即可。

錯誤1:如果出現錯誤 「git clone -q git://github.com/dmoj/django-sortedm2m.git fatal: unable to connect to github.com

在命令模式執行「git config --global url."https://".insteadOf git://」,使用https://取代git://。

錯誤2:如果出現錯誤「error: invalid command ‘bdist_wheel

#pip install wheel

#pip install pyinstaller

錯誤3:如果出現錯誤「fatal error: seccomp.h: No such file or directory

#sudo  apt install libseccomp-dev


(dmojsite) $ pip3 install -r requirements-zsoj.txt   --force    #安裝所需python套件,未完整安裝,後方套件補裝

(dmojsite) $ pip3 install mysqlclient ansi2html  martor lupa webauthn  netaddr


Step6)在dmoj資料夾下新增local_settings.py,下載自https://github.com/DMOJ/docs/blob/master/sample_files/local_settings.py,進行修改,如下,DMOJ的local_settings.py

檢查dmoj目前是否還正常

(dmojsite) $   python3 manage.py check

錯誤1:如果出現錯誤cannot import name '...' from 'jinja2'

安裝django-jinja、markupsafe與Jinja2, 「pip install pip install django-jinja==2.7.0」「pip install markupsafe==2.0.1」「pip install Jinja2==2.11.3」

錯誤2:如果出現錯誤「No module named 'sortedm2m'

安裝django-sortedm2m,「pip install django-sortedm2m」


Step7)收集static資料夾內檔案,static資料夾定義在local_settings.py的「STATIC_ROOT = '/home/jang/site/static/'」,所以建立資料夾/home/jang/site/static

(dmojsite) $ mkdir   /home/jang/site/static

(dmojsite) $ cd /home/jang/site

(dmojsite) $ ./make_style.sh

錯誤1:出現「ReferenceError: globalThis is not defined」重新安裝nodejs。

$ sudo curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -

$ sudo apt install nodejs

$ sudo npm install -g sass postcss-cli postcss autoprefixer

錯誤2:出現以下錯誤unexpected token '.',表示node版本有相容性問題。

安裝node版本控制套件n

$sudo npm install -g n

下載穩定版本的node,筆者安裝node20.11.1版(2024/03/23測試)

$sudo n  lts 

再重新執行「./make_style.sh」


在site資料夾下,重新命名static為static2,並重新建立空資料夾static,執行以下指令將檔案放置於資料夾static

(dmojsite) $ python3 manage.py collectstatic

如果出現「AttributeError: module 'mistune' has no attribute '_pre_tags'」,安裝mistune0.8.0

#pip install mistune==0.8.0


Step8)建立語言檔

(dmojsite) $ python3 manage.py compilemessages

(dmojsite) $ python3 manage.py compilejsi18n


Step9)建立資料庫內的資料表,與備份還原資料庫

(dmojsite) $ python3 manage.py migrate

使用指令「mysqldump -u root -p dmoj > zsoj.sql」備份ZSOJ上的資料庫dmoj

使用指令「mysql -u root -p dmoj < zsoj.sql」還原到新機器的資料庫dmoj


Step10)載入安裝資料

(dmojsite) $ python3 manage.py loaddata navbar

(dmojsite) $ python3 manage.py loaddata language_small

(dmojsite) $ python3 manage.py loaddata demo


Step11)啟用DMOJ

在新機器的dmoj/settings.py的ALLOWED_HOSTS新增主機IP,如右,ALLOWED_HOSTS = ['新機器IP']

(dmojsite) $ python3 manage.py runserver 0.0.0.0:8000

使用瀏覽器瀏覽http://新機器IP:8000/,正常情況應該可以看到DMOJ

不要使用runserver啟用dmoj,改用nginx與uWSGI 


Step12)啟用Bridge,沒出現錯誤就Ctrl+C

(dmojsite) $ python3 manage.py runbridged

如果出現錯誤「OSError: [Errno 99] Cannot assign requested address」表示site/dmoj/local_settings.py的BRIDGED_JUDGE_ADDRESS設定錯誤


Step13)啟用redis與celery,celery是分散式任務處理系統,將需要長時間處理的程式交給其他機器處理,而redis是celery的broker(中間人)與backend(結果儲存)

(dmojsite)   $   sudo service redis-server start

在local_settings.py取消註解CELERY_BROKER_URL與CELERY_RESULT_BACKEND

(dmojsite) $  pip3 install redis

在site資料夾下有dmoj_celery.py,在site資料夾下執行以下指令

(dmojsite) $ celery -A dmoj_celery worker


Step14)設定uWSGI

編輯設定檔uwsgi.ini,如下,檢查是否要修改資料夾路徑

(dmojsite) $    pip3 install uwsgi

(dmojsite) jian@jian:~/site$ uwsgi --ini uwsgi.ini

出現spawned表示正常,使用Ctrl+C中斷


Step15)使用supervisor啟動uwsgi、bridged、celery

(dmojsite) $ sudo apt install supervisor

在/etc/supervisor/conf.d/下建立設定檔site.conf、bridged.conf與celery.conf

site.conf如下,檢查是否要修改資料夾路徑

bridged.conf如下,檢查是否要修改資料夾路徑

celery.conf如下,檢查是否要修改資料夾路徑

使用supervisor啟用uwsgi、bridged、celery,等一下nginx會呼叫使用

(dmojsite)$ sudo supervisorctl update

(dmojsite)$ sudo supervisorctl status

Step16)安裝與設定nginx,使用nginx當成web伺服器,呼叫後方的uwsgi,uwsgi再呼叫django的dmoj套件

(dmojsite) $   sudo  apt install nginx

編輯設定檔/etc/nginx/site-available/default,檢查是否要修改server_name與資料夾路徑

建立超連結sites-enabled/default指向sites-available/default

$ sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default

測試nginx

$sudo nginx  -t

啟動nginx

$service nginx    start

使用瀏覽器瀏覽http://192.168.43.16:8080就可以看到nginx所啟動的DMOJ


如果出現錯誤「Bad Request (400) 」,編輯「site/dmoj/local_setting.py」,在ALLOWED_HOSTS 加入伺服器的IP

Step17)設定event    server,新增/home/jang/site/websocket/config.js如下,在local_settings.py的EVENT_DAEMON_POST、EVENT_DAEMON_GET與EVENT_DAEMON_POLL也需設定,在前面local_settings.py中已經加上。

檢查是否需要在websocket/config.js加上以下資料,已經有了就不加。

(dmojsite) $ cat > websocket/config.js

module.exports = {

    get_host: '127.0.0.1',

    get_port: 15100,

    post_host: '127.0.0.1',

    post_port: 15101,

    http_host: '127.0.0.1',

    http_port: 15102,

    long_poll_timeout: 29000,

};

安裝套件

(dmojsite) $ npm install qu ws simplesets

(dmojsite) $ pip install websocket-client

在supervisor啟動event    server

編輯/etc/supervisor/conf.d/wsevent.conf,如下,檢查是否要修改server_name與資料夾路徑。

Step19)重新啟動服務

$ sudo supervisorctl update

$ sudo supervisorctl restart bridged

$ sudo supervisorctl restart site

$ sudo service nginx restart


Step20)重新建立judge server

請參考「在Ubuntu安裝DMOJ Judge  Server


Step21)修改網站的名稱與IP、連接埠的對應

使用管理者登入DMOJ,點選「Dashboard->網站」編輯網站對應的IP、連接埠


參考資料

https://docs.dmoj.ca/#/site/installation

https://lisz.me/tech/linux/dmoj.html