Justus OJ 是一個以 Python Flask + Docker 建置的輕量級 C++ Online Judge 線上解題系統。
本系統提供題目管理、C++ 程式碼編譯與評測、範例測資測試、AI 解題提示、使用者登入註冊、解題統計、後台管理,以及獨立 C++ 編輯器。所有 C++ 程式碼皆透過 Docker 沙箱執行,降低伺服器被惡意程式碼影響的風險。
- C++ 線上解題與自動評測
- Docker 沙箱隔離執行環境
- 支援 AC / WA / CE / RE / TLE 等評測狀態
- 支援範例測資即時測試
- 支援上傳
.cpp/.txt程式碼 - 支援 CodeMirror 程式碼編輯器
- 支援 C++ 關鍵字提示與自動補全
- 支援 AI 解題思路提示
- 支援使用者登入、註冊、登出
- 支援未登入提交時暫存程式碼,登入後自動還原
- 支援使用者解題統計:已解題數、正確率、排名
- 支援管理員後台新增、編輯、刪除題目
- 支援題目圖片上傳
- 支援範例測資與隱藏測資管理
- 支援題庫 JSON 匯出與匯入
- 支援獨立 C++ 編輯器頁面
- 支援自訂 stdin 執行程式
- 支援下載目前程式碼為
.cpp檔案 - 支援 Cloudflare 真實 IP 解析
- 支援 CSRF 保護
- 支援系統事件 Log 紀錄
使用者可以註冊、登入與登出。登入後可以正式提交題目,系統會記錄提交結果與程式碼。
功能包含:
- 使用者註冊
- 使用者登入
- 使用者登出
- 密碼雜湊儲存
- Session 登入狀態管理
- 管理員角色判斷
- 登入後顯示使用者名稱
- 管理員登入後可進入後台
預設管理員帳號會在資料庫初始化時自動建立,可透過環境變數設定。
首頁提供卡片式題目列表,讓使用者快速選擇題目進入解題頁。
功能包含:
-
Hero Banner
-
題目卡片列表
-
題目 ID、標題、敘述摘要
-
題目圖片顯示
-
已解題題目顯示綠色勾勾
-
使用者登入後顯示:
- 已解決題數
- 提交正確率
- 排名
-
快速進入 C++ 編輯器
-
登入、註冊、登出、後台管理入口
-
Footer 技術資訊與聯絡資訊
每一題都有獨立的解題頁面,使用者可以閱讀題目、查看範例測資、撰寫程式碼、測試範例、送出正式評測。
功能包含:
- 題目切換下拉選單
- 題目敘述顯示
- 題目圖片顯示
- 範例輸入 / 範例輸出顯示
- CodeMirror C++ 編輯器
- C++ 語法模式
- Dracula 編輯器主題
- 行號顯示
- 括號自動補全
- C++ 關鍵字自動提示
Ctrl + Space手動觸發 autocomplete- 支援貼上程式碼
- 支援上傳
.cpp/.txt檔案 - 支援範例測資測試
- 支援正式送出評測
- 顯示評測結果
- 自動捲動到執行結果區
系統會將使用者提交的程式碼寫入暫存檔,再使用 Docker 進行編譯與執行。
評測流程:
- 建立唯一暫存檔名
- 將 C++ 程式碼寫入
temp_code/ - 使用 Docker 中的
gcc:latest執行g++ - 若編譯失敗,回傳 CE
- 若編譯成功,逐筆執行隱藏測資
- 比對使用者輸出與標準輸出
- 全部通過則回傳 AC
- 任一測資錯誤則回傳 WA
- 執行錯誤則回傳 RE
- 執行逾時則回傳 TLE
- 最後清理暫存檔
支援狀態:
| 狀態 | 說明 |
|---|---|
| AC | Accepted,所有測資通過 |
| WA | Wrong Answer,答案錯誤 |
| CE | Compilation Error,編譯錯誤 |
| RE | Runtime Error,執行錯誤 |
| TLE | Time Limit Exceeded,執行逾時 |
| MLE | Memory Limit Exceeded,記憶體限制相關錯誤 |
在正式提交前,使用者可以先執行題目公開的 Sample Test。
功能包含:
-
不寫入正式提交紀錄
-
只執行題目範例測資
-
顯示每筆 Sample 的:
- Input
- Expected Output
- Actual Output
- Pass / Fail
-
編譯錯誤時直接顯示錯誤訊息
-
使用 AJAX 與後端
/run_samples/<problem_id>溝通
這個功能適合讓使用者先確認基本輸入輸出是否正確,再送出正式評測。
系統提供 AI 解題提示功能,讓登入使用者可以針對目前題目與程式碼取得解題方向。
功能包含:
- 登入後才能使用
- 針對題目敘述產生提示
- 會參考使用者目前的程式碼
- 回覆解題思路、演算法方向、資料結構、邊界條件
- 要求 AI 不直接給完整程式碼答案
- 支援 Markdown 顯示
- 支援 MathJax 公式渲染
- AI 請求頻率限制,預設冷卻時間 30 秒
- 使用
OLLAMA_API_URL設定 AI API 位址 - 預設模型名稱為
gemini-3-flash-preview
系統提供 /editor 頁面,這是一個不綁題目、不送出正式評測的 C++ 練習編輯器。
適合用途:
- 臨時寫 C++ 程式
- 測試 stdin / stdout
- 練習語法
- 下載目前程式碼為
.cpp - 不想綁定題目時快速測試
功能包含:
- CodeMirror C++ 編輯器
- 行號顯示
- Dracula 主題
- 自動補括號
- C++ 關鍵字提示
Ctrl + Space自動補全- 自訂檔名
- 下載
.cpp檔案 - stdin 輸入欄位
- stdout / 錯誤訊息輸出欄位
- 執行狀態 Badge
- 清空輸出
- 使用
/run_custom執行自訂程式 - 不寫入 submissions 正式提交紀錄
- 仍使用 Docker 沙箱執行
- 仍套用基本防刷頻率限制
管理員登入後可以進入 /admin 管理題庫。
功能包含:
- 新增題目
- 編輯題目
- 刪除題目
- 上傳題目圖片
- 管理公開範例測資 Samples
- 管理隱藏測資 Test Cases
- 題目列表檢視
- 顯示題目是否有圖片
- 題庫 JSON 匯出
- 題庫 JSON 匯入
- 管理操作 Log 紀錄
題目資料包含:
- 題目標題
- 題目敘述
- 題目圖片
- 範例輸入
- 範例輸出
- 隱藏測資輸入
- 隱藏測資輸出
管理員可以透過後台匯出與匯入題目資料。
功能包含:
/admin/export- 匯出
problems_backup.json - 匯出題目文字資料
- 匯出 Samples
- 匯出 Test Cases
/admin/import- 上傳 JSON 還原題目
- 匯入時會新增到現有題庫,不會覆蓋原本題目
注意:
題目圖片檔案不會包含在 JSON 備份中。若題目包含圖片,請另外備份:
static/uploads/
本系統透過 Docker 執行使用者程式碼,並加入多層安全限制。
Docker 執行限制包含:
- 使用獨立 Docker container 執行
- 執行後自動刪除 container
- 禁用網路連線
- 限制記憶體
- 限制 CPU
- 限制 process 數量
- 限制 nproc
- 關閉額外 Linux capabilities
- 啟用
no-new-privileges - 使用非 root UID / GID 執行
- 執行環境設為 read-only
- 使用唯一檔名避免衝突
- 執行完清除暫存檔
預設限制:
| 項目 | 設定 |
|---|---|
| 編譯記憶體 | 256MB |
| 執行記憶體 | 128MB |
| 執行逾時 | 2 秒 |
| Process 限制 | 30 |
| nproc 限制 | 20 |
| Docker Image | gcc:latest |
| 網路 | disabled |
| 權限 | cap_drop ALL |
系統針對使用者 IP 進行頻率限制,避免惡意連續提交或大量呼叫 AI。
目前包含:
- 正式提交冷卻時間
- 範例 / 編輯器執行冷卻限制
- AI 提示冷卻時間
- 透過 SQLite 紀錄 IP 最後操作時間
- 支援 Cloudflare 真實 IP 解析
預設:
RATE_LIMIT_SECONDS = 15
AI_RATE_LIMIT_SECONDS = 30系統支援 Cloudflare Tunnel / Proxy 情境。
功能包含:
-
讀取
CF-Connecting-IP -
取得真實使用者 IP
-
使用
ProxyFix -
支援 HTTPS 反向代理部署
-
Session Cookie 設定:
SESSION_COOKIE_SECURE = TrueSESSION_COOKIE_HTTPONLY = TrueSESSION_COOKIE_SAMESITE = 'Lax'
本系統使用 Flask-WTF 的 CSRFProtect 進行 CSRF 防護。
涵蓋範圍包含:
- 登入表單
- 註冊表單
- 題目提交表單
- 後台新增題目
- 後台匯入題庫
- AJAX 請求中的
X-CSRFToken
若部署網域不同,請確認 CSRF_TRUSTED_ORIGINS 設定是否正確。
系統會將重要事件記錄到:
oj_events.log
紀錄格式:
<IP> : <時間> : <事件>
紀錄事件包含:
- 新使用者註冊
- 使用者登入
- 題目提交結果
- AI 請求
- 編輯器執行結果
- 管理員新增題目
- 管理員編輯題目
- 管理員刪除題目
- 題庫匯出
- 題庫匯入
當使用者訪問不存在的題目或錯誤路由時,系統會顯示友善 404 頁面。
功能包含:
- 顯示錯誤訊息
- 倒數自動回首頁
- 提供立即返回首頁按鈕
- Python 3
- Flask
- SQLite
- Docker SDK for Python
- Flask-WTF
- Werkzeug
- python-dotenv
- requests
- HTML5
- CSS3
- Bootstrap 5
- JavaScript
- CodeMirror
- Marked.js
- MathJax
- Docker Engine
- GCC Docker Image:
gcc:latest - Linux Server / VPS
- 可搭配 Nginx、Cloudflare Tunnel、systemd 部署
cpp_oj/
├── app.py
├── README.md
├── LICENSE
├── cpp_oj.db # SQLite 資料庫,首次執行後自動產生
├── oj_events.log # 系統事件紀錄,執行後自動產生
├── temp_code/ # 暫存 C++ 原始碼、輸入檔、執行檔
├── static/
│ ├── favicon.ico
│ └── uploads/ # 題目圖片存放位置
└── templates/
├── home.html # 首頁與題目列表
├── index.html # 解題頁面
├── editor.html # 獨立 C++ 編輯器
├── admin.html # 管理員後台
├── edit.html # 題目編輯頁
├── login.html # 登入頁
├── register.html # 註冊頁
└── 404.html # 404 頁面
| 路由 | 方法 | 功能 |
|---|---|---|
/ |
GET | 首頁與題目列表 |
/register |
GET / POST | 使用者註冊 |
/login |
GET / POST | 使用者登入 |
/logout |
GET | 使用者登出 |
/problem/<problem_id> |
GET / POST | 題目頁與正式提交 |
/run_samples/<problem_id> |
POST | 執行公開範例測資 |
/get_hint/<problem_id> |
POST | AI 解題提示 |
/editor |
GET | 獨立 C++ 編輯器 |
/run_custom |
POST | 執行編輯器自訂程式 |
/admin |
GET / POST | 管理員後台與新增題目 |
/admin/export |
GET | 匯出題庫 JSON |
/admin/import |
POST | 匯入題庫 JSON |
/edit/<problem_id> |
GET / POST | 編輯題目 |
/delete/<problem_id> |
GET | 刪除題目 |
/favicon.ico |
GET | 網站圖示 |
本系統建議部署於 Linux 環境,例如 Ubuntu / Debian。
sudo apt update
sudo apt install docker.io -y
sudo systemctl start docker
sudo systemctl enable docker將目前使用者加入 Docker 群組:
sudo usermod -aG docker $USER執行後請重新登入,讓群組設定生效。
docker pull gcc:latestgit clone https://github.com/cloud-driver/cpp_oj.git
cd cpp_ojpython3 -m venv venv
source venv/bin/activatepip install flask flask-wtf werkzeug python-dotenv requests docker建議建立 .env 管理敏感設定:
ADMIN_USERNAME=admin
ADMIN_PASSWORD=your_secure_admin_password
FLASK_SECRET_KEY=your_random_secret_key
OLLAMA_API_URL=http://localhost:11434/api/generate請務必修改:
ADMIN_PASSWORDFLASK_SECRET_KEY
不要在正式環境使用預設密碼與預設 Secret Key。
python3 app.py預設啟動於:
http://0.0.0.0:8080
第一次啟動時,系統會自動建立:
- SQLite 資料庫
- 題目表
- 使用者表
- 提交紀錄表
- Log 表
- 預設管理員帳號
- 暫存資料夾
- 圖片上傳資料夾
- 進入首頁
- 註冊帳號
- 登入
- 選擇題目
- 閱讀題目敘述與範例測資
- 撰寫 C++ 程式碼
- 可先按「測試範例」
- 確認基本輸出正確後按「送出評測」
- 查看 AC / WA / CE / RE / TLE 結果
- 點選首頁或導覽列的「C++ 編輯器」
- 在左側編輯 C++ 程式碼
- 在 stdin 欄位輸入測試資料
- 按下「執行程式」
- 在 stdout 欄位查看輸出或錯誤訊息
- 可輸入檔名並下載
.cpp
此功能不綁定任何題目,也不會寫入正式提交紀錄。
- 使用管理員帳號登入
- 點選「後台管理」
- 新增題目
- 填寫題目名稱與敘述
- 可選擇上傳題目圖片
- 新增 Samples
- 新增 Hidden Test Cases
- 儲存題目
- 可編輯、刪除既有題目
- 可匯出 / 匯入題庫 JSON
| 變數名稱 | 說明 | 預設值 |
|---|---|---|
ADMIN_USERNAME |
管理員帳號 | admin |
ADMIN_PASSWORD |
管理員密碼 | admin |
FLASK_SECRET_KEY |
Flask Session Secret Key | default-unsafe-key |
OLLAMA_API_URL |
AI API 位址 | http://localhost:11434/api/generate |
可在 app.py 中調整:
RATE_LIMIT_SECONDS = 15
AI_RATE_LIMIT_SECONDS = 30
AI_MODEL = "gemini-3-flash-preview"
DOCKER_IMAGE = "gcc:latest"
OJ_RUNNER_UID = "999"
OJ_RUNNER_GID = "986"若伺服器不存在 UID 999 或 GID 986,請依照實際環境調整。
正式部署時建議使用:
- Gunicorn
- Nginx
- systemd
- Cloudflare Tunnel / HTTPS
.env管理環境變數- 定期備份
cpp_oj.db - 定期備份
static/uploads/
可建立:
sudo nano /etc/systemd/system/justus-oj.service範例內容:
[Unit]
Description=Justus OJ Flask Service
After=network.target docker.service
Requires=docker.service
[Service]
User=YOUR_USER
WorkingDirectory=/path/to/cpp_oj
Environment="PATH=/path/to/cpp_oj/venv/bin"
ExecStart=/path/to/cpp_oj/venv/bin/python /path/to/cpp_oj/app.py
Restart=always
[Install]
WantedBy=multi-user.target啟用服務:
sudo systemctl daemon-reload
sudo systemctl enable justus-oj
sudo systemctl start justus-oj查看狀態:
sudo systemctl status justus-oj重啟服務:
sudo systemctl restart justus-oj建議定期備份:
cpp_oj.db
static/uploads/
.env
若只需要備份題目文字與測資,可使用後台的 JSON 匯出功能。
本系統雖然使用 Docker 沙箱限制使用者程式碼,但仍不建議直接以高權限裸露在公開網路。
建議:
- 不要使用 root 身分執行 Flask 服務
- 不要讓 Docker container 使用 privileged mode
- 不要移除 network disabled
- 不要移除 CPU / memory / process 限制
- 正式環境務必修改管理員密碼
- 正式環境務必修改
FLASK_SECRET_KEY - 建議放在 Nginx 或 Cloudflare Tunnel 後方
- 定期檢查
oj_events.log - 定期備份資料庫與圖片
- 目前主要支援 C++
- 題庫圖片不會包含在 JSON 匯出中
- AI 提示需要另外準備可用的 AI API
- Docker 需要在伺服器上正確安裝並啟動
- Windows 原生環境部署較不建議,推薦 Linux VPS
- 評測目前以標準輸入輸出比對為主
- 尚未提供完整的排行榜頁面,首頁僅顯示登入使用者目前排名
本專案採用 MIT License 授權。