Homepage: https://lqdoj.edu.vn
Based on DMOJ.
Supported Programming Languages:
- Assembly (x64)
- AWK
- C
- C++03 / C++11 / C++14 / C++17 / C++20 / C++23
- Java
- Pascal
- Perl
- Python 2 / Python 3
- PyPy 2 / PyPy 3
Features:
- Plagiarism detection via Stanford MOSS
- Contest management with various formats
- User rating and performance tracking
- Real-time chat system
- Multi-language support
- Dark/Light theme
- Organization management
Most of the setup follows the same process as DMOJ installations. You can view the installation guide of DMOJ here: https://docs.dmoj.ca/#/site/installation.
The main difference is instead of git clone https://github.com/DMOJ/site.git, you clone this repository: git clone https://github.com/LQDJudge/online-judge.git.
Step 1: Install required libraries
$here means sudo. For example, the first line means runsudo apt update
$ apt update
$ apt install git gcc g++ make python3-dev python3-pip libxml2-dev libxslt1-dev zlib1g-dev gettext curl redis-server pkg-config
$ curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash -
$ apt install nodejs
$ npm install -g sass postcss-cli postcss autoprefixerStep 2: Set up database
- The server currently uses
MariaDB ≥ 10.5, but you can also useMySQLif there are conflicts - If after running the commands below your
MariaDBversion is old (< 10.5), you can Google how to install the latestMariaDB(10.5 or 10.6) - You can check your
MariaDBversion by typingsudo mysql(Ctrl + C to quit)
$ apt update
$ apt install mariadb-server libmysqlclient-devStep 3: Create database tables
- You can change the table name and password
$ sudo mysql
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
$ mariadb-tzinfo-to-sql /usr/share/zoneinfo | sudo mariadb -u root mysqlStep 4: Set up virtual environment and pull code
- If
pip3 install mysqlclientfails, try runningpip3 install mysqlclient==2.1.1
$ python3 -m venv dmojsite
$ . dmojsite/bin/activate
$ git clone https://github.com/LQDJudge/online-judge.git
$ cd online-judge
$ git submodule init
$ git submodule update
$ pip3 install -r requirements.txt
$ pip3 install mysqlclient
$ pre-commit installStep 5: Create local_settings.py
This is the file for customizing Django settings. Create the file at online-judge/dmoj/local_settings.py
- Sample file:
online-judge/dmoj/sample_local_settings.py - If you changed the database table name or password, update the corresponding information in
Databases - After completion, run
python3 manage.py checkto verify
Step 6: Compile CSS and translations
- Commands 1 and 2 should be run after each change to CSS or JS files (HTML files don't require this)
- Commands 3 and 4 should be run after each change to translation files
- Note: After running these commands, the folder corresponding to
STATIC_ROOTinlocal_settings.pymust be created. If it hasn't been created, you need to create that folder before running the first two commands.
$ ./make_style.sh
$ python3 manage.py collectstatic
$ python3 manage.py compilemessages
$ python3 manage.py compilejsi18nStep 7: Add data to database
$ python3 manage.py migrate
$ python3 manage.py loaddata navbar
$ python3 manage.py loaddata language_small
$ python3 manage.py loaddata demoStep 8: Run the site
At this point, the basic setup is complete (without judge, websocket, celery). You can access it at localhost:8000
python3 manage.py runserver 0.0.0.0:8000-
(WSL) You can download the Terminal application from the Windows Store
-
(WSL) Each time you open Ubuntu, you need to run the following command to start MariaDB:
sudo service mysql restart(similar for other services like memcached, celery) -
After installation, you only need to activate the virtual environment and run the runserver command:
. dmojsite/bin/activate python3 manage.py runserver -
For nginx, after configuring according to the DMOJ guide, you need to add the following location to use the profile image feature. Replace
path/to/ojwith the path where you cloned the source code:location /profile_images/ { root /path/to/oj; } -
Development workflow:
- After changing code, Django will automatically rebuild, you just need to press F5
- Some styles are in .scss files. You need to recompile CSS to see changes.
Before running unit tests, create the test database in MariaDB/MySQL:
sudo mariadbCREATE DATABASE test_dmoj DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;
GRANT ALL PRIVILEGES ON test_dmoj.* TO 'dmoj'@'localhost';
FLUSH PRIVILEGES;# Run all tests
python3 manage.py test judge.tests --keepdb
# Run a specific test
python3 manage.py test judge.tests.TestClass.test_method --keepdbYou can save these aliases for faster development:
mtrans: to generate translation when you add a string in codetrans: compile translation (after you've translated to Vietnamese)cr: change to OJ folderpr: run serversm: restart services (mainly for WSL)sd: activate virtual envcss: compile CSS files
alias mtrans='python3 manage.py makemessages -l vi && python3 manage.py makedmojmessages -l vi --no-mark-obsolete'
alias pr='python3 manage.py runserver'
alias sd='source ~/LQDOJ/dmojsite/bin/activate'
alias sm='sudo service mysql restart && sudo service redis-server start && sudo service memcached start'
alias trans='python3 manage.py compilemessages -l vi && python3 manage.py compilejsi18n -l vi'
alias cr='cd ~/LQDOJ/online-judge'
alias css='./make_style.sh && python3 manage.py collectstatic --noinput'Used for in-memory caching:
$ sudo apt install memcachedUsed for live updates (like chat):
-
The WebSocket configuration file
online-judge/websocket/config.jsis already included with default settings. -
Install Node.js dependencies:
$ cd websocket
$ npm install- Add WebSocket settings to
local_settings.py:
# WebSocket daemon settings
EVENT_DAEMON_KEY = 'lqdoj' # Must match backend_auth_token in config.js
EVENT_DAEMON_URL = 'http://127.0.0.1:15100'
EVENT_DAEMON_PUBLIC_URL = 'http://127.0.0.1:15100' # Same as EVENT_DAEMON_URL in development
# For production with SSL/domain
# EVENT_DAEMON_PUBLIC_URL = 'wss://your-domain.com' # nginx proxies to port 15100- Start (in a separate tab)
$ node websocket/daemon.jsProduction Deployment:
For nginx, add this location block:
location /socket.io/ {
proxy_pass http://127.0.0.1:15100/socket.io/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}Used for background tasks like batch rejudging, AI processing, moderation, and scheduled maintenance. Run both a worker and beat in production:
celery -A dmoj_celery worker
celery -A dmoj_celery beatInstall in a separate folder outside the site:
$ apt install python3-dev python3-pip build-essential libseccomp-dev
$ git clone https://github.com/LQDJudge/judge-server.git
$ cd judge-server
$ sudo pip3 install -e .- Create a
judge.ymlfile outside the judge-server folder (sample file: https://github.com/DMOJ/docs/blob/master/sample_files/judge_conf.yml) - Add judge to site via UI: Admin → Judge → Add Judge → enter id and key (only need to add once) or use command
python3 manage.py addjudge <id> <key> - Run Bridge (connection between judge and site) in a separate tab in the online-judge folder:
$ python3 manage.py runbridged- Start Judge (in a separate tab):
$ dmoj -c judge.yml localhost- Note: Each time you want to run judges later, open 1 tab for bridge and n tabs for judges. Each judge needs a different yml file (containing different authentication)
For running judges on multiple servers, you can use JuiceFS to share problem data across machines via a POSIX-compatible distributed filesystem backed by S3/R2. See docs/juicefs-setup.md for the full setup guide.
-
Missing
local_settings.py: You need to copy thelocal_settings.pyin order to pass the check. -
Missing problem folder in
local_settings.py: You need to create a folder to contain all problem packages and configure inlocal_settings.py. -
Missing static folder in
local_settings.py: Similar to problem folder, make sure to configureSTATIC_FILESinsidelocal_settings.py. -
Missing configure file for judges: Each judge must have a separate configure file. To create this file, you can run
dmoj-autoconf. Check out all sample files here: https://github.com/DMOJ/docs/blob/master/sample_files. -
Missing timezone data for SQL: If you're using Ubuntu and following DMOJ's installation guide for the server, and you get the error mentioned in #45, then you can follow this method to fix:
# You may have to do this if you haven't set root password for MySQL, replace mypass with your password # SET PASSWORD FOR 'root'@'localhost' = PASSWORD('mypass'); # FLUSH PRIVILEGES; mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -D mysql -u root -p mysql -u root -p -e "flush tables;" mysql
After finishing all installation steps, every time you want to run a local server, follow these steps:
-
Activate virtual environment:
source dmojsite/bin/activate -
Run server:
python3 manage.py runserver 0.0.0.0:8000
-
Create a bridge (open in a different terminal if using the same machine)
python3 manage.py runbridged
-
Create a judge (another terminal)
dmoj 0.0.0.0 -p 9999 -c <path to yml configure file>
Here we assume you use the default port
9999for bridge insettings.py. You can create multiple judges, each should be in a separate terminal.
-
Run celery worker (server's queue, may be necessary for some functions)
celery -A dmoj_celery worker
-
Run live event server (for real-time updates like in production)
node websocket/daemon.js
-
To use subdomain for each organization: Go to admin page → navigation bar → sites, add domain name (e.g.,
localhost:8000). Then addUSE_SUBDOMAIN = Truetolocal_settings.py.
Most steps are similar to standard Django tutorials. Here are two common operations:
- If you add any new phrases in the code:
python3 manage.py makemessages - Go to
locale/vi - Modify
.pofile python3 manage.py compilemessagespython3 manage.py compilejsi18n
- Change
.css/.scssfiles inresourcesfolder ./make_style.sh && python3 manage.py collectstatic- Sometimes you need to press
Ctrl + F5to see the new user interface in browser
This section covers deploying LQDOJ to a production server. The setup uses Nginx as a reverse proxy, uWSGI as the application server, Supervisor to manage processes, and Docker for the bridge and judges.
It is assumed you have completed the Installation steps (database, virtualenv, code, migrations, static files) on your production server, and that services like Memcached, Redis, Celery, and WebSocket are configured as described in Optional Components.
Edit local_settings.py for production:
# SECURITY: disable debug mode
DEBUG = False
# Generate a strong secret key:
# python3 -c 'from django.core.management.utils import get_random_secret_key;print(get_random_secret_key())'
SECRET_KEY = '<your generated secret key>'
# Optional: SSL settings (uncomment if using HTTPS)
# DMOJ_SSL = 2
# SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# SECURE_SSL_REDIRECT = True
# SESSION_COOKIE_SECURE = True
# CSRF_COOKIE_SECURE = True
# Database - use 127.0.0.1 (not localhost) to force TCP connection.
# This is required for the Docker bridge to connect to the database.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'dmoj',
'USER': 'dmoj',
'PASSWORD': '<your password>',
'HOST': '127.0.0.1',
'OPTIONS': {
'charset': 'utf8mb4',
'sql_mode': 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION',
},
},
}
# Bridge - bind to 0.0.0.0 so Docker judges can connect
BRIDGED_JUDGE_ADDRESS = [('0.0.0.0', 9999)]
BRIDGED_DJANGO_ADDRESS = [('localhost', 9998)]Make sure the required services are installed and running:
sudo apt install memcached redis-server
sudo systemctl enable memcached redis-server
sudo systemctl start memcached redis-serverRecommended MariaDB production safeguards for web-only database connections:
# Add these inside the existing [mariadbd] or [mysqld] section in:
# /etc/mysql/mariadb.conf.d/50-server.cnf
innodb_ft_min_token_size = 2
max_statement_time = 8
idle_transaction_timeout = 30
idle_write_transaction_timeout = 15
idle_readonly_transaction_timeout = 30max_statement_time prevents unexpectedly expensive statements from running too long. The idle transaction timeouts prevent sleeping web connections from holding row locks indefinitely. After editing the config, validate and restart MariaDB:
sudo mariadbd --validate-config
sudo systemctl restart mariadb
sudo mariadb dmoj -e "SHOW GLOBAL VARIABLES WHERE Variable_name IN ('innodb_ft_min_token_size', 'max_statement_time', 'idle_transaction_timeout', 'idle_write_transaction_timeout', 'idle_readonly_transaction_timeout');"For migrations or maintenance commands that legitimately need longer database work, override the limit for that session instead of changing the global default:
SET SESSION max_statement_time = 0;Install uWSGI inside the virtualenv:
(dmojsite) $ pip3 install uwsgiCopy sample_conf/uwsgi.ini to the site root directory and adjust the paths. Test with:
(dmojsite) $ uwsgi --ini uwsgi.iniInstall Supervisor:
sudo apt install supervisorCopy the sample configs from sample_conf/supervisor/ to /etc/supervisor/conf.d/ and adjust the paths:
site.conf— Django application server (uWSGI)celery.conf— Background task workerwsevent.conf— WebSocket event server
Then load and start all services:
sudo supervisorctl update
sudo supervisorctl statusInstall Nginx:
sudo apt install nginxCopy sample_conf/nginx/nginx.conf to /etc/nginx/conf.d/ and adjust the paths. Then test and reload:
sudo nginx -t
sudo systemctl reload nginxIf you get 403 errors on static files, nginx (running as www-data) likely can't traverse your home directory. Fix with:
chmod o+x /home/<user> /path/to/static /path/to/mediasudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d <your domain>Certbot will automatically modify the Nginx config to add SSL. If you enable SSL, uncomment the SSL settings in local_settings.py (see Pre-deployment Configuration).
LQDOJ runs the bridge in Docker (instead of Supervisor as in standard DMOJ). The Docker files are in .docker/bridge/.
Build the bridge image (run from the parent of the online-judge directory):
.docker/bridge/build.shStart the bridge:
.docker/bridge/run.shThe bridge uses --network=host so it can connect to the host's database on 127.0.0.1 and be reachable by judges on port 9999.
Verify the bridge is running:
docker logs bridgeLQDOJ uses Docker-based judges built from the DMOJ judge-server. Scripts are in .docker/judge/.
Clone the judge-server repo alongside the online-judge directory (if not already done):
git clone https://github.com/LQDJudge/judge-server.gitThen build the Docker image:
.docker/judge/build_image.shBy default the script looks for judge-server/ next to online-judge/. Set JUDGE_SERVER_DIR to override.
Tip: The full
tierlqdojimage includes all runtimes and takes a long time to build. For a quick start, you can buildtier1instead (Python 2/3, C/C++, Java 8, Pascal):cd judge-server/.docker && make judge-tier1Then set
JUDGE_IMAGE=vnoj/judge-tier1:latestwhen running judges.
Register judges in the site database (run from the online-judge directory with virtualenv activated):
.docker/judge/register_judges.sh 1 10 '<authentication key>'This registers judge1 through judge10 with the given key. You can also add judges via the admin panel: Admin -> Judges -> Add Judge.
Create a config file in your problems directory (e.g., /mnt/problems/__conf__/general.yml). A full sample is at sample_conf/judge.yml. The judge name is passed via the command line, so the config only needs the key and paths:
key: '<authentication key>'
problem_storage_globs:
- /problems/**/
# All configuration for language executors.
# If you're unsure of what values a language needs, consult the source of the executor:
# <https://github.com/DMOJ/judge/tree/master/dmoj/executors>
runtime:
g++: /usr/bin/g++
gcc: /usr/bin/gcc
fpc: /usr/bin/fpc
java: /usr/lib/jvm/java-25-openjdk-amd64/bin/java
javac: /usr/lib/jvm/java-25-openjdk-amd64/bin/javac
python3: /usr/bin/python3
pypy3: /opt/pypy3/bin/pypy3
# ... add more runtimes as neededNote: the problem_storage_globs uses /problems/ because that's the mount point inside the Docker container.
Set PROBLEMS_DIR to your problems directory before running judges:
export PROBLEMS_DIR=/path/to/problemsStart a single judge:
.docker/judge/start_judge.sh judge1Start multiple judges at once:
.docker/judge/start_judges.sh 1 5This starts judge1 through judge5. Each judge runs in its own Docker container with --network=host.
Verify judges are connected in Admin -> Judges — they should appear as online.
Make sure port 9999 is open on the site server's firewall. For sharing problem data across multiple servers, see Distributed Judges (JuiceFS).
By default, media files (user uploads, profile images, etc.) are stored on the local filesystem. To use Amazon S3 or S3-compatible storage (e.g., Cloudflare R2) instead:
pip install django-storages[boto3]Then uncomment and configure the S3 section in local_settings.py (see sample_local_settings.py for all options):
AWS_ACCESS_KEY_ID = 'your-access-key'
AWS_SECRET_ACCESS_KEY = 'your-secret-key'
AWS_STORAGE_BUCKET_NAME = 'your-bucket-name'
AWS_S3_REGION_NAME = 'ap-southeast-1'
AWS_S3_CUSTOM_DOMAIN = 'cdn.example.com' # Optional: CloudFront or custom domain
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'No code changes are needed — the codebase uses Django's default_storage abstraction, so all file operations automatically use S3 when configured.
LQDOJ includes a problem recommendation system using collaborative filtering and neural Two Tower models with MariaDB vector search. Requires MariaDB 11.7+.
See judge/ml/README.md for the full setup guide.
Application-level periodic jobs are scheduled in CELERY_BEAT_SCHEDULE in
dmoj/settings.py and require celery -A dmoj_celery beat plus at least one
Celery worker. This includes moderation, notification cleanup, session cleanup,
inactive-account cleanup, score recomputation, contribution recomputation,
organization-private flag sync, and auto-review reapers.
Use cron only for server/infrastructure scripts that should stay outside the Django worker process, such as backups, bridge container restarts, or external ML pipelines. Example production crontab entries:
0 2 * * * /home/ubuntu/backup/backup.sh >> /home/ubuntu/backup/backup.log 2>&1
0 3 * * * /home/ubuntu/cronjobs/ml_gen_data.sh
30 2 * * * /home/ubuntu/bridge/run.sh >> /home/ubuntu/bridge/cron.log 2>&1Nhấp để xem hướng dẫn bằng Tiếng Việt
Trang chủ: https://lqdoj.edu.vn
Dựa trên DMOJ.
Ngôn ngữ lập trình được hỗ trợ:
- Assembly (x64)
- AWK
- C
- C++03 / C++11 / C++14 / C++17 / C++20 / C++23
- Java
- Pascal
- Perl
- Python 2 / Python 3
- PyPy 2 / PyPy 3
Tính năng:
- Phát hiện đạo văn qua Stanford MOSS
- Quản lý cuộc thi với nhiều định dạng khác nhau
- Theo dõi rating và hiệu suất người dùng
- Hệ thống chat thời gian thực
- Hỗ trợ đa ngôn ngữ
- Giao diện sáng/tối
- Quản lý tổ chức
Hầu hết các bước cài đặt giống với DMOJ. Bạn có thể xem hướng dẫn cài đặt DMOJ tại: https://docs.dmoj.ca/#/site/installation.
Điểm khác biệt chính là thay vì git clone https://github.com/DMOJ/site.git, bạn clone repository này: git clone https://github.com/LQDJudge/online-judge.git.
Bước 1: Cài các thư viện cần thiết
$ở đây nghĩa là sudo. Ví dụ dòng đầu nghĩa là chạy lệnhsudo apt update
$ apt update
$ apt install git gcc g++ make python3-dev python3-pip libxml2-dev libxslt1-dev zlib1g-dev gettext curl redis-server pkg-config
$ curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash -
$ apt install nodejs
$ npm install -g sass postcss-cli postcss autoprefixerBước 2: Tạo cơ sở dữ liệu
- Server đang dùng
MariaDB ≥ 10.5, các bạn cũng có thể dùngMySQLnếu bị conflict - Nếu sau khi chạy lệnh dưới mà version
MariaDBbị cũ (< 10.5) thì có thể tra Google cách càiMariaDBmới nhất (10.5 hoặc 10.6) - Các bạn có thể thấy version
MariaDBbằng cách gõ lệnhsudo mysql(Ctrl + C để quit)
$ apt update
$ apt install mariadb-server libmysqlclient-devBước 3: Tạo bảng trong cơ sở dữ liệu
- Các bạn có thể thay tên bảng và mật khẩu
$ sudo mysql
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
$ mariadb-tzinfo-to-sql /usr/share/zoneinfo | sudo mariadb -u root mysqlBước 4: Cài đặt môi trường ảo (virtual env) và pull code
- Nếu
pip3 install mysqlclientbị lỗi thì thử chạypip3 install mysqlclient==2.1.1
$ python3 -m venv dmojsite
$ . dmojsite/bin/activate
$ git clone https://github.com/LQDJudge/online-judge.git
$ cd online-judge
$ git submodule init
$ git submodule update
$ pip3 install -r requirements.txt
$ pip3 install mysqlclient
$ pre-commit installBước 5: Tạo local_settings.py
Đây là file để custom setting cho Django. Các bạn tạo file vào online-judge/dmoj/local_settings.py
- File mẫu:
online-judge/dmoj/sample_local_settings.py - Nếu bạn đổi tên hoặc mật khẩu bảng cơ sở dữ liệu thì thay đổi thông tin tương ứng trong
Databases - Sau khi xong, chạy lệnh
python3 manage.py checkđể kiểm tra
Bước 6: Compile CSS và bản dịch
- Lệnh 1 và 2 gọi sau mỗi lần thay đổi file CSS hoặc file JS (file HTML thì không cần)
- Lệnh 3 và 4 gọi sau mỗi lần thay đổi file dịch
- Note: Sau khi chạy lệnh này, thư mục tương ứng với
STATIC_ROOTtronglocal_settings.pyphải được tạo. Nếu chưa được tạo thì cần tạo thư mục đó trước khi chạy 2 lệnh đầu.
$ ./make_style.sh
$ python3 manage.py collectstatic
$ python3 manage.py compilemessages
$ python3 manage.py compilejsi18nBước 7: Thêm dữ liệu vào cơ sở dữ liệu
$ python3 manage.py migrate
$ python3 manage.py loaddata navbar
$ python3 manage.py loaddata language_small
$ python3 manage.py loaddata demoBước 8: Chạy trang web
Đến đây thì cơ bản đã hoàn thành (chưa có judge, websocket, celery). Các bạn có thể truy cập tại localhost:8000
python3 manage.py runserver 0.0.0.0:8000-
(WSL) Có thể tải ứng dụng Terminal trong Windows Store
-
(WSL) Mỗi lần mở Ubuntu, các bạn cần chạy lệnh sau để MariaDB khởi động:
sudo service mysql restart(tương tự cho một số service khác như memcached, celery) -
Sau khi cài đặt, các bạn chỉ cần activate virtual env và chạy lệnh runserver:
. dmojsite/bin/activate python3 manage.py runserver -
Đối với nginx, sau khi config xong theo guide của DMOJ, bạn cần thêm location như sau để sử dụng được tính năng profile image, thay thế
path/to/ojthành đường dẫn nơi bạn đã clone source code:location /profile_images/ { root /path/to/oj; } -
Quy trình phát triển:
- Sau khi thay đổi code thì Django tự build lại, các bạn chỉ cần F5
- Một số style nằm trong các file .scss. Các bạn cần recompile CSS thì mới thấy được thay đổi.
Trước khi chạy unit test, tạo database test trong MariaDB/MySQL:
sudo mariadbCREATE DATABASE test_dmoj DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;
GRANT ALL PRIVILEGES ON test_dmoj.* TO 'dmoj'@'localhost';
FLUSH PRIVILEGES;# Chạy tất cả test
python3 manage.py test judge.tests --keepdb
# Chạy một test cụ thể
python3 manage.py test judge.tests.TestClass.test_method --keepdbCác bạn có thể lưu các alias này để sau này dùng cho nhanh:
alias mtrans='python3 manage.py makemessages -l vi && python3 manage.py makedmojmessages -l vi --no-mark-obsolete'
alias pr='python3 manage.py runserver'
alias sd='source ~/LQDOJ/dmojsite/bin/activate'
alias sm='sudo service mysql restart && sudo service redis-server start && sudo service memcached start'
alias trans='python3 manage.py compilemessages -l vi && python3 manage.py compilejsi18n -l vi'
alias cr='cd ~/LQDOJ/online-judge'
alias css='./make_style.sh && python3 manage.py collectstatic --noinput'Dùng cho in-memory cache:
$ sudo apt install memcachedDùng để live update (như chat):
-
File cấu hình WebSocket
online-judge/websocket/config.jsđã được bao gồm với cài đặt mặc định. -
Cài các thư viện Node.js:
$ cd websocket
$ npm install- Thêm cài đặt WebSocket vào
local_settings.py:
# WebSocket daemon settings
EVENT_DAEMON_KEY = 'lqdoj' # Phải giống backend_auth_token trong config.js
EVENT_DAEMON_URL = 'http://127.0.0.1:15100'
EVENT_DAEMON_PUBLIC_URL = 'http://127.0.0.1:15100' # Giống EVENT_DAEMON_URL trong development
# Cho production với SSL/domain
# EVENT_DAEMON_PUBLIC_URL = 'wss://your-domain.com' # nginx proxy đến port 15100- Khởi động (trong 1 tab riêng)
$ node websocket/daemon.jsTriển khai Production:
Cho nginx, thêm location block này:
location /socket.io/ {
proxy_pass http://127.0.0.1:15100/socket.io/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}Dùng cho các task nền như batch rejudge, xử lý AI, moderation và maintenance định kỳ. Trên production cần chạy cả worker và beat:
celery -A dmoj_celery worker
celery -A dmoj_celery beatCài đặt ở 1 thư mục riêng bên ngoài site:
$ apt install python3-dev python3-pip build-essential libseccomp-dev
$ git clone https://github.com/LQDJudge/judge-server.git
$ cd judge-server
$ sudo pip3 install -e .- Tạo một file
judge.ymlở bên ngoài thư mục judge-server (file mẫu: https://github.com/DMOJ/docs/blob/master/sample_files/judge_conf.yml) - Thêm judge vào site bằng UI: Admin → Judge → Thêm Judge → nhập id và key (chỉ cần thêm 1 lần) hoặc dùng lệnh
python3 manage.py addjudge <id> <key> - Chạy Bridge (cầu nối giữa judge và site) trong 1 tab riêng trong thư mục online-judge:
$ python3 manage.py runbridged- Khởi động Judge (trong 1 tab riêng):
$ dmoj -c judge.yml localhost- Lưu ý: Mỗi lần sau này muốn chạy judge thì mở 1 tab cho bridge và n tab cho judge. Mỗi judge cần 1 file yml khác nhau (chứa authentication khác nhau)
Để chạy judge trên nhiều server, bạn có thể dùng JuiceFS để chia sẻ dữ liệu bài tập qua hệ thống file phân tán tương thích POSIX, backed bởi S3/R2. Xem docs/juicefs-setup.md để biết chi tiết.
-
Thiếu
local_settings.py: Bạn cần tạo filelocal_settings.pyđể pass được bước check. -
Thiếu thư mục problem trong
local_settings.py: Bạn cần tạo thư mục chứa các gói bài tập và cấu hình tronglocal_settings.py. -
Thiếu thư mục static trong
local_settings.py: Tương tự thư mục problem, đảm bảo cấu hìnhSTATIC_FILEStronglocal_settings.py. -
Thiếu file cấu hình cho judge: Mỗi judge cần một file cấu hình riêng. Để tạo file này, bạn có thể chạy
dmoj-autoconf. Xem tất cả file mẫu tại: https://github.com/DMOJ/docs/blob/master/sample_files. -
Thiếu dữ liệu timezone cho SQL: Nếu bạn dùng Ubuntu và làm theo hướng dẫn cài đặt của DMOJ, gặp lỗi như trong #45, có thể sửa bằng cách:
# Có thể cần đặt mật khẩu root cho MySQL, thay mypass bằng mật khẩu của bạn # SET PASSWORD FOR 'root'@'localhost' = PASSWORD('mypass'); # FLUSH PRIVILEGES; mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -D mysql -u root -p mysql -u root -p -e "flush tables;" mysql
Sau khi hoàn thành cài đặt, mỗi lần muốn chạy server local, làm theo các bước sau:
-
Activate virtual environment:
source dmojsite/bin/activate -
Chạy server:
python3 manage.py runserver 0.0.0.0:8000
-
Chạy bridge (mở terminal khác nếu cùng máy)
python3 manage.py runbridged
-
Chạy judge (terminal khác)
dmoj 0.0.0.0 -p 9999 -c <đường dẫn đến file yml>
Ở đây giả sử bạn dùng port mặc định
9999cho bridge trongsettings.py. Bạn có thể tạo nhiều judge, mỗi judge chạy trong một terminal riêng.
-
Chạy celery worker (hàng đợi tác vụ, cần thiết cho một số chức năng)
celery -A dmoj_celery worker
-
Chạy live event server (cho cập nhật real-time)
node websocket/daemon.js
-
Sử dụng subdomain cho tổ chức: Vào trang admin → navigation bar → sites, thêm tên miền (ví dụ
localhost:8000). Sau đó thêmUSE_SUBDOMAIN = Truevàolocal_settings.py.
Hầu hết các bước tương tự Django tutorials chuẩn. Dưới đây là hai thao tác thường dùng:
- Nếu bạn thêm chuỗi mới trong code:
python3 manage.py makemessages - Vào
locale/vi - Sửa file
.po python3 manage.py compilemessagespython3 manage.py compilejsi18n
- Thay đổi file
.css/.scsstrong thư mụcresources ./make_style.sh && python3 manage.py collectstatic- Đôi khi cần nhấn
Ctrl + F5để thấy giao diện mới trong trình duyệt
Phần này hướng dẫn triển khai LQDOJ lên server production. Hệ thống sử dụng Nginx làm reverse proxy, uWSGI làm application server, Supervisor để quản lý tiến trình, và Docker cho bridge và judge.
Giả sử bạn đã hoàn thành các bước Cài đặt (database, virtualenv, code, migration, static files) trên server production, và các dịch vụ như Memcached, Redis, Celery, WebSocket đã được cấu hình như mô tả trong Các thành phần tùy chọn.
Chỉnh sửa local_settings.py cho production:
# BẢO MẬT: tắt chế độ debug
DEBUG = False
# Tạo secret key mạnh:
# python3 -c 'from django.core.management.utils import get_random_secret_key;print(get_random_secret_key())'
SECRET_KEY = '<secret key của bạn>'
# Tùy chọn: cài đặt SSL (bỏ comment nếu dùng HTTPS)
# DMOJ_SSL = 2
# SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# SECURE_SSL_REDIRECT = True
# SESSION_COOKIE_SECURE = True
# CSRF_COOKIE_SECURE = True
# Database - dùng 127.0.0.1 (không dùng localhost) để buộc kết nối TCP.
# Cần thiết để Docker bridge kết nối được đến database.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'dmoj',
'USER': 'dmoj',
'PASSWORD': '<mật khẩu>',
'HOST': '127.0.0.1',
'OPTIONS': {
'charset': 'utf8mb4',
'sql_mode': 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION',
},
},
}
# Bridge - bind 0.0.0.0 để Docker judge có thể kết nối
BRIDGED_JUDGE_ADDRESS = [('0.0.0.0', 9999)]
BRIDGED_DJANGO_ADDRESS = [('localhost', 9998)]Đảm bảo các dịch vụ cần thiết đã được cài và chạy:
sudo apt install memcached redis-server
sudo systemctl enable memcached redis-server
sudo systemctl start memcached redis-serverCấu hình MariaDB khuyến nghị cho production khi database chỉ phục vụ web:
# Thêm các dòng này vào section [mariadbd] hoặc [mysqld] có sẵn trong:
# /etc/mysql/mariadb.conf.d/50-server.cnf
innodb_ft_min_token_size = 2
max_statement_time = 8
idle_transaction_timeout = 30
idle_write_transaction_timeout = 15
idle_readonly_transaction_timeout = 30max_statement_time chặn các câu SQL bất thường chạy quá lâu. Các timeout idle_*_transaction_timeout tránh việc connection web đang ngủ nhưng vẫn giữ row lock quá lâu. Sau khi sửa config, kiểm tra và restart MariaDB:
sudo mariadbd --validate-config
sudo systemctl restart mariadb
sudo mariadb dmoj -e "SHOW GLOBAL VARIABLES WHERE Variable_name IN ('innodb_ft_min_token_size', 'max_statement_time', 'idle_transaction_timeout', 'idle_write_transaction_timeout', 'idle_readonly_transaction_timeout');"Với migration hoặc lệnh maintenance cần chạy database lâu hơn bình thường, override theo session thay vì đổi global default:
SET SESSION max_statement_time = 0;Cài uWSGI trong virtualenv:
(dmojsite) $ pip3 install uwsgiCopy sample_conf/uwsgi.ini vào thư mục gốc của site và chỉnh sửa đường dẫn. Test bằng:
(dmojsite) $ uwsgi --ini uwsgi.iniCài Supervisor:
sudo apt install supervisorCopy các file cấu hình mẫu từ sample_conf/supervisor/ vào /etc/supervisor/conf.d/ và chỉnh sửa đường dẫn:
site.conf— Django application server (uWSGI)celery.conf— Worker xử lý tác vụ nềnwsevent.conf— WebSocket event server
Sau đó load và khởi động:
sudo supervisorctl update
sudo supervisorctl statusCài Nginx:
sudo apt install nginxCopy sample_conf/nginx/nginx.conf vào /etc/nginx/conf.d/ và chỉnh sửa đường dẫn. Sau đó test và reload:
sudo nginx -t
sudo systemctl reload nginxNếu gặp lỗi 403 với static files, nginx (chạy dưới user www-data) có thể không đọc được thư mục home. Sửa bằng:
chmod o+x /home/<user> /path/to/static /path/to/mediasudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d <domain của bạn>Certbot sẽ tự động chỉnh sửa cấu hình Nginx để thêm SSL. Nếu bật SSL, bỏ comment các cài đặt SSL trong local_settings.py.
LQDOJ chạy bridge trong Docker (thay vì Supervisor như DMOJ chuẩn). Các file Docker nằm trong .docker/bridge/.
Build image:
.docker/bridge/build.shKhởi động bridge:
.docker/bridge/run.shBridge sử dụng --network=host để kết nối đến database trên host (127.0.0.1) và để judge kết nối được qua port 9999.
Kiểm tra bridge đang chạy:
docker logs bridgeLQDOJ sử dụng judge chạy trên Docker từ DMOJ judge-server. Các script nằm trong .docker/judge/.
Clone repo judge-server cạnh thư mục online-judge (nếu chưa có):
git clone https://github.com/LQDJudge/judge-server.gitBuild Docker image:
.docker/judge/build_image.shMặc định script tìm judge-server/ cạnh online-judge/. Đặt JUDGE_SERVER_DIR để thay đổi.
Mẹo: Image
tierlqdojđầy đủ chứa tất cả runtime và build rất lâu. Để test nhanh, có thể buildtier1(Python 2/3, C/C++, Java 8, Pascal):cd judge-server/.docker && make judge-tier1Sau đó đặt
JUDGE_IMAGE=vnoj/judge-tier1:latestkhi chạy judge.
Đăng ký judge vào database (chạy từ thư mục online-judge với virtualenv đã activate):
.docker/judge/register_judges.sh 1 10 '<authentication key>'Lệnh trên đăng ký judge1 đến judge10. Bạn cũng có thể thêm qua admin: Admin -> Judges -> Add Judge.
Tạo file cấu hình trong thư mục problems (ví dụ: /mnt/problems/__conf__/general.yml). File mẫu đầy đủ tại sample_conf/judge.yml. Tên judge được truyền qua command line, nên file cấu hình chỉ cần key và đường dẫn:
key: '<authentication key>'
problem_storage_globs:
- /problems/**/
runtime:
g++: /usr/bin/g++
gcc: /usr/bin/gcc
python3: /usr/bin/python3
# ... thêm runtime khác theo nhu cầuLưu ý: problem_storage_globs dùng /problems/ vì đó là mount point bên trong Docker container.
Đặt PROBLEMS_DIR trỏ đến thư mục problems trước khi chạy:
export PROBLEMS_DIR=/path/to/problemsKhởi động một judge:
.docker/judge/start_judge.sh judge1Khởi động nhiều judge cùng lúc:
.docker/judge/start_judges.sh 1 5Kiểm tra judge đã kết nối trong Admin -> Judges — judge sẽ hiển thị trạng thái online.
Đảm bảo port 9999 mở trên firewall của server site. Để chia sẻ dữ liệu bài tập giữa nhiều server, xem Distributed Judges (JuiceFS).
Mặc định, media files được lưu trên filesystem local. Để dùng Amazon S3 hoặc storage tương thích S3 (ví dụ Cloudflare R2):
pip install django-storages[boto3]Bỏ comment và cấu hình phần S3 trong local_settings.py (xem sample_local_settings.py để biết tất cả tùy chọn):
AWS_ACCESS_KEY_ID = 'your-access-key'
AWS_SECRET_ACCESS_KEY = 'your-secret-key'
AWS_STORAGE_BUCKET_NAME = 'your-bucket-name'
AWS_S3_REGION_NAME = 'ap-southeast-1'
AWS_S3_CUSTOM_DOMAIN = 'cdn.example.com'
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'Không cần thay đổi code — codebase sử dụng default_storage của Django nên mọi thao tác file tự động dùng S3 khi được cấu hình.
LQDOJ có hệ thống gợi ý bài tập sử dụng collaborative filtering và mô hình Two Tower với MariaDB vector search. Yêu cầu MariaDB 11.7+.
Xem judge/ml/README.md để biết hướng dẫn chi tiết.
Các job định kỳ thuộc ứng dụng được cấu hình trong CELERY_BEAT_SCHEDULE ở
dmoj/settings.py và cần celery -A dmoj_celery beat cùng ít nhất một Celery
worker. Nhóm này bao gồm moderation, dọn notification, dọn session, dọn account
không hoạt động, tính lại score, tính lại contribution, đồng bộ cờ
organization-private và các reaper của auto-review.
Chỉ dùng cron cho script hạ tầng nằm ngoài Django worker, ví dụ backup, restart container bridge hoặc pipeline ML bên ngoài. Ví dụ crontab production:
0 2 * * * /home/ubuntu/backup/backup.sh >> /home/ubuntu/backup/backup.log 2>&1
0 3 * * * /home/ubuntu/cronjobs/ml_gen_data.sh
30 2 * * * /home/ubuntu/bridge/run.sh >> /home/ubuntu/bridge/cron.log 2>&1