# vault-cortex — remote quickstart (Obsidian Sync) # # Run vault-cortex on a VPS with Obsidian Sync for remote access from any device. # Three services: init-config-perms → obsidian-sync → vault-mcp. # # 1. cp .env.example .env (then fill in required values) # 2. docker compose up -d # 3. Connect your MCP client to http://:8000/mcp # # Full docs: https://github.com/aliasunder/vault-cortex name: vault-cortex services: # Workaround: the upstream Dockerfile creates /home/obsidian/.config as # root. Docker named volumes inherit this root ownership, so the obsidian # user (UID 1000) can't write sync state. This init container chowns the # volume before obsidian-sync starts. # Remove when upstream fixes: github.com/Belphemur/obsidian-headless-sync-docker init-config-perms: image: alpine:latest command: sh -c "chown -R ${PUID:-1000}:${PGID:-1000} /config" volumes: - obsidian_config:/config restart: "no" obsidian-sync: image: ghcr.io/belphemur/obsidian-headless-sync-docker:latest container_name: obsidian-sync restart: unless-stopped depends_on: init-config-perms: condition: service_completed_successfully environment: OBSIDIAN_AUTH_TOKEN: "${OBSIDIAN_AUTH_TOKEN:?Set OBSIDIAN_AUTH_TOKEN — see .env.example}" VAULT_NAME: "${VAULT_NAME:?Set VAULT_NAME to your Obsidian vault name (case-sensitive)}" VAULT_PASSWORD: ${VAULT_PASSWORD:-} PUID: ${PUID:-1000} PGID: ${PGID:-1000} DEVICE_NAME: ${DEVICE_NAME:-vault-cortex} CONFLICT_STRATEGY: ${CONFLICT_STRATEGY:-merge} SYNC_MODE: ${SYNC_MODE:-bidirectional} TZ: ${TZ:-UTC} volumes: - vault_data:/vault - obsidian_config:/home/obsidian/.config healthcheck: test: ["CMD-SHELL", "test -d /vault && pgrep -f 'ob sync' >/dev/null"] interval: 30s timeout: 5s retries: 5 start_period: 60s logging: driver: json-file options: { max-size: "10m", max-file: "3" } vault-mcp: image: ghcr.io/aliasunder/vault-mcp:latest container_name: vault-mcp restart: unless-stopped depends_on: obsidian-sync: condition: service_started environment: PORT: "8000" HOST: "0.0.0.0" VAULT_PATH: /vault INDEX_DB_PATH: /data/index.db MCP_AUTH_TOKEN: "${MCP_AUTH_TOKEN:?Set MCP_AUTH_TOKEN in .env — see .env.example}" PUBLIC_URL: "${PUBLIC_URL:?Set PUBLIC_URL to your server's public URL}" MEMORY_DIR: ${MEMORY_DIR:-About Me} LOG_LEVEL: ${LOG_LEVEL:-info} LOG_DIR: ${LOG_DIR:-/data/logs} LOG_RETENTION_DAYS: ${LOG_RETENTION_DAYS:-30} TZ: ${TZ:-UTC} # Optional overrides. When unset, the server applies smart defaults # ( below is the resolved MEMORY_DIR value, default "About Me"): # PROTECTED_PATHS default: ", Daily Notes" (blocked from vault_delete_note) # ORPHAN_EXCLUDE_FOLDERS default: "Daily Notes, Templates, " (excluded from vault_find_orphans) # SERVICE_DOCUMENTATION_URL default: https://github.com/aliasunder/vault-cortex # PROTECTED_PATHS: ${PROTECTED_PATHS:-} # ORPHAN_EXCLUDE_FOLDERS: ${ORPHAN_EXCLUDE_FOLDERS:-} # SERVICE_DOCUMENTATION_URL: ${SERVICE_DOCUMENTATION_URL:-} volumes: - vault_data:/vault:rw - mcp_data:/data ports: - "0.0.0.0:${PORT:-8000}:8000" healthcheck: test: [ "CMD", "node", "-e", "fetch('http://127.0.0.1:8000/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))", ] interval: 15s timeout: 5s retries: 3 start_period: 20s logging: driver: json-file options: { max-size: "10m", max-file: "3" } volumes: vault_data: mcp_data: obsidian_config: