Deployment
Deploy Vdoc with one docker-compose.yml. Settings, accounts, passwords, and internal keys all live in this file. No .env, initialization scripts, or source checkout is required.
Install Docker Engine / Docker Desktop and Docker Compose v2. Published Linux images support amd64 and arm64. The example below runs locally; existing installations should read Upgrade and Rollback first.
1. Download the Compose File
Download docker-compose.yml into a dedicated deployment directory, or run:
mkdir vdoc-deploy
cd vdoc-deploy
curl -fLO https://chnmig.github.io/Vdoc-site/downloads/docker-compose.yml
chmod 600 docker-compose.ymlThe website serves the current stable release. For a specific version, download the same YAML from the v0.3.0 Release. Its docker-compose.yml.sha256 attachment can verify the downloaded bytes.
2. Fill In Settings and Your Login
Edit docker-compose.yml, replace every CHANGE_ME value, and set the administrator email and name. Quote passwords in YAML. Write a literal $ as $$ so Compose does not interpret it as an environment variable.
| Setting | Purpose |
|---|---|
VDOC_DATABASE_PASSWORD | PostgreSQL password, shared with its container through a YAML anchor |
VDOC_STORAGE_ACCESS_KEY / VDOC_STORAGE_SECRET_KEY | RustFS account and password, also shared through anchors |
VDOC_JWT_KEY | Signs and verifies login credentials; use an independent random key of at least 32 characters |
VDOC_MCP_TOKEN_CIPHER_KEY | Encrypts stored MCP tokens, AI Provider keys, and share capabilities; use another random key of at least 32 characters |
VDOC_INITIAL_ADMIN_EMAIL / VDOC_INITIAL_ADMIN_NAME | Initial administrator email and name |
VDOC_INITIAL_ADMIN_PASSWORD | Initial administrator password, 12–72 bytes |
RustFS requires an access key of at least 3 characters and a secret key of at least 8 characters. Generate values with a password manager, or run openssl rand -hex 32 separately for the JWT and MCP keys.
You supply these values and keep them in Compose; the backend does not create a separate key file. Preserve them during upgrades. Changing the JWT key invalidates existing login credentials; losing the MCP encryption key prevents reading affected stored ciphertext. Keep your completed YAML private.
The initial administrator is created only when the user table is empty. Restarting or upgrading does not create duplicates or overwrite passwords changed later by users. Public registration is disabled by default; the backend refuses to start with an empty database and no usable administrator configuration.
3. Start Vdoc
docker compose pull
docker compose up -d
docker compose psCompose first runs config-check once. If placeholders remain or required settings are invalid, validation fails before PostgreSQL or RustFS initializes. Correct the YAML and run docker compose up -d again.
After validation, Compose starts PostgreSQL, RustFS, Backend, and Admin. Backend creates tables, applies pending database migrations, creates the storage bucket, and initializes the first administrator during startup. An Exited (0) status for the completed config-check container is expected.
Open the Vdoc workbench and sign in with your configured administrator account. Backend health is available at http://127.0.0.1:8080/api/v1/open/health.
Next: publish your first document and query it with an agent.
Complete Compose Example
This example includes all settings, four persistent services, a one-shot configuration check, health checks, and data volumes. It reads directly from the published YAML source and matches the download. Replace the placeholders before starting.
# Save this file as docker-compose.yml. Replace every CHANGE_ME value below.
# Keep this private file, its credentials, and the project name when upgrading.
# Use Docker Compose v2: docker compose pull && docker compose up -d
name: vdoc
x-backend-image: &backend-image ghcr.io/chnmig/vdoc:v0.3.0
x-admin-image: &admin-image ghcr.io/chnmig/vdoc-admin:v0.3.0
# All deployment settings are here; no .env or initialization script is needed.
# A literal dollar sign in any value must be written as $$ for Docker Compose.
x-backend-environment: &backend-environment
model: release
VDOC_SERVER_PORT: "8080"
VDOC_SERVER_PID_FILE: ""
VDOC_SERVER_CORS_ALLOWED_ORIGINS: "http://127.0.0.1:8081,http://localhost:8081"
VDOC_DATABASE_ENABLED: "true"
VDOC_DATABASE_HOST: postgres
VDOC_DATABASE_PORT: "5432"
VDOC_DATABASE_NAME: &database-name vdoc
VDOC_DATABASE_USER: &database-user vdoc
VDOC_DATABASE_PASSWORD: &database-password "CHANGE_ME_DATABASE_PASSWORD"
VDOC_DATABASE_SSL_MODE: disable
VDOC_STORAGE_ENABLED: "true"
VDOC_STORAGE_ENDPOINT: rustfs:9000
VDOC_STORAGE_BUCKET: vdoc
VDOC_STORAGE_ACCESS_KEY: &storage-user "CHANGE_ME_STORAGE_ACCESS_KEY"
VDOC_STORAGE_SECRET_KEY: &storage-password "CHANGE_ME_STORAGE_SECRET_KEY"
VDOC_STORAGE_USE_SSL: "false"
VDOC_STORAGE_PATH_STYLE: "true"
# Use independent random keys of at least 32 characters. Preserve on upgrade.
VDOC_JWT_KEY: "CHANGE_ME_JWT_KEY"
VDOC_MCP_TOKEN_CIPHER_KEY: "CHANGE_ME_MCP_ENCRYPTION_KEY"
VDOC_MCP_TOKEN_CIPHER_KID: local-aes-gcm-v1
VDOC_MCP_TOKEN_CIPHER_KEYRING: "{}"
VDOC_AUTH_ALLOW_REGISTRATION: "false"
VDOC_INITIAL_ADMIN_EMAIL: "admin@example.com"
VDOC_INITIAL_ADMIN_NAME: "Vdoc Admin"
VDOC_INITIAL_ADMIN_PASSWORD: "CHANGE_ME_INITIAL_ADMIN_PASSWORD"
services:
# Runs the backend's read-only validator before PostgreSQL initializes data.
config-check:
image: *backend-image
command: ["--check-config"]
environment: *backend-environment
restart: "no"
healthcheck:
disable: true
postgres:
image: postgres:18@sha256:06cad38a5d9f5d24b4d83d86def30795d5e4b757fedbf5281172b576dedcd941
restart: unless-stopped
depends_on:
config-check:
condition: service_completed_successfully
environment:
POSTGRES_DB: *database-name
POSTGRES_USER: *database-user
POSTGRES_PASSWORD: *database-password
TZ: Asia/Shanghai
volumes:
- postgres-data:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 10s
timeout: 5s
retries: 10
rustfs:
image: rustfs/rustfs:1.0.0-beta.10@sha256:60f4f2f41ce95216f8cac676e69f9d90c0bfec458a3bc7fd7fb9b7c2452ac57a
restart: unless-stopped
depends_on:
config-check:
condition: service_completed_successfully
environment:
RUSTFS_VOLUMES: /data
RUSTFS_ADDRESS: 0.0.0.0:9000
RUSTFS_CONSOLE_ADDRESS: 0.0.0.0:9001
RUSTFS_CONSOLE_ENABLE: "true"
RUSTFS_ACCESS_KEY: *storage-user
RUSTFS_SECRET_KEY: *storage-password
volumes:
- rustfs-data:/data
- rustfs-logs:/app/logs
healthcheck:
test: ["CMD-SHELL", "curl -f http://127.0.0.1:9000/health"]
interval: 10s
timeout: 5s
retries: 12
start_period: 40s
backend:
image: *backend-image
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
rustfs:
condition: service_healthy
environment: *backend-environment
ports:
- "127.0.0.1:8080:8080"
admin:
image: *admin-image
restart: unless-stopped
depends_on:
backend:
condition: service_healthy
environment:
VDOC_ADMIN_API_BASE_URL: "http://127.0.0.1:8080"
ports:
- "127.0.0.1:8081:8080"
healthcheck:
test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1:8080/ || exit 1"]
interval: 10s
timeout: 5s
retries: 6
volumes:
postgres-data:
rustfs-data:
rustfs-logs:Update the Version
Back up your data, update the x-backend-image and x-admin-image version tags in your existing YAML, and preserve all other settings. Then run:
docker compose pull
docker compose up -dBackend applies migrations included in the new version; completed migrations are not repeated. This does not track the latest release automatically: the deployer chooses when to update. A failed migration prevents normal backend startup. Follow Upgrade and Rollback to inspect failures and recover.
Daily Management and Persistence
Run these commands from the directory containing your YAML:
docker compose ps
docker compose logs --tail=100 backend admin postgres rustfs
docker compose stop
docker compose up -ddocker compose down removes containers and networks while preserving named volumes. Do not use docker compose down -v for data you need to keep: it deletes postgres-data, rustfs-data, and rustfs-logs. Keep the Compose project name vdoc; changing it selects different volumes.
PostgreSQL 18 mounts its data volume at /var/lib/postgresql. Vdoc application migrations do not upgrade the PostgreSQL major version. Older database majors require a separate pg_upgrade or dump/restore procedure.
Deploy on a Server
Ports bind to 127.0.0.1 by default, suitable for local access or an HTTPS reverse proxy on the same server. PostgreSQL and RustFS are available only inside the Compose network.
For server domains, set VDOC_ADMIN_API_BASE_URL to the browser-accessible HTTPS backend URL and VDOC_SERVER_CORS_ALLOWED_ORIGINS to the exact HTTPS workbench origin in YAML. If your proxy runs in another container or host, also adjust ports or networking so it can reach Backend and Admin.
Backend uses postgres:5432 and rustfs:9000 internally. Do not use http://backend:8080 as the browser API URL: browsers cannot resolve Compose service names. Apply configuration edits with docker compose up -d.
Source Development and Advanced Settings
Application deployments do not require the source bootstrap archive. To modify code, run disposable E2E tests, or use external database/object storage services, see the public workspace deployment guide. The source workspace retains .env, test database scripts, and exact source locks for development and release verification.
Key rotation must account for stored ciphertext; replacing a key alone is insufficient. Follow the operations guide to configure historical KIDs and the keyring, and verify the rewrite before removing old keys.