青岛OJ跑起来之后,第一件让我夜不能寐的事,就是它还在用HTTP裸奔。登录页面输入暗语一样的强密码,训练场上百号人同时提交代码,密码在局域网里倒还好,一旦把OJ暴露到公网,抓包工具一开,所有账号密码和提交的代码全部“直播”出去。我才意识到,配置SSL证书、开启HTTPS访问不是锦上添花,而是OJ上线的刚需。
这篇是这个系列的第七篇,重点说清楚给青岛OJ配SSL证书的完整路径:从证书方案选型、acme.sh签发,到把证书挂进Docker里的Nginx、开启HTTPS并自动续期,顺便解决几个我踩过的坑。适合已经能够正常通过HTTP访问青岛OJ、想把站点升级为HTTPS的管理员,也适合部署其他Docker化Web服务的人参考。
1. 为什么OJ站点必须走HTTPS:登录密码泄露跟“裸奔”没区别
先说一个被很多人忽略的点:你在Nginx或者后端做的任何密码加密、Session加密,都不解决传输层的问题。HTTP是明文协议,数据从浏览器到服务器之间经过的每一个路由器、交换机、Wi-Fi热点,理论上都能完整看到POST表单里的密码。OJ这种场景尤其危险——账号密码、待评测的源代码,都是敏感数据。源代码如果被中间人篡改,还可能直接影响评测结果。
有人会反驳:“我OJ是内网部署,不暴露公网。”那也建议开HTTPS。内网也有一堆ARP欺骗、伪基站Wi-Fi,配置一次成本很低,没必要赌。而且现在主流浏览器对HTTP站点直接标“不安全”,学生访问OJ、老师演示的时候,页面上一把红色锁头,观感太差。
还有一点跟OJ强相关:现代浏览器对HTTPS页面里的HTTP请求有限制,也就是混合内容拦截。等你之后加代码高亮、MathJax公式、在线IDE这类子功能,如果还停留在HTTP,很多浏览器会直接挡住混在页面里的非HTTPS资源。到时候排查起来比现在配证书麻烦十倍。
所以,给OJ配HTTPS不是一个“可选优化”,而是部署清单里的一项基本配置。接下来进入实操环节,我会把从零到生效的每一步都拆开讲。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 证书方案怎么选:Let‘s Encrypt、云厂商免费证书还是自签名
市面上免费SSL证书来源不少,但适合OJ场景的其实就两类。
2.1 Let’s Encrypt证书:自动续期、通配符支持
Let‘s Encrypt是目前最主流的免费证书颁发机构,证书有效期只有90天,靠ACME协议自动续期。优点是完全免费、自动化程度高、所有主流客户端都有,比如acme.sh、certbot。签发时有两种验证方式:HTTP验证和DNS验证。HTTP验证需要在域名对应站点根目录放一个临时文件,或者用standalone模式临时占用80端口;DNS验证则需要在DNS服务商处加一个TXT记录,适合通配符证书。
对青岛OJ来说,如果没有特殊需求,签发一个普通单域名证书就够了,比如oj.example.com。如果你将来想给多个子域名都上HTTPS,也可以签发通配符证书,比如*.example.com,前提是你的DNS服务商支持API自动添加记录。acme.sh对国内外主流DNS服务商都有接口,配置好之后续期完全不用管。
2.2 云厂商免费证书:一年量、手动续期
阿里云、腾讯云等云厂商也提供免费SSL证书,一般一年期。这类证书适合不想折腾ACME、习惯在云控制台操作的人。流程是:在控制台申请证书,绑定域名,下载Nginx格式的证书文件,然后上传到服务器。缺点是一年到期后需要手动再次申请,有些还限制单账号每年免费额度。热搜里提到的“阿里云ssl证书免费续期”,实际上就是指这种证书到期后重新申请免费版,并不是自动续费,至少流程上是手动操作一步。2025年之后阿里云免费证书策略也有调整,个人申请通常只能一次3个月或一年,具体以控制台为准。
既然我们做OJ,追求的是稳定省心,我更推荐Let’s Encrypt + acme.sh。这不是说云厂商证书不好,而是自动续期的体验差异太大:一个忘记续期,证书过期,浏览器直接拒绝连接,OJ停摆;另一个只要定时任务正常,证书到期前自动续上,根本不用管。
2.3 自签名证书:只能说“本地测试专用”
自签名证书可以自己用openssl生成,也能让浏览器通过HTTPS访问(需手动信任),但没有任何公信力,协作者每台设备都要导入证书,学生异地访问OJ时更麻烦。除非你是在完全离线的内网做测试,否则不建议。青岛OJ本身就有公网访问需求,老老实实用公网受信任的证书。
选型之前,还要确认两件事:第一,你有没有域名,没有的话先去注册一个,IP地址是没法申请公网HTTPS证书的(内网IP也不行);第二,域名能不能解析到你服务器,最好提前把A记录配置好,并且确认解析生效。证书验证的是“你确实控制这个域名”,所以域名解析是前提。
3. 用acme.sh签发证书:域名解析、安装、签发的完整链路
我之前一直用certbot,后来换成了acme.sh,原因就一个:纯Shell脚本,不依赖Python环境,对服务器内存占用极小,而且部署到Nginx超简单。下面以acme.sh为例。
3.1 安装acme.sh
执行下面一条命令即可:
bash复制curl https://get.acme.sh | sh -s email=你的邮箱@example.com
它会自动把你的acme.sh安装到当前用户目录下的.acme.sh,并写入一个定时任务(cron)用于每天检查证书到期时间。安装完成后,执行下面命令让环境变量生效:
bash复制source ~/.bashrc
如果服务器有多个用户,建议用专门运行Nginx服务的管理员用户来安装,避免权限纠缠。
3.2 签发证书前必须确认的“前置条件”
在签发之前,
