最近帮朋友在阿里云 ECS 上部署了一个 PHP + MySQL + Apache 的网站,最后一步自然是给它上一把「安全锁」——申请 Let's Encrypt 免费 SSL 证书。本以为用 Certbot 三两下就能搞定,结果硬是被各种奇奇怪怪的报错魔了一整天。趁热打铁,我把整个过程记录成了这篇保姆级教程,希望能帮到有同样遭遇的兄弟。服务器环境:Alibaba Cloud Linux 3.2104 LTS 64 位Web 环境:Apache 2.4 + PHP 7.x/8.x + MySQL域名:***.fun、zhao.***.fun(及各自 www 前缀),共 4 个子域名目标:申请一张通配符证书覆盖上面四个域名(当然这里是多域名证书),并实现自动续期。
一、工欲善其事,必先利其器——准备工作
在动手敲命令之前,一定要先确认下面这两件事,不然上来就撞墙的概率极高。
域名解析已生效把 ***.fun 和 zhao.***.fun(及它们的 www)都指向 ECS 的公网 IP,用 ping 或 dig 确认一下解析结果。
安全组放行 80 和 443 端口登录阿里云控制台 → 安全组规则,入方向放行 TCP 80 和 443,授权对象一般填 0.0.0.0/0(如果只是临时测试可以限定 IP)。同时,如果你的服务器在国内机房,域名必须先完成 ICP 备案,否则 80 端口的请求会被拦截,Certbot 验证会直接挂掉。
Apache 已安装并正常运行没装的话先装一下:
sudo dnf install httpd -y
sudo systemctl enable --now httpd
二、安装 Certbot 及 Apache 插件
Alibaba Cloud Linux 3 源自 RHEL,所以包管理器是 dnf,需要先启用 EPEL 仓库。
sudo dnf install epel-release -ysudo dnf install certbot python3-certbot-apache -y
这里我们装了两个包:certbot 本体和 python3-certbot-apache 插件,后者可以帮我们自动修改 Apache 配置,实现一键 HTTPS。但就是这一步,为后面的连环坑埋下了伏笔。
三、第一次尝试「自动配置」就给我来了个下马威
我想着官方推荐用法嘛,走起:
sudo certbot --apache -d ***.fun -d www.***.fun
报错:
NoInstallationError('Cannot find Apache executable apache2ctl',)
查了一下,原来 Certbot 的 Apache 插件内部会查找 apache2ctl 这个可执行文件,但 RHEL 系(包括阿拉云 Linux)的 Apache 服务名叫 httpd,控制脚本是 /usr/sbin/apachectl。解决方法很简单:创建一个软链接。
sudo ln -s /usr/sbin/apachectl /usr/sbin/apache2ctl
再试一次,又报错:
“Could not find configuration root”
我又按照文档尝试了:
sudo certbot --apache --apache-server-root /etc/httpd -d ***.fun -d www.***.fun
依然不行,还是提示找不到 apache2ctl,哪怕我软链接都做了、根目录也指定了,这个插件就是跟我杠上了。
多次折腾后,我决定放弃自动配置,改用更稳的 webroot 模式 手动申请证书。
四、webroot 模式申请证书——这才是正确的打开方式
webroot 的原理很简单:Certbot 往你指定的网站根目录里放一个临时验证文件,然后通过 HTTP 访问这个文件来证明域名是你的。全程不碰 Apache 配置,非常安全。
因为我四个域名分布在两个不同的目录中(主站 ***.fun 根目录是 /var/www,招生子站 zhao.***.fun 根目录是 /var/www/xxx),所以命令要分别指定 webroot:
sudo certbot certonly --webroot \ -w /var/www -d ***.fun -d www.***.fun \ -w /var/www/xxx -d zhao.***.fun -d www.zhao.***.fun \ --email 你的邮箱@qq.com --agree-tos --no-eff-email
结果又红了,全部 404,只有招生站的子域名能过?这就很诡异了。
排查:到底是谁在背后捣鬼?
通过
查看虚拟主机配置,我发现了端倪:
port 80 namevhost zhao.***.fun (/etc/httpd/conf.d/sir.conf:1) alias www.zhao.***.fun alias ***.fun ← 这里居然把主站域名当了别名!
原来之前有人在 sir.conf 文件里把 ***.fun 写成了招生站的别名,导致所有访问 ***.fun 的请求全部落到了招生站的根目录 /var/www/xxx,而 Certbot 放在 /var/www/.well-known/ 下的验证文件根本访问不到,所以主站的两个域名一直 404。
修复:
编辑 /etc/httpd/conf.d/sir.conf,找到类似 ServerAlias 那行,把 ***.fun 删掉,只保留 www.zhao.***.fun。同时确保主站自己的配置文件 /etc/httpd/conf.d/high.conf 中只包含这两个别名:
<VirtualHost *:80> ServerName ***.fun ServerAlias www.***.fun DocumentRoot /var/www <Directory /var/www> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory></VirtualHost>
重载 Apache 后,本地测试了一下验证文件,一切正常。再次执行上面的 certbot certonly 命令,成功!
Successfully received certificate.Certificate is saved at: /etc/letsencrypt/live/***.fun/fullchain.pemKey is saved at: /etc/letsencrypt/live/***.fun/privkey.pemThis certificate expires on 2026-08-05.
看到这个提示的时候,眼泪都快下来了。
五、手动配置 Apache SSL 虚拟主机
证书是拿到了,但 Apache 还不知道怎么用。接下来我们要手动配置 HTTPS 站点了。
首先备份一下系统自带的 SSL 默认配置(避免端口冲突):
sudo mv /etc/httpd/conf.d/ssl.conf /etc/httpd/conf.d/ssl.conf.bak
然后创建主站的 SSL 配置文件
/etc/httpd/conf.d/high-ssl.conf:
<VirtualHost *:443> ServerName ***.fun ServerAlias www.***.fun SSLEngine on SSLCertificateFile /etc/letsencrypt/live/***.fun/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/***.fun/privkey.pem DocumentRoot /var/www <Directory /var/www> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> # 如果你的站点需要 PHP,这里根据实际 PHP-FPM 监听方式填写 # <FilesMatch \.php$> # SetHandler "proxy:fcgi://127.0.0.1:9000" # </FilesMatch></VirtualHost>
同样道理,创建招生子站的 SSL 配置
/etc/httpd/conf.d/zhao-ssl.conf把 ServerName 和 DocumentRoot 换成对应的即可。
检查配置时报了个语法错误:SetHandler takes one argument。原来 SetHandler 后面的值要作为一个整体,用引号包起来且中间不能有空格,比如 "proxy:fcgi://127.0.0.1:9000"。改好后再 apachectl configtest 就 OK 了。
重载 Apache:
sudo systemctl reload httpd
打开浏览器访问 https://***.fun,终于看到了绿色小锁!
六、自动续期——免维护的最后一步
Certbot 在安装时理论上会自动配置一个 systemd timer,但我机器上的状态是 inactive (dead)。手动启用一下:
sudo systemctl enable certbot-renew.timer --nowsudo systemctl status certbot-renew.timer
确保状态为 active (waiting) 并且有下一次触发时间。不放心的话还可以再加一条 cron 兜底:
sudo crontab -e# 每周日凌晨 3 点续期并重载 apache0 3 * * 7 /usr/bin/certbot renew --quiet --post-hook "systemctl reload httpd"
最后用
sudo certbot renew --dry-run
测试一遍,输出
“Congratulations, all simulated renewals succeeded”
就说明万事大吉。
七、总结:我踩过的坑,你们绕着走
- Certbot 的 Apache 插件在 RHEL 系(含 Alibaba Cloud Linux)上经常水土不服遇到报错别硬刚,直接切 webroot 模式手动配置反而更可控。
- 虚拟主机别名(ServerAlias)不要乱写一个域名的别名配到了其他站点下,就会导致 404 或证书申请卡死。
- SetHandler 的语法全部参数用英文双引号括起来作为一个整体,中间不能有空格。
- 自动续期依赖 systemd timer如果发现没起来要手动
enable --now,或者用 crontab 做个兜底。
整个流程走下来,从跌跌撞撞到最终成功,不仅把 HTTPS 搞定了,对 Apache 虚拟主机的运作机制也理解得更深了一层。希望这篇分享能帮你在部署 SSL 的路上少走几段弯路。
如果你也遇到了奇怪的问题,欢迎留言交流,我们一起把坑填平!