curl 部署 Coolify,域名 HTTPS 与日志排错

通过 curl 安装 Coolify 后面板打不开,先别反复重跑脚本:检查 Docker 守护进程、8000 端口监听和服务器防火墙;遇到 Deployment Failed,按 Compose 解析、镜像拉取、镜像构建和容器启动四层排查;容器 Exited 则看退出码和运行日志;域名返回 502、504 或 HTTPS 异常,再依次检查 DNS、网络入口、反向代理和容器端口。

看到的现象 优先检查
安装脚本报错或面板打不开 Docker、8000 端口监听、防火墙、安全组
Deployment Failed 部署日志、Compose 配置、镜像拉取
容器 Exited 或反复重启 容器状态、退出码、运行日志
域名 502 或超时 DNS、目标端口、反向代理上游
HTTPS 证书错误 A/AAAA 记录、证书验证、80/443、TLS 握手

开始排障前先执行下面这些只读命令:

docker version
docker compose version
docker info
docker compose ps -a

其中,docker compose ps -a 要在正确的 Compose 项目目录执行。旧环境如果只提供 docker-compose,先确认实际可用命令。本文后文统一用 docker compose 表示 Compose 操作,实际执行时按环境使用对应语法,不要把两套语法混用。

Coolify 官方 GitHub 仓库将其定位为开源、可自托管的 Vercel、Heroku 与 Netlify 替代方案,可用于部署静态站点、数据库和全栈应用。 实际排障时,故障通常不在“能不能安装”这一层,而在配置、容器状态、网络入口和证书之间。

curl 脚本跑完了,8000 端口为什么还打不开

先判断安装是否完成、Docker 是否运行,以及 8000 端口链路是否被挡住,不要把重跑安装脚本当成通用修复方法。

安装前至少确认系统是 Linux,Docker 环境可用,并留出足够的存储和内存。现有资料没有给出统一的最低配置数值,因此不要把某台机器的规格当成所有部署的硬门槛。

安装示例使用下面的命令,安装完成后从服务器的 8000 端口进入配置。 脚本会检查当前用户是否具有 root 权限,因此也可以使用带 sudo 的写法。

curl -fsSL https://cdn.coollabs.io/coolify/install.sh | sudo bash

这条命令把下载和执行连在了一起。为了先审阅脚本内容,可以拆成两步:

curl -fsSL https://cdn.coollabs.io/coolify/install.sh -o install.sh
less install.sh
sudo bash install.sh

安装脚本会修改系统环境并启动相关服务,执行前至少应确认下载地址和脚本内容符合预期。不要因为下载缓慢,就直接换成来源不明的第三方替换脚本。

安装结束后,先看 Docker 是否真的可用:

docker version
docker info
df -h
free -h

在使用 systemd 的 Linux 发行版上,还可以检查 Docker 服务状态:

systemctl is-active docker
systemctl status docker --no-pager

接着确认 8000 端口是否监听:

ss -lntp | grep ':8000'
curl -v http://127.0.0.1:8000/ -o /dev/null
docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'

按这些结果分流。如果 docker info 失败,说明 Docker 客户端可能存在,但守护进程没有正常响应,或者当前用户没有访问 Docker socket 的权限。如果 Docker 正常,但 ss 找不到 8000 端口,应回查安装输出和容器状态,不要继续检查域名。如果本机访问 127.0.0.1:8000 成功,但外部浏览器访问超时,优先检查云安全组、服务器防火墙和上游网络对 8000 端口的拦截。如果本机访问也失败,则说明问题还在服务器内部,应继续看容器状态和运行日志。

如果安装卡在镜像拉取,先区分 DNS、网络、镜像地址和 CPU 架构问题:

getent hosts registry-1.docker.io
curl -sS -o /dev/null -w '%{http_code}\n' https://registry-1.docker.io/v2/
docker pull <image>

能收到 HTTP 响应,至少说明到镜像仓库的网络路径已经建立;具体状态码还可能涉及认证或仓库策略。如果域名无法解析,是 DNS 问题;连接超时或被拒绝,是出口网络、防火墙或代理问题;镜像名或标签不存在,则是仓库地址问题;错误里出现架构不匹配、no matching manifest 一类信息时,再核对镜像是否提供当前服务器架构的版本。

现有资料把 Docker 镜像拉取列为国内安装时的主要卡点。 这可以作为排查方向,但不能据此认定所有超时都是同一个问题,也不要用一个未经核验的第三方安装脚本替换官方脚本。

Docker Compose 部署失败,先分清解析、拉取、构建还是启动

Compose 报错时,按配置解析、镜像获取、镜像构建、容器启动四层检查,不要在尚未定位时直接重装 Coolify。

下面用 compose.yaml 代表实际 Compose 文件路径,用 <service> 代表真实服务名。服务名可以先从下面的命令获取:

docker compose -f compose.yaml config --services

先验证 Compose 最终解析出来的配置:

docker compose -f compose.yaml config

这一步重点看镜像名称、构建上下文、环境变量、端口、网络、卷和健康检查是否与预期一致。Compose 在解析文件时会进行变量插值,缺失变量、变量名大小写不一致、.env 不在预期位置,都可能得到空值或错误配置。支持相关选项的 Compose 版本还可以先查看未插值的结构:

docker compose -f compose.yaml config --no-interpolate

.env 主要用于给 Compose 插值,它不会因为文件存在就自动进入容器。容器里能否读到变量,仍取决于 environment 或 env_file 配置。也可以显式指定变量文件:

docker compose --env-file .env -f compose.yaml config

某些仓库会把环境变量模板命名为 env.windows-docker-desktop.example。现有资料记录过将这个文件改名为 .env 后再部署的场景,但这是特定项目的做法,不是所有 Compose 项目的统一要求;是否改名应以仓库说明为准。

配置解析通过后,再分别检查镜像拉取和镜像构建:

docker compose -f compose.yaml pull
docker compose -f compose.yaml build

pull 主要暴露镜像名、标签、网络、认证和架构问题;它只适用于引用远端镜像的服务。build 主要暴露 Dockerfile 路径、构建上下文、依赖下载和构建参数问题。两者都成功,也不代表应用一定能启动。

接下来看服务和日志:

docker compose -f compose.yaml ps -a
docker compose -f compose.yaml logs --tail=200 --timestamps <service>

如果服务没有创建成功,先查 Coolify 部署日志和上面的拉取、构建输出。如果容器创建后立即退出,再查应用运行日志。此时还应检查宿主机端口是否已被占用、挂载目录权限是否正确、依赖服务是否已经可用,以及健康检查命令本身是否能在容器环境里运行。

在 Coolify 已经管理的同一项目上,不要随手再执行另一套 up -d:

docker compose -f compose.yaml up -d

它可能创建重复容器、网络或卷,让 Coolify 页面与宿主机实际状态变得不一致。只在仓库副本或隔离测试环境中使用这条命令。

容器显示 Exited,部署日志里却找不到原因

部署日志负责解释“容器如何被创建”,容器日志负责解释“进程为什么退出”,两者不能混用。

先找到目标容器及其状态:

docker compose -f compose.yaml ps -a
docker inspect --format '{{json .State}}' <container_id>
docker logs --tail 200 --timestamps <container_id>

按这些结果继续排查。如果没有容器,问题还在拉取、构建或部署阶段,应回到 Coolify 部署日志。如果容器刚创建就退出,退出码、stdout 和 stderr 通常比最后一条 UI 提示更有用。如果容器反复重启,则检查启动命令、依赖服务、挂载是否在启动前准备好,以及健康检查是否过于严格。

如果定义了健康检查,可以继续查看:

docker inspect --format '{{json .State.Health}}' <container_id>
docker stats --no-stream <container_id>

状态中如果出现 OOMKilled,应检查容器内存限制和进程实际占用;如果是非零 ExitCode,则沿应用异常方向检查。退出码为 0 只表示进程正常结束,对于本应长期运行的服务来说,退出仍然是问题。

“日志为空”不一定是 Docker 异常。容器根本没有创建时,自然没有容器日志;查错容器或服务名,也会拿到空结果。应用如果把日志写进文件而不是标准输出,docker logs 同样可能没有内容。进程在日志系统初始化前崩溃,也可能来不及留下任何输出。这时要结合退出码、入口命令、挂载目录和容器内的日志文件继续查。

域名已经解析,HTTP 还是打不开

先沿着 DNS、网络入口、反向代理和容器端口逐层走,不要直接把问题归因于域名解析。

dig +short A <domain>
dig +short AAAA <domain>
dig +short CNAME <domain>
curl -4 -vI http://<domain>
curl -6 -vI http://<domain>

CNAME 没有结果不一定异常,域名也可能直接提供 A 或 AAAA 记录。A 记录应指向当前服务器;如果还保留着失效的 AAAA 记录,部分客户端会优先尝试 IPv6,从而出现“浏览器打不开,但服务器 curl 正常”的现象,应删除或修正失效记录。

域名能正确解析,但连接超时,优先检查 80、443 是否被服务器防火墙或云安全组拦截。最好分别从服务器和外部网络执行 curl,避免本地网络、代理或回环路由掩盖真实链路。

域名请求已经到达反向代理后,要核对三件事:目标服务是否仍在运行,反向代理选择的上游地址和端口是否正确,上游协议是 HTTP 还是 HTTPS。容器里的应用如果只监听 127.0.0.1,其他容器和反向代理通常无法通过容器网络访问。反向代理应该指向容器网络中实际可达的服务端口,而不是只看宿主机上“映射出来的端口”。

502 通常表示代理与上游连接失败、连接被关闭或协议不匹配;504 更偏向等待上游响应超时。但应用自身也可能返回 502 或 404,所以不能只凭状态码下结论。应同时查看响应头、反向代理错误日志和应用容器日志。

如果启用了 Cloudflare 代理模式,需要额外比较代理结果与源站结果;DNS-only 模式则跳过这一步。可用 --resolve 保留域名和 SNI,直接访问源站:

curl -vI --resolve <domain>:80:<origin-ip> http://<domain>
curl -vI --resolve <domain>:443:<origin-ip> https://<domain>

如果源站只允许 Cloudflare 地址访问,直连源站失败并不能证明应用故障。部分只供 Cloudflare 使用的源站证书也不能被普通客户端直接信任。最终应结合当前 Cloudflare 设置、源站响应和代理日志判断。

HTTPS 报错,是证书没签下来还是应用本身有问题

把 DNS、证书签发、TLS 握手和 HTTP 响应分开测,避免把不同层的问题混成“SSL 坏了”。

curl -vI http://<domain>
curl -vI https://<domain>
openssl s_client -connect <domain>:443 -servername <domain> </dev/null

先确认 A、AAAA 记录指向当前服务器,并检查 80、443 是否可达。如果当前采用的证书验证方式需要通过 HTTP 完成验证,就要重点检查 80 端口是否开放,以及带正确 Host 的请求能否到达验证服务;如果采用 DNS 验证,则应检查 DNS 权限和验证记录是否成功更新。具体方式应按当前版本和对应官方文档确认。

HTTP 请求正常但 HTTPS 握手失败,优先检查证书是否过期、域名是否匹配、证书链是否完整,以及反向代理是否加载了最新证书。openssl s_client 可以帮助区分握手失败和证书内容问题。

如果 HTTPS 已经完成握手,但页面仍返回 404、502、504 或应用错误,说明问题已经越过 TLS 层,应回到反向代理上游、容器端口和应用日志排查。

不建议通过关闭证书校验来“修复”。跳过校验最多只能帮助确认错误发生在证书层,不能解决签发、域名匹配或证书链问题。具体证书开关和当前界面字段可能随版本变化,不应照搬旧教程中的菜单路径。

改完配置却没有生效,先对齐容器和日志时间

部署成功不代表新容器已经替换旧容器。要用容器 ID、镜像、创建时间和日志时间确认实际运行的是哪一次构建。

docker compose -f compose.yaml logs --since=10m <service>
docker inspect --format '{{.Created}} {{.Config.Image}} {{json .State}}' <container_id>
docker compose -f compose.yaml ps -a

如果只是执行了容器重启,而没有重新构建或重建镜像,构建参数、镜像标签、环境变量等配置可能根本没有应用。.env 的新值也通常要通过重新创建容器才能进入运行环境。

还要检查反向代理是否仍指向旧容器、是否选错 Compose 服务,或者宿主机上同时存在手工启动和 Coolify 启动的两套实例。容器名与 Compose 服务名不一定相同,应先用 docker compose ps -a 对照关系,不要凭名称猜。

排障时不要顺手执行下面的命令:

docker compose -f compose.yaml down -v

down -v 可能删除 Compose 项目声明的卷和匿名卷,清理未使用卷的命令也可能带走后续仍需要的数据。删除卷、清理镜像都应该是确认数据不再需要后的单独操作,而不是默认排障步骤。

另外,docker inspect、环境变量和日志都可能包含密码、令牌或连接串。公开报错前应统一脱敏,不要只删掉明显的 PASSWORD 字段。

下一次报错,先留下这几份证据

完整错误和时间线比“重新部署一次”更有助于定位问题。再次提交问题或搜索官方仓库 Issues 前,建议保存:

  1. 实际执行的完整命令,以及日志中的第一条原始报错。
  2. 报错时间、时区、服务器操作系统和 Docker、Compose 版本。
  3. 应用仓库的提交版本、镜像标签、Compose 文件路径。
  4. Coolify 部署日志和目标容器的运行日志。
  5. 容器 ID、容器状态、退出码和健康状态。
  6. 脱敏后的 DNS、curl -vI 和 TLS 检查结果。
date -Is
docker version
docker compose version
docker compose -f compose.yaml ps -a

然后用原始报错文本搜索 Coolify 官方仓库的 Issues,并附上上述环境信息。 不要只写“部署失败”“502”或“证书错误”,因为这些只是现象,不是足以定位故障的证据。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容