部署默认端口改为 18080,支持与宿主机 Caddy 共存

避免与已有 80/443 服务冲突;补充端口检测、Caddyfile 示例与文档说明。
This commit is contained in:
yml2213
2026-07-15 15:38:07 +08:00
parent d4ba9e7a56
commit 0d3543fd4b
6 changed files with 216 additions and 34 deletions
+77 -9
View File
@@ -1,5 +1,6 @@
#!/usr/bin/env bash
# 客服云 — 腾讯云 / 任意 Linux 一键生产部署
# 默认 HTTP_PORT=18080,避免与宿主机 Caddy(80/443) 冲突;见 deploy/caddy/Caddyfile.example
# 用法:
# ./deploy/scripts/deploy.sh # 构建并启动
# ./deploy/scripts/deploy.sh --seed # 启动后导入演示账号数据
@@ -44,6 +45,58 @@ rand_hex() {
fi
}
# 检测宿主机 TCP 端口是否已被占用(非本 compose 的 web 容器)
port_in_use() {
local port="$1"
if command -v ss >/dev/null 2>&1; then
ss -tlnH "sport = :${port}" 2>/dev/null | grep -q .
return $?
fi
if command -v lsof >/dev/null 2>&1; then
lsof -iTCP:"${port}" -sTCP:LISTEN -n -P >/dev/null 2>&1
return $?
fi
# 无 ss/lsof 时用 bash /dev/tcp 探测(仅作弱检测)
(echo >/dev/tcp/127.0.0.1/"${port}") >/dev/null 2>&1
}
# 端口是否由本项目的 web 容器占用(升级/重部署时允许)
port_held_by_our_web() {
local port="$1"
docker ps --format '{{.Names}} {{.Ports}}' 2>/dev/null \
| grep -E 'kefu-cloud-web' \
| grep -qE "0\\.0\\.0\\.0:${port}->|:::${port}->"
}
check_http_port() {
local port="${HTTP_PORT:-18080}"
if ! [[ "$port" =~ ^[0-9]+$ ]] || [[ "$port" -lt 1 || "$port" -gt 65535 ]]; then
err "HTTP_PORT 无效: ${port}"
exit 1
fi
if [[ "$port" == "80" ]] || [[ "$port" == "443" ]]; then
if port_in_use "$port" && ! port_held_by_our_web "$port"; then
err "HTTP_PORT=${port} 已被占用(常见:宿主机 Caddy/Nginx"
err "请将 $ENV_FILE 中 HTTP_PORT 改为 18080,并由 Caddy 反代到该端口"
err "参考: deploy/caddy/Caddyfile.example 与 deploy/README.md「与现有 Caddy 共存」"
exit 1
fi
elif port_in_use "$port" && ! port_held_by_our_web "$port"; then
err "HTTP_PORT=${port} 已被其它进程占用,请改 $ENV_FILE 中的 HTTP_PORT"
if command -v ss >/dev/null 2>&1; then
ss -tlnp 2>/dev/null | grep -E ":${port}\\s" || true
fi
exit 1
fi
# 80/443 被占用但用户选了 18080 时给提示
if [[ "$port" != "80" ]] && port_in_use 80; then
log "检测到宿主机 :80 已被占用(多为 Caddy),将使用 HTTP_PORT=${port}"
log "部署后请把 Caddy 反代到 127.0.0.1:${port}(见 deploy/caddy/Caddyfile.example"
fi
}
ensure_env() {
if [[ ! -f "$ENV_FILE" ]]; then
if [[ ! -f "$ENV_EXAMPLE" ]]; then
@@ -71,8 +124,9 @@ ensure_env() {
warn "已生成随机 JWT_SECRET / DB_PASSWORD / STORAGE_SECRET_KEY"
warn "请编辑 $ENV_FILE,至少设置:"
warn " APP_BASE_URL=http://你的公网IP或域名"
warn " STORAGE_PUBLIC_BASE_URL=http://你的公网IP或域名/files"
warn " APP_BASE_URL=https://你的域名 # 经 Caddy 时用 https 域名,勿写 :18080"
warn " STORAGE_PUBLIC_BASE_URL=https://你的域名/files"
warn " HTTP_PORT=18080 # 已有 Caddy 占 80 时保持默认;独占机可改 80"
echo
read -r -p "设置完成后按回车继续(或 Ctrl+C 退出先改配置): " _
fi
@@ -83,6 +137,9 @@ ensure_env() {
source <(sed 's/\r$//' "$ENV_FILE" | grep -v '^\s*#' | grep -v '^\s*$' || true)
set +a
# 未显式设置时与 compose 默认一致
HTTP_PORT="${HTTP_PORT:-18080}"
if [[ -z "${JWT_SECRET:-}" || "${JWT_SECRET}" == *"请改"* ]]; then
err "请在 $ENV_FILE 中设置有效的 JWT_SECRET"
exit 1
@@ -92,7 +149,7 @@ ensure_env() {
exit 1
fi
if [[ -z "${STORAGE_PUBLIC_BASE_URL:-}" || "${STORAGE_PUBLIC_BASE_URL}" == *"你的"* ]]; then
err "请在 $ENV_FILE 中设置 STORAGE_PUBLIC_BASE_URL(如 http://1.2.3.4/files"
err "请在 $ENV_FILE 中设置 STORAGE_PUBLIC_BASE_URL(如 https://域名/files"
exit 1
fi
if [[ -z "${STORAGE_ACCESS_KEY:-}" || -z "${STORAGE_SECRET_KEY:-}" ]]; then
@@ -103,10 +160,12 @@ ensure_env() {
err "STORAGE_SECRET_KEY 长度至少 8 位(MinIO 要求)"
exit 1
fi
check_http_port
}
wait_healthy() {
local url="${1:-http://127.0.0.1:${HTTP_PORT:-80}/health}"
local url="${1:-http://127.0.0.1:${HTTP_PORT:-18080}/health}"
local i
log "等待服务就绪: $url"
for i in $(seq 1 60); do
@@ -121,7 +180,8 @@ wait_healthy() {
}
print_summary() {
local base="${APP_BASE_URL:-http://127.0.0.1:${HTTP_PORT:-80}}"
local port="${HTTP_PORT:-18080}"
local base="${APP_BASE_URL:-http://127.0.0.1:${port}}"
echo
log "========== 部署完成 =========="
echo " 访问地址: ${base}"
@@ -129,14 +189,22 @@ print_summary() {
echo " 健康检查: ${base}/health"
echo " Widget 预览: ${base}/widget/preview"
echo " 图片前缀: ${STORAGE_PUBLIC_BASE_URL}"
echo " 本机探测: http://127.0.0.1:${port}/healthz web 容器映射端口)"
echo
if [[ "$port" != "80" && "$port" != "443" ]]; then
echo " Caddy 共存:"
echo " 1) 确认本机: curl -fsS http://127.0.0.1:${port}/healthz"
echo " 2) 合并 deploy/caddy/Caddyfile.example 到现有 Caddy,反代 127.0.0.1:${port}"
echo " 3) APP_BASE_URL / STORAGE_PUBLIC_BASE_URL 使用 https 域名(不要写 :${port}"
echo
fi
echo " 常用命令:"
echo " 查看状态 ./deploy/scripts/deploy.sh --status"
echo " 查看日志 docker compose -f $COMPOSE_FILE --env-file $ENV_FILE logs -f"
echo " 导入种子 ./deploy/scripts/deploy.sh --seed-only"
echo " 停止服务 ./deploy/scripts/deploy.sh --down"
echo
echo " 安全提示: 安全组仅放行 80/443;改默认密码;生产务必使用 HTTPS。"
echo " 安全提示: 安全组仅放行 22/80/443(不必公网放行 ${port};改默认密码;生产用 HTTPS。"
echo "=============================="
}
@@ -171,8 +239,8 @@ cmd_up() {
compose up -d --remove-orphans
fi
wait_healthy "http://127.0.0.1:${HTTP_PORT:-80}/health" || true
wait_healthy "http://127.0.0.1:${HTTP_PORT:-80}/healthz" || true
wait_healthy "http://127.0.0.1:${HTTP_PORT:-18080}/health" || true
wait_healthy "http://127.0.0.1:${HTTP_PORT:-18080}/healthz" || true
if [[ "$seed" -eq 1 ]]; then
log "导入演示种子数据…"
@@ -204,7 +272,7 @@ cmd_status() {
if [[ -f "$ENV_FILE" ]]; then
compose ps
echo
curl -fsS "http://127.0.0.1:${HTTP_PORT:-80}/health" && echo || warn "health 不可达"
curl -fsS "http://127.0.0.1:${HTTP_PORT:-18080}/health" && echo || warn "health 不可达"
else
err "缺少 $ENV_FILE"
exit 1