证书签发和续期
Could not bind TCP port 80:Certbot 端口被占用的修法
Could not bind TCP port 80“Could not bind TCP port 80” 的意思是:Certbot 的 standalone 插件想在 80 端口上为 HTTP-01 验证启动自己的临时 Web 服务,被操作系统拒绝了。 要么是别的程序(通常是你的 Web 服务器)已经在监听 80 端口,要么是 Certbot 没有以足够的权限运行,开不了 1024 以下的端口。域名和 Let's Encrypt 都没问题,要在本机解决。
报错的两种写法
这条报错有两种后半句,分别对应端口被占用和权限不够。Certbot 根据系统返回的套接字错误选择措辞:
Could not bind TCP port 80 because it is already in use by another process on this
system (such as a web server). Please stop the program in question and then try again.
Could not bind TCP port 80 because you don't have the appropriate permissions (for
example, you aren't running this program as root).
第一种在交互运行时还会询问 Retry 或 Cancel。日志里可能还有底层的 Problem binding to port 80: ...。
为什么非得是 80 端口
Let's Encrypt 的 HTTP-01 验证只连 80 端口。CA 会访问 http://example.com/.well-known/acme-challenge/<token>,Let's Encrypt 文档写明 HTTP-01 只能走 80 端口。standalone 插件用自己的服务来回应这个请求,所以 Certbot 文档说它需要绑定 80 端口,“可能需要先停掉现有的 Web 服务器”。
一般在什么场景下遇到
主要有三种场景:首次安装、自动续期和容器环境。第一次安装时,照着某篇教程执行了 certbot certonly --standalone,而服务器上早就跑着 Nginx 或宝塔。自动续期时,systemd 定时器或 cron 按几个月前保存的 standalone 设置执行 certbot renew,失败了也没人知道,直到证书快过期才暴露;Let's Encrypt 从 2025-06-04 起不再发到期提醒邮件,没有任何东西会提醒你。容器环境里,Certbot 跑在一个容器里,另一个反向代理容器已经把宿主机的 80 端口占了。
常见原因(按出现频率排序)
端口绑定失败有 5 种原因,最常见的是 Web 服务器已经占着 80 端口。
1. Web 服务器正在运行
Nginx、Apache、Caddy,或者宝塔、1Panel 等面板自带的 Web 服务占着 80 端口。查是谁:
sudo ss -ltnp 'sport = :80'
2. 续期配置里存的是 standalone
第一张证书是在还没装 Web 服务器时签的。Certbot 把验证方式记在 /etc/letsencrypt/renewal/example.com.conf 里,几个月后续期时 80 端口已经被占。检查:
sudo grep -E 'authenticator|pre_hook|post_hook' /etc/letsencrypt/renewal/example.com.conf
3. 容器映射了 80 端口
docker ps 里能看到反向代理容器有 0.0.0.0:80->80/tcp,宿主机上的 Certbot 就绑不了同一个端口。改用 webroot 的做法见 Docker + Nginx + Certbot。
4. 没有用 root 运行
用普通用户运行,或者在没有绑定低端口权限的容器里运行,会出现权限那种写法。加 sudo,或者在有权限的环境里运行。
5. 上一次运行卡住了
被中断的 Certbot 进程可能还占着端口。ss 里能看到 certbot 或 python 进程,结束它再重试。
怎么修
方案 A:别用 standalone,改用现有的 Web 服务器(推荐)。
装了 Nginx 或 Apache 的,直接让 Certbot 用它们:
sudo certbot certonly --nginx -d example.com -d www.example.com
或者让 Web 服务器继续运行,用 webroot 方式,从网站目录提供验证文件:
sudo certbot certonly --webroot -w /var/www/example.com -d example.com -d www.example.com
已有证书想换验证方式,Certbot 2.3.0 及以上版本提供 reconfigure:它会先用新设置对测试服务器做一次续期演练,成功后才保存:
sudo certbot reconfigure --cert-name example.com --webroot -w /var/www/example.com
宝塔面板用户不需要另装 Certbot:面板“网站 → 设置 → SSL”里自带 Let's Encrypt 申请和续签,支持文件验证和 DNS 验证,文件验证通过网站目录提供验证文件,不会和面板的 Nginx 抢端口,详见 宝塔面板配置 SSL。
方案 B:保留 standalone,续期时临时停一下 Web 服务。
sudo certbot renew --pre-hook "systemctl stop nginx" --post-hook "systemctl start nginx"
Certbot 文档说明这两个钩子会在每次续期尝试的前后执行。放在 /etc/letsencrypt/renewal-hooks/pre 和 /post 目录里的可执行文件也会自动运行,见 Certbot 续期钩子。
面板环境下,宝塔、1Panel 等面板安装的 Nginx,服务名和启停方式可能和系统包管理器装的不一样,钩子里的命令要按实际情况写,并先手动执行一遍确认能停能起。面板环境更省事的做法是直接用面板自带的证书功能。
方案 C:改用 DNS-01。 不需要任何入站端口,还能申请通配符证书。
端口绑定的问题解决之后,如果验证又报连接超时,说明外部访问不到你的 80 端口,常见于云服务器安全组或防火墙没放行,见 Certbot Timeout during connect。
权限那种情况: 用 sudo 运行,不要为此修改系统的端口权限。
用 acme.sh 时的同类问题
acme.sh 的 --standalone 模式有同样的问题,修法也和 Certbot 一样。它会在 80 端口启动内置 Web 服务,端口被占用时报 tcp port 80 is already used by 加上占用进程的名字。修法:换成 --webroot 或 --nginx 模式,让现有的 Web 服务器提供验证文件;或者干脆改用 DNS API 验证,用 DNSPod、阿里云 DNS 的接口自动添加 TXT 记录。其他验证失败的情况见 acme.sh 验证报错。
不要这样做
这 4 种做法能绕过报错,但会误停别的网站、让验证继续失败,或者留下权限隐患。
- 不要不看清楚就结束占用 80 端口的进程。 在共享服务器或面板环境里,它可能还承载着别的网站,应该通过服务管理器停止,才能干净地恢复。
- 不要随便改用
--http-01-port,除非外部 80 端口转发到了这个端口,CA 永远只连 80。 - 不要为了不用 root 而给 Python 解释器开放绑定低端口的权限,这个权限会对所有使用同一解释器的脚本生效。
- 不要为了消除报错而关掉自动续期。 先把验证方式改对,再用演练确认。
怎么确认已经修好
修好后,演练命令 certbot renew --dry-run 会通过,certbot certificates 会显示新的到期时间。
- 用测试环境演练整个流程,不影响现有证书:
bash
sudo certbot renew --dry-run
- 正式运行后,
sudo certbot certificates能看到新的到期时间。 - 确认 Web 服务已经恢复运行(
systemctl status nginx),并用 SSL 检测 确认网站用上了新证书。
常见问题
能不能让 Certbot 在 8080 之类的端口上验证?
不能单独这样做,Let's Encrypt 的 HTTP-01 只连 80 端口。--http-01-port 8080 只是让 Certbot 在本机监听 8080,必须有 NAT 规则或反向代理把外部 80 转发过来才有用,否则验证会报连接错误。
续期好几个月都正常,最近突然报这个错,为什么?
第一次签发时用的是 standalone,那时 80 端口空着,Certbot 把这个选择存进了续期配置。之后服务器上装了 Web 服务。把这张证书改成 webroot 或 Web 服务器插件,或者加上前后钩子。
续期时停一下 Nginx 可以吗?
可以,但 Certbot 验证的那几秒网站是打不开的。webroot 或 Nginx 插件完全不用停机,生产环境优先用它们。
80 端口完全用不了怎么办?
改用 DNS-01 验证,通过 TXT 记录证明域名控制权,不需要任何入站端口,申请通配符证书也只能用它。国内 DNS 服务商可以参考 acme.sh 配合 DNSPod/阿里云 DNS。