Deployment
Codex2API
Docker Compose 一键部署
适用于已经安装 Docker Engine 与 Docker Compose v2 的 Linux 服务器。默认公开监听 8080 端口,数据保存在 Docker 命名卷中。
执行前
- 终端使用能执行 Bash 的 SSH 会话
- 运行时Docker Engine 与
docker compose - 网络服务器防火墙或安全组放行 TCP 8080
SSH
完整部署命令
bash <<'CODEX2API_DEPLOY'
set -Eeuo pipefail
APP_DIR="${APP_DIR:-$HOME/codex2api}"
PORT="${PORT:-8080}"
BIND_HOST="${BIND_HOST:-0.0.0.0}"
TIMEZONE="${TIMEZONE:-Asia/Shanghai}"
IMAGE="${IMAGE:-ghcr.io/james-6-23/codex2api:latest}"
WAIT_SECONDS="${WAIT_SECONDS:-120}"
fail() {
printf '[FAIL] %s\n' "$*" >&2
exit 1
}
random_hex() {
local bytes="$1"
if command -v openssl >/dev/null 2>&1; then
openssl rand -hex "$bytes"
else
od -An -N "$bytes" -tx1 /dev/urandom | tr -d ' \n'
fi
}
env_value() {
local key="$1"
sed -n "s/^${key}=//p" .env | head -n 1
}
command -v docker >/dev/null 2>&1 || fail "未找到 Docker Engine"
docker info >/dev/null 2>&1 || fail "Docker daemon 未运行,或当前用户没有权限"
docker compose version >/dev/null 2>&1 || fail "需要 Docker Compose v2"
command -v curl >/dev/null 2>&1 || fail "未找到 curl"
[[ "$PORT" =~ ^[0-9]+$ ]] && (( PORT >= 1 && PORT <= 65535 )) || fail "PORT 必须是 1-65535"
umask 077
mkdir -p "$APP_DIR/logs"
cd "$APP_DIR"
APP_DIR="$(pwd -P)"
if [[ -f .env ]]; then
printf '[INFO] 保留现有配置:%s/.env\n' "$APP_DIR"
else
ADMIN_SECRET="adm_$(random_hex 24)"
IMAGE_ASSET_SIGNING_SECRET="$(random_hex 32)"
cat > .env <<ENV_FILE
BIND_HOST=$BIND_HOST
CODEX_PORT=$PORT
CODEX_BIND=0.0.0.0
ADMIN_SECRET=$ADMIN_SECRET
CODEX_ALLOW_ANONYMOUS=false
DATABASE_DRIVER=sqlite
DATABASE_PATH=/data/codex2api.db
CACHE_DRIVER=memory
IMAGE_ASSET_DIR=/data/images
IMAGE_ASSET_SIGNING_SECRET=$IMAGE_ASSET_SIGNING_SECRET
LOG_DIR=/app/logs
LOG_DISABLED=false
TZ=$TIMEZONE
CODEX2API_IMAGE=$IMAGE
ENV_FILE
chmod 600 .env
fi
cat > docker-compose.yml <<'COMPOSE_FILE'
name: codex2api-sqlite
services:
codex2api:
image: "${CODEX2API_IMAGE:-ghcr.io/james-6-23/codex2api:latest}"
container_name: codex2api-sqlite
restart: unless-stopped
env_file:
- .env
ports:
- "${BIND_HOST:-0.0.0.0}:${CODEX_PORT:-8080}:${CODEX_PORT:-8080}"
volumes:
- codex2api-data:/data
- ./logs:/app/logs
logging:
driver: json-file
options:
max-size: 20m
max-file: "5"
security_opt:
- no-new-privileges:true
volumes:
codex2api-data:
name: codex2api-sqlite_sqlite-data
COMPOSE_FILE
chmod 600 docker-compose.yml
docker compose config --quiet
docker compose pull
docker compose up -d --remove-orphans
ACTIVE_PORT="$(env_value CODEX_PORT)"
ACTIVE_BIND="$(env_value BIND_HOST)"
ACTIVE_PORT="${ACTIVE_PORT:-8080}"
ACTIVE_BIND="${ACTIVE_BIND:-0.0.0.0}"
PROBE_HOST="$ACTIVE_BIND"
[[ "$PROBE_HOST" == "0.0.0.0" ]] && PROBE_HOST="127.0.0.1"
HEALTH_URL="http://${PROBE_HOST}:${ACTIVE_PORT}/health"
printf '[INFO] 等待健康检查:%s\n' "$HEALTH_URL"
deadline=$((SECONDS + WAIT_SECONDS))
until curl --fail --silent --show-error --max-time 4 --output /dev/null "$HEALTH_URL"; do
if (( SECONDS >= deadline )); then
docker compose logs --tail=120 codex2api >&2 || true
fail "${WAIT_SECONDS} 秒内健康检查未通过"
fi
if [[ "$(docker inspect --format '{{.State.Running}}' codex2api-sqlite 2>/dev/null || true)" != "true" ]]; then
docker compose logs --tail=120 codex2api >&2 || true
fail "容器已退出"
fi
sleep 2
done
DISPLAY_HOST="$ACTIVE_BIND"
if [[ "$DISPLAY_HOST" == "0.0.0.0" ]]; then
DISPLAY_HOST="${SERVER_IP:-$(hostname -I 2>/dev/null | awk '{print $1}')}"
DISPLAY_HOST="${DISPLAY_HOST:-<服务器IP>}"
fi
printf '\n[OK] Codex2API 已部署并通过健康检查\n'
printf '部署目录:%s\n' "$APP_DIR"
printf '管理后台:http://%s:%s/admin/\n' "$DISPLAY_HOST" "$ACTIVE_PORT"
printf 'API Base URL:http://%s:%s/v1\n' "$DISPLAY_HOST" "$ACTIVE_PORT"
printf '管理密码:%s\n' "$(env_value ADMIN_SECRET)"
printf '首次登录后,请在“API Keys”页面创建调用密钥。\n'
CODEX2API_DEPLOY
部署完成后
管理后台
http://服务器IP:8080/admin/健康检查
http://服务器IP:8080/healthAPI 地址
http://服务器IP:8080/v1脚本会在终端显示随机管理密码。首次登录后台后,在“API Keys”页面创建调用密钥;匿名 API 访问保持关闭。
常用维护命令
查看日志
cd ~/codex2api && docker compose logs -f codex2api拉取更新
cd ~/codex2api && docker compose pull && docker compose up -d停止服务
cd ~/codex2api && docker compose down停止服务不要附加 -v;命名卷承载 SQLite 数据、图库与持久化配置。