Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 8 additions & 17 deletions Caddyfile
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
# OpenViking aggregated reverse proxy
#
# Port 1934 merges the API server (1933) and Console (8020) under one origin.
# This block always serves plain HTTP — suitable for local dev, internal
# networks, and as an upstream behind your own TLS-terminating proxy.
# Port 1934 fronts the OV server (1933) under one stable origin. This block
# always serves plain HTTP — suitable for local dev, internal networks, and
# as an upstream behind your own TLS-terminating proxy.
#
# Web Studio (the in-server SPA) is served by OV itself at `/studio`, so a
# single upstream is all that's needed here.
#
# To add public HTTPS, append a domain block below (Caddy auto-provisions
# Let's Encrypt certs):
#
# {$OPENVIKING_PUBLIC_BASE_URL} {
# @console path /console /console/*
# handle @console {
# reverse_proxy openviking:8020
# }
# handle {
# reverse_proxy openviking:1933
# }
# reverse_proxy openviking:1933
# # Optional: pin ACME email
# # tls {$OV_ACME_EMAIL}
# }
Expand All @@ -23,11 +20,5 @@
# OPENVIKING_PUBLIC_BASE_URL=https://your-domain.com in .env.

:1934 {
@console path /console /console/*
handle @console {
reverse_proxy openviking:8020
}
handle {
reverse_proxy openviking:1933
}
reverse_proxy openviking:1933
}
58 changes: 30 additions & 28 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,26 @@
# ragfs-python's default S3-enabled dependency set currently requires rustc >= 1.91.1.
FROM rust:1.91.1-trixie AS rust-toolchain

# Stage 2: build Python environment with uv (builds Rust CLI + C++ extension from source)
# Stage 2: build web-studio static bundle (Vite SPA). Runs before py-builder so
# the dist can be copied into openviking/web_studio/dist/ and included in the
# python wheel via package-data — no separate runtime COPY required.
#
# WEB_STUDIO_BASE_PATH is passed to `vite build --base=...` and is also
# consumed at runtime by getRouterBasePath() through import.meta.env.BASE_URL,
# so the SPA's asset URLs and TanStack Router basepath stay in sync.
FROM node:20-bookworm-slim AS web-studio-builder
WORKDIR /web-studio
ARG TARGETPLATFORM
ARG WEB_STUDIO_BASE_PATH=/studio/

COPY web-studio/package.json web-studio/package-lock.json ./
RUN --mount=type=cache,target=/root/.npm,id=npm-${TARGETPLATFORM} \
npm ci

COPY web-studio/ ./
RUN npm run build -- --base="${WEB_STUDIO_BASE_PATH}"

# Stage 3: build Python environment with uv (builds Rust CLI + C++ extension from source)
FROM ghcr.io/astral-sh/uv:python3.13-trixie-slim AS py-builder

# Reuse Rust toolchain from stage 1 so setup.py can compile ov CLI in-place.
Expand Down Expand Up @@ -49,6 +68,11 @@ COPY openviking_cli/ openviking_cli/
COPY src/ src/
COPY third_party/ third_party/

# Bundle the prebuilt web-studio dist into the openviking python package so the
# wheel produced by `uv sync` ships /studio assets out of the box (parallel to
# the legacy openviking/console/static layout, just for the new SPA).
COPY --from=web-studio-builder /web-studio/dist /app/openviking/web_studio/dist

# Install project and dependencies (triggers setup.py artifact builds + build_extension).
# Default to auto-refreshing uv.lock inside the ephemeral build context when it is
# stale, so Docker builds stay unblocked after dependency changes. Set
Expand Down Expand Up @@ -82,26 +106,6 @@ RUN --mount=type=cache,target=/root/.cache/uv,id=uv-${TARGETPLATFORM} \
;; \
esac

# Stage 3: build web-studio static bundle (Vite SPA).
# Produces /web-studio/dist which the runtime stage mounts at /studio in the
# OpenViking server. Lockfile-first dependency install keeps the layer cached
# until package.json / lockfile actually change.
#
# WEB_STUDIO_BASE_PATH is passed to `vite build --base=...` and is also
# consumed at runtime by getRouterBasePath() through import.meta.env.BASE_URL,
# so the SPA's asset URLs and TanStack Router basepath stay in sync.
FROM node:20-bookworm-slim AS web-studio-builder
WORKDIR /web-studio
ARG TARGETPLATFORM
ARG WEB_STUDIO_BASE_PATH=/studio/

COPY web-studio/package.json web-studio/package-lock.json ./
RUN --mount=type=cache,target=/root/.npm,id=npm-${TARGETPLATFORM} \
npm ci

COPY web-studio/ ./
RUN npm run build -- --base="${WEB_STUDIO_BASE_PATH}"

# Stage 4: runtime
FROM python:3.13-slim-trixie

Expand All @@ -114,18 +118,16 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
WORKDIR /app

COPY --from=py-builder /app/.venv /app/.venv
COPY --from=web-studio-builder /web-studio/dist /app/web-studio/dist
COPY docker/openviking-console-entrypoint.sh /usr/local/bin/openviking-console-entrypoint
COPY docker/openviking-entrypoint.sh /usr/local/bin/openviking-entrypoint
COPY docker/pending_health_server.py /usr/local/bin/openviking-pending-health
RUN mkdir -p /app/.openviking \
&& chmod +x /usr/local/bin/openviking-console-entrypoint /usr/local/bin/openviking-pending-health
&& chmod +x /usr/local/bin/openviking-entrypoint /usr/local/bin/openviking-pending-health
ENV HOME="/app" \
PATH="/app/.venv/bin:$PATH" \
OPENVIKING_CONFIG_FILE="/app/.openviking/ov.conf" \
OPENVIKING_CLI_CONFIG_FILE="/app/.openviking/ovcli.conf" \
OPENVIKING_WEB_STUDIO_DIR="/app/web-studio/dist"
OPENVIKING_CLI_CONFIG_FILE="/app/.openviking/ovcli.conf"

EXPOSE 1933 8020
EXPOSE 1933

HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
CMD curl -fsS http://127.0.0.1:1933/health || exit 1
Expand All @@ -138,4 +140,4 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
# JSON, or `docker exec` in and run `openviking-server init`.
# Override command to run CLI, e.g.:
# docker run --rm -v ~/.openviking:/app/.openviking <image> openviking --help
ENTRYPOINT ["openviking-console-entrypoint"]
ENTRYPOINT ["openviking-entrypoint"]
10 changes: 4 additions & 6 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ services:
openviking:
image: ghcr.io/volcengine/openviking:latest
container_name: openviking
# Direct access to individual services (optional — caddy:1934 is the
# recommended single entry point). Comment these out once Caddy is your
# only ingress.
# Direct access (optional — caddy:1934 is the recommended single entry
# point). Comment this out once Caddy is your only ingress.
ports:
- "1933:1933"
- "8020:8020"
volumes:
- ~/.openviking:/app/.openviking
environment:
Expand All @@ -34,8 +32,8 @@ services:
start_period: 30s
restart: unless-stopped

# Aggregated reverse proxy — merges API (1933) + Console (8020) on port
# 1934 under one origin. Always enabled, plain HTTP by default.
# Aggregated reverse proxy — fronts OV (1933) on port 1934 under one stable
# origin. Always enabled, plain HTTP by default.
#
# For public HTTPS: edit the Caddyfile to add a domain block, set
# OPENVIKING_PUBLIC_BASE_URL in .env, uncomment the 80/443 port lines
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,11 @@ set -eu

SERVER_URL="http://127.0.0.1:1933"
SERVER_HEALTH_URL="${SERVER_URL}/health"
SERVER_READY_URL="${SERVER_URL}/ready"
CONSOLE_PORT="${OPENVIKING_CONSOLE_PORT:-8020}"
CONSOLE_HOST="${OPENVIKING_CONSOLE_HOST:-0.0.0.0}"
WITH_BOT="${OPENVIKING_WITH_BOT:-1}"
HEALTH_MAX_ATTEMPTS="${OPENVIKING_HEALTH_MAX_ATTEMPTS:-120}"
READY_MAX_ATTEMPTS="${OPENVIKING_READY_MAX_ATTEMPTS:-300}"
CONFIG_FILE="${OPENVIKING_CONFIG_FILE:-/app/.openviking/ov.conf}"
PENDING_HEALTH_SCRIPT="/usr/local/bin/openviking-pending-health"
SERVER_PID=""
CONSOLE_PID=""
PENDING_PID=""

stop_pending_health() {
Expand All @@ -30,11 +25,11 @@ ensure_config() {
mkdir -p "$(dirname "${CONFIG_FILE}")"
if [ -n "${OPENVIKING_CONF_CONTENT:-}" ]; then
printf '%s' "${OPENVIKING_CONF_CONTENT}" > "${CONFIG_FILE}"
echo "[openviking-console-entrypoint] wrote ${CONFIG_FILE} from OPENVIKING_CONF_CONTENT"
echo "[openviking-entrypoint] wrote ${CONFIG_FILE} from OPENVIKING_CONF_CONTENT"
return
fi
cat >&2 <<EOF
[openviking-console-entrypoint] ${CONFIG_FILE} not found.
[openviking-entrypoint] ${CONFIG_FILE} not found.

To start OpenViking, do one of:
- mount ~/.openviking on the host to /app/.openviking
Expand All @@ -52,7 +47,7 @@ EOF

while [ ! -f "${CONFIG_FILE}" ]; do
if ! kill -0 "${PENDING_PID}" 2>/dev/null; then
echo "[openviking-console-entrypoint] pending health server exited unexpectedly" >&2
echo "[openviking-entrypoint] pending health server exited unexpectedly" >&2
PENDING_PID=""
exit 1
fi
Expand All @@ -61,7 +56,7 @@ EOF

stop_pending_health
trap - INT TERM
echo "[openviking-console-entrypoint] detected ${CONFIG_FILE}, starting OpenViking"
echo "[openviking-entrypoint] detected ${CONFIG_FILE}, starting OpenViking"
}

normalize_with_bot() {
Expand All @@ -73,7 +68,7 @@ normalize_with_bot() {
WITH_BOT="0"
;;
*)
echo "[openviking-console-entrypoint] invalid OPENVIKING_WITH_BOT=${1}" >&2
echo "[openviking-entrypoint] invalid OPENVIKING_WITH_BOT=${1}" >&2
exit 2
;;
esac
Expand Down Expand Up @@ -102,9 +97,6 @@ forward_signal() {
if [ -n "${SERVER_PID}" ] && kill -0 "${SERVER_PID}" 2>/dev/null; then
kill "${SERVER_PID}" 2>/dev/null || true
fi
if [ -n "${CONSOLE_PID}" ] && kill -0 "${CONSOLE_PID}" 2>/dev/null; then
kill "${CONSOLE_PID}" 2>/dev/null || true
fi
}

trap 'forward_signal' INT TERM
Expand All @@ -122,58 +114,19 @@ attempt=0
until curl -fsS "${SERVER_HEALTH_URL}" >/dev/null 2>&1; do
attempt=$((attempt + 1))
if ! kill -0 "${SERVER_PID}" 2>/dev/null; then
echo "[openviking-console-entrypoint] openviking-server exited before becoming healthy" >&2
echo "[openviking-entrypoint] openviking-server exited before becoming healthy" >&2
wait "${SERVER_PID}" || true
exit 1
fi
if [ "${attempt}" -ge "${HEALTH_MAX_ATTEMPTS}" ]; then
echo "[openviking-console-entrypoint] timed out waiting for ${SERVER_HEALTH_URL}" >&2
echo "[openviking-entrypoint] timed out waiting for ${SERVER_HEALTH_URL}" >&2
forward_signal
wait "${SERVER_PID}" || true
exit 1
fi
sleep 1
done
echo "[openviking-entrypoint] openviking-server is healthy"

# Wait for server to become fully ready before starting console
ready_attempt=0
until curl -fsS "${SERVER_READY_URL}" 2>/dev/null | grep -q '"status":"ready"'; do
ready_attempt=$((ready_attempt + 1))
if ! kill -0 "${SERVER_PID}" 2>/dev/null; then
echo "[openviking-console-entrypoint] openviking-server exited before becoming ready" >&2
wait "${SERVER_PID}" || true
exit 1
fi
if [ "${ready_attempt}" -ge "${READY_MAX_ATTEMPTS}" ]; then
echo "[openviking-console-entrypoint] timed out waiting for ${SERVER_READY_URL}" >&2
forward_signal
wait "${SERVER_PID}" || true
exit 1
fi
sleep 2
done
echo "[openviking-console-entrypoint] openviking-server is ready"

python -m openviking.console.bootstrap \
--host "${CONSOLE_HOST}" \
--port "${CONSOLE_PORT}" \
--openviking-url "${SERVER_URL}" &
CONSOLE_PID=$!

while kill -0 "${SERVER_PID}" 2>/dev/null && kill -0 "${CONSOLE_PID}" 2>/dev/null; do
sleep 1
done

if ! kill -0 "${SERVER_PID}" 2>/dev/null; then
wait "${SERVER_PID}" || SERVER_STATUS=$?
SERVER_STATUS=${SERVER_STATUS:-1}
forward_signal
wait "${CONSOLE_PID}" || true
exit "${SERVER_STATUS}"
fi

wait "${CONSOLE_PID}" || CONSOLE_STATUS=$?
CONSOLE_STATUS=${CONSOLE_STATUS:-0}
forward_signal
wait "${SERVER_PID}" || true
exit "${CONSOLE_STATUS}"
wait "${SERVER_PID}" || SERVER_STATUS=$?
exit "${SERVER_STATUS:-0}"
4 changes: 1 addition & 3 deletions docs/en/getting-started/02-quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ If you prefer to run OpenViking as a standalone service, Docker is recommended.
container_name: openviking
ports:
- "1933:1933"
- "8020:8020"
volumes:
- ~/.openviking:/app/.openviking
restart: unless-stopped
Expand All @@ -50,7 +49,7 @@ If you prefer to run OpenViking as a standalone service, Docker is recommended.
docker-compose up -d
```

By default, the container starts the OpenViking API server on `1933`, the Console UI on `8020`, and the bundled `vikingbot` gateway. If you need to disable `vikingbot`, add either `command: ["--without-bot"]` or `environment: ["OPENVIKING_WITH_BOT=0"]`.
By default, the container starts the OpenViking API server on `1933` (which also serves the Web Studio UI at `/studio`) and the bundled `vikingbot` gateway. If you need to disable `vikingbot`, add either `command: ["--without-bot"]` or `environment: ["OPENVIKING_WITH_BOT=0"]`.

On platforms that don't allow bind mounts, set `OPENVIKING_CONF_CONTENT` to the full config JSON to bootstrap on first start, or `docker exec` in and run `openviking-server init` after the container is up. See [Deployment Guide](../guides/03-deployment.md#when-docker--v-is-not-available) for details.

Expand All @@ -65,7 +64,6 @@ If you prefer to run OpenViking as a standalone service, Docker is recommended.
> openviking:
> image: ghcr.io/volcengine/openviking:latest
> ports:
> - "8020:8020"
> - "1933:1934" # Map host 1933 to container 1934
> volumes:
> - ~/.openviking:/app/.openviking
Expand Down
4 changes: 1 addition & 3 deletions docs/zh/getting-started/02-quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ pip install openviking --upgrade --force-reinstall
container_name: openviking
ports:
- "1933:1933"
- "8020:8020"
volumes:
- ~/.openviking:/app/.openviking
restart: unless-stopped
Expand All @@ -50,7 +49,7 @@ pip install openviking --upgrade --force-reinstall
docker-compose up -d
```

默认情况下,容器会同时启动 OpenViking API 服务(`1933`)、Console 界面(`8020`)以及内置的 `vikingbot` gateway。如果你需要关闭 `vikingbot`,可以在 Compose 里增加 `command: ["--without-bot"]`,或者设置 `environment: ["OPENVIKING_WITH_BOT=0"]`。
默认情况下,容器会启动 OpenViking API 服务(`1933`,同时在 `/studio` 提供 Web Studio 前端)以及内置的 `vikingbot` gateway。如果你需要关闭 `vikingbot`,可以在 Compose 里增加 `command: ["--without-bot"]`,或者设置 `environment: ["OPENVIKING_WITH_BOT=0"]`。

如果运行平台不支持 bind mount,可以通过 `OPENVIKING_CONF_CONTENT` 环境变量传入完整的配置 JSON,或在容器启动后 `docker exec` 进去执行 `openviking-server init`。详见 [部署指南](../guides/03-deployment.md#无法使用-docker--v-时)。

Expand All @@ -65,7 +64,6 @@ pip install openviking --upgrade --force-reinstall
> openviking:
> image: ghcr.io/volcengine/openviking:latest
> ports:
> - "8020:8020"
> - "1933:1934" # 将宿主机 1933 映射到容器 1934
> volumes:
> - ~/.openviking:/app/.openviking
Expand Down
Loading
Loading