diff --git a/README.md b/README.md index ca0dc93ed..7e7510dcf 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,16 @@ sudo docker compose --env-file .env -f docker-compose.deploy.yml logs -f --tail= 默认拉取 `ghcr.io/ddcat-ai/open-ai-canvas-web:latest` 和 `ghcr.io/ddcat-ai/open-ai-canvas-backend:latest`。发布版本还会生成去掉 `v` 前缀的版本标签;如需固定版本,可在 `.env` 中设置 `CANVAS_IMAGE_TAG=1.0.2`。 +### 直接使用 GitHub Packages 镜像 + +如果服务器不需要源码目录,可以使用只拉取 GitHub Container Registry(GHCR)镜像的快速脚本。脚本会下载部署 Compose 文件,不会 clone Git 仓库;首次执行仍会自动安装 Docker、生成 `/opt/open-ai-canvas/.env` 并启动全部服务: + +```bash +curl -fsSL https://raw.githubusercontent.com/ddcat-ai/open-ai-canvas/main/scripts/install-server-image.sh | sudo bash +``` + +默认使用 `latest` 标签。固定版本或修改端口可在首次执行后编辑 `/opt/open-ai-canvas/.env`,然后重新执行脚本;使用私有 GHCR 镜像时,请先执行 `docker login ghcr.io`,或在直接运行脚本时提供 `GHCR_USERNAME` 和 `GHCR_TOKEN` 环境变量完成登录。 + 部署配置和 PostgreSQL 密码保存在 `/opt/open-ai-canvas/.env`,不要发送给他人,也不要删除 `backend-data`、`postgres-data` 和 `redis-data` 数据卷。数据卷持久化不等于备份,请定期备份 PostgreSQL 和上传文件。直接使用 IP 访问仅适合首次配置;公网长期使用必须绑定域名并配置 HTTPS。 ## 本地开发 diff --git a/scripts/install-server-image.sh b/scripts/install-server-image.sh new file mode 100755 index 000000000..a2729dee3 --- /dev/null +++ b/scripts/install-server-image.sh @@ -0,0 +1,157 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +REPOSITORY_REF="${REPOSITORY_REF:-main}" +INSTALL_DIR="${INSTALL_DIR:-/opt/open-ai-canvas}" +CANVAS_HTTP_PORT="${CANVAS_HTTP_PORT:-3000}" +CANVAS_IMAGE_TAG="${CANVAS_IMAGE_TAG:-latest}" +COMPOSE_FILE="docker-compose.deploy.yml" +COMPOSE_URL="${COMPOSE_URL:-https://raw.githubusercontent.com/ddcat-ai/open-ai-canvas/${REPOSITORY_REF}/${COMPOSE_FILE}}" + +step() { + printf '\n==> %s\n' "$1" +} + +fail() { + printf '\n安装失败:%s\n' "$1" >&2 + exit 1 +} + +require_root() { + if [[ "${EUID}" -ne 0 ]]; then + fail "请使用 README 中带 sudo 的一键安装命令" + fi + [[ "$(uname -s)" == "Linux" ]] || fail "一键部署脚本仅支持 Linux 服务器" + [[ "$CANVAS_HTTP_PORT" =~ ^[0-9]+$ ]] || fail "CANVAS_HTTP_PORT 必须是 1 到 65535 的数字" + ((CANVAS_HTTP_PORT >= 1 && CANVAS_HTTP_PORT <= 65535)) || fail "CANVAS_HTTP_PORT 必须是 1 到 65535 的数字" + [[ "$CANVAS_IMAGE_TAG" =~ ^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$ ]] || fail "CANVAS_IMAGE_TAG 不是有效的 Docker 镜像标签" +} + +install_packages() { + local packages=(ca-certificates curl openssl) + + if command -v apt-get >/dev/null 2>&1; then + apt-get update + DEBIAN_FRONTEND=noninteractive apt-get install -y "${packages[@]}" + elif command -v dnf >/dev/null 2>&1; then + dnf install -y "${packages[@]}" + elif command -v yum >/dev/null 2>&1; then + yum install -y "${packages[@]}" + else + fail "暂不支持当前 Linux 发行版,请先手动安装 Docker、curl 和 OpenSSL" + fi +} + +install_docker() { + if command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1; then + return + fi + + step "安装 Docker 和 Docker Compose" + local installer + installer="$(mktemp)" + curl -fsSL https://get.docker.com -o "$installer" + sh "$installer" + rm -f "$installer" + + if command -v systemctl >/dev/null 2>&1; then + systemctl enable --now docker + elif command -v service >/dev/null 2>&1; then + service docker start + fi + + docker compose version >/dev/null 2>&1 || fail "Docker Compose 安装失败" +} + +login_ghcr() { + if [[ -n "${GHCR_USERNAME:-}" || -n "${GHCR_TOKEN:-}" ]]; then + [[ -n "${GHCR_USERNAME:-}" && -n "${GHCR_TOKEN:-}" ]] || fail "GHCR_USERNAME 和 GHCR_TOKEN 必须同时配置" + step "登录 GitHub Container Registry" + # token 只通过 stdin 交给 Docker,避免出现在命令参数和进程列表中。 + printf '%s' "$GHCR_TOKEN" | docker login ghcr.io --username "$GHCR_USERNAME" --password-stdin + fi +} + +prepare_environment() { + mkdir -p "$INSTALL_DIR" + cd "$INSTALL_DIR" + + if [[ -f .env ]]; then + grep -Eq '^POSTGRES_PASSWORD=.+$' .env || fail "现有 .env 缺少 POSTGRES_PASSWORD" + grep -Eq '^DATABASE_URL=.+$' .env || fail "现有 .env 缺少 DATABASE_URL" + + local configured_http_port + configured_http_port="$(sed -n 's/^CANVAS_HTTP_PORT=//p' .env | tail -n 1)" + if [[ -n "$configured_http_port" ]]; then + [[ "$configured_http_port" =~ ^[0-9]+$ ]] || fail ".env 中的 CANVAS_HTTP_PORT 无效" + ((configured_http_port >= 1 && configured_http_port <= 65535)) || fail ".env 中的 CANVAS_HTTP_PORT 无效" + CANVAS_HTTP_PORT="$configured_http_port" + fi + + local configured_image_tag + configured_image_tag="$(sed -n 's/^CANVAS_IMAGE_TAG=//p' .env | tail -n 1)" + if [[ -n "$configured_image_tag" ]]; then + [[ "$configured_image_tag" =~ ^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$ ]] || fail ".env 中的 CANVAS_IMAGE_TAG 无效" + CANVAS_IMAGE_TAG="$configured_image_tag" + fi + return + fi + + step "生成 PostgreSQL 随机密码和部署配置" + local database_password + database_password="$(openssl rand -hex 32)" + umask 077 + cat >.env <