用云服务器搭建一个私人在线代码运行沙箱:Docker + Judge0 部署实践
用云服务器搭建一个私人在线代码运行沙箱:Docker + Judge0 部署实践
前言
很多开发者都用过在线代码运行平台,比如 LeetCode、洛谷、牛客、CodeSandbox 等。它们背后都有一个核心能力:用户提交一段代码,服务器在隔离环境中编译、运行,并返回结果。
这篇文章记录一次在云服务器上部署私人代码运行沙箱的过程。部署完成后,我们可以通过 API 提交代码,让服务器自动编译并执行,适合用来做:
- 在线判题系统
- 编程练习平台
- 代码教学工具
- AI 代码评测服务
- 私人工具接口
本文使用 Judge0 作为代码执行引擎,它支持 C、C++、Java、Python、JavaScript、Go、Rust 等多种语言,并且基于 Docker 运行,隔离性和可维护性都比较好。
服务器方面我使用的是雨云云服务器 雨云注册通道 。它的优势是开通快、控制台简单,适合这种需要快速验证的部署实验。个人测试建议选择 2 核 4G 起步,内存太小的话,多语言运行环境会比较吃力。
一、最终效果
部署完成后,我们可以通过 HTTP API 提交一段代码。
例如提交一段 Python:
print("Hello Judge0")请求接口后,服务会返回运行结果:
{"stdout":"Hello Judge0\n","time":"0.01","memory":3328,"stderr":null,"compile_output":null,"message":null,"status":{"id":3,"description":"Accepted"}}这意味着我们拥有了一个可以远程调用的代码执行服务。
二、准备云服务器
这类服务比较依赖 Docker 和内存,建议服务器配置不要太低。
推荐配置:
| 项目 | 建议 |
|---|---|
| CPU | 2 核及以上 |
| 内存 | 4G 及以上 |
| 系统 | Ubuntu 22.04 LTS |
| 磁盘 | 30G 及以上 |
| 带宽 | 3M 及以上 |
如果只是个人测试,雨云的轻量云服务器就够用。购买完成后,在控制台拿到公网 IP 和 root 密码。
使用 SSH 登录服务器:
sshroot@你的服务器公网IP更新系统:
aptupdate&&aptupgrade-y安装常用工具:
aptinstall-ycurlwgetgitvimunzip三、安装 Docker 和 Docker Compose
Judge0 官方推荐使用 Docker Compose 部署,所以先安装 Docker。
执行安装脚本:
curl-fsSLhttps://get.docker.com|bash启动 Docker:
systemctl startdockersystemctlenabledocker查看版本:
docker-v安装 Docker Compose 插件:
aptinstall-ydocker-compose-plugin查看版本:
dockercompose version如果能正常输出版本号,说明环境没问题。
四、下载 Judge0 部署文件
进入/opt目录:
cd/opt下载 Judge0:
wgethttps://github.com/judge0/judge0/releases/download/v1.13.1/judge0-v1.13.1.zip解压:
unzipjudge0-v1.13.1.zip进入目录:
cdjudge0-v1.13.1复制配置文件:
cpjudge0.conf.example judge0.conf五、修改 Judge0 配置
编辑配置文件:
vimjudge0.conf建议重点修改下面几个配置。
1. 数据库密码
找到:
POSTGRES_PASSWORD=YourPasswordHere1234改成一个复杂密码:
POSTGRES_PASSWORD=你的复杂数据库密码2. Redis 密码
找到:
REDIS_PASSWORD=YourPasswordHere1234改成:
REDIS_PASSWORD=你的复杂Redis密码3. 是否开启认证
个人测试可以先不启用认证。如果要开放到公网,强烈建议加一层网关认证,或者只允许自己的服务器访问。
Judge0 本身可以配置 API 鉴权,但如果只是搭建个人工具,也可以通过 Nginx Basic Auth、访问白名单等方式控制。
六、启动 Judge0
在 Judge0 目录下执行:
dockercompose up-ddb redis等待数据库和 Redis 启动后,再启动主服务:
dockercompose up-d查看容器状态:
dockercomposeps正常情况下可以看到多个服务处于 running 状态。
查看日志:
dockercompose logs-f如果没有明显报错,说明服务已经启动。
七、开放端口
Judge0 默认 API 端口通常是:
2358如果服务器开启了 UFW,需要放行端口:
ufw allow2358还要在云服务器控制台中放行安全组端口:
TCP 2358然后访问:
http://你的服务器公网IP:2358如果返回 Judge0 相关信息,说明 API 服务可以访问。
八、测试代码运行接口
Judge0 提交代码需要使用 Base64 编码参数。为了方便测试,可以用base64_encoded=false。
提交 Python 代码:
curl-XPOST"http://你的服务器公网IP:2358/submissions?base64_encoded=false&wait=true"\-H"Content-Type: application/json"\-d'{ "language_id": 71, "source_code": "print(\"Hello from Judge0\")" }'其中:
language_id=71表示 Python 3wait=true表示等待运行完成后直接返回结果base64_encoded=false表示请求体不使用 Base64 编码
返回示例:
{"stdout":"Hello from Judge0\n","time":"0.01","memory":3364,"stderr":null,"compile_output":null,"message":null,"status":{"id":3,"description":"Accepted"}}再测试一段 C++:
curl-XPOST"http://你的服务器公网IP:2358/submissions?base64_encoded=false&wait=true"\-H"Content-Type: application/json"\-d'{ "language_id": 54, "source_code": "#include <iostream>\nusing namespace std;\nint main(){ cout << \"Hello C++\" << endl; return 0; }" }'常用语言 ID:
| 语言 | language_id |
|---|---|
| C | 50 |
| C++ | 54 |
| Java | 62 |
| Python 3 | 71 |
| JavaScript | 63 |
| Go | 60 |
| Rust | 73 |
九、配置 Nginx 反向代理
直接暴露2358端口不太优雅,可以用 Nginx 做反向代理。
安装 Nginx:
aptinstall-ynginx创建配置文件:
vim/etc/nginx/sites-available/judge0写入:
server { listen 80; server_name 你的域名或服务器IP; location / { proxy_pass http://127.0.0.1:2358; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 20m; proxy_read_timeout 300s; proxy_connect_timeout 300s; proxy_send_timeout 300s; } }启用配置:
ln-s/etc/nginx/sites-available/judge0 /etc/nginx/sites-enabled/judge0检查配置:
nginx-t重启 Nginx:
systemctl restart nginx现在就可以通过:
http://你的域名或者:
http://你的服务器公网IP访问 Judge0 API。
十、加一层简单访问保护
代码运行服务不建议完全裸奔在公网,因为它会消耗服务器资源。如果被恶意调用,可能导致 CPU、内存被打满。
一种简单方式是使用 Nginx Basic Auth。
安装工具:
aptinstall-yapache2-utils创建账号密码:
htpasswd-c/etc/nginx/.judge0_passwd admin修改 Nginx 配置:
server { listen 80; server_name 你的域名或服务器IP; auth_basic "Judge0 API"; auth_basic_user_file /etc/nginx/.judge0_passwd; location / { proxy_pass http://127.0.0.1:2358; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 20m; proxy_read_timeout 300s; proxy_connect_timeout 300s; proxy_send_timeout 300s; } }重启 Nginx:
nginx-tsystemctl restart nginx之后请求接口时需要带上账号密码:
curl-uadmin:你的密码\-XPOST"http://你的域名/submissions?base64_encoded=false&wait=true"\-H"Content-Type: application/json"\-d'{ "language_id": 71, "source_code": "print(\"auth ok\")" }'十一、资源限制建议
代码沙箱服务的风险主要来自资源消耗,所以建议做好限制。
可以从几个方向控制:
- 不开放给所有人使用
- 使用 Basic Auth 或 Token 鉴权
- 限制单次代码运行时间
- 限制提交频率
- 不在低配置服务器上开放高并发调用
- 使用防火墙限制访问 IP
如果只是自己使用,可以直接在云服务器安全组中限制访问来源 IP,这样比应用层鉴权更简单。
十二、常见问题
1. Docker Compose 启动失败
先看日志:
dockercompose logs-f常见原因:
- 内存太小
- 数据库密码没有修改
- Docker 没有正常启动
- 服务器磁盘空间不足
可以查看资源:
free-hdf-h2. 接口可以访问,但运行代码失败
查看 worker 日志:
dockercompose logs-fworker如果是语言环境相关问题,确认使用的是 Judge0 官方完整镜像,而不是自己精简过的镜像。
3. 访问很慢
代码运行本身会有编译和执行开销。如果服务器配置较低,第一次运行某些语言会慢一些。可以升级 CPU 和内存,或者减少同时运行任务数量。
4. 返回 401 或认证失败
如果配置了 Basic Auth,curl 请求要加:
-u用户名:密码浏览器访问时也会弹出登录框。
十三、总结
这次我们在云服务器上部署了一个私人在线代码运行沙箱,核心流程包括:
- 准备 Ubuntu 云服务器
- 安装 Docker 和 Docker Compose
- 部署 Judge0
- 使用 API 提交代码
- 配置 Nginx 反向代理
- 添加 Basic Auth 访问保护
相比普通的 Web 项目部署,代码沙箱更接近真实平台型服务的基础组件。无论是做在线判题系统、教学平台,还是给 AI Agent 提供代码执行能力,都可以基于这个方案继续扩展。
如果你只是想快速验证,雨云这类轻量云服务器比较适合入门,开通快,成本也不高。后续如果访问量变大,再考虑升级配置或者拆分数据库、Redis、执行节点即可。
