Self-host (Node / standalone)
Run chmonitor on any server using Node.js or Bun. Best for bare VMs, dedicated servers, or any environment where you manage the process directly.
Quick start
Section titled “Quick start”git clone https://github.com/duyet/clickhouse-monitoring.gitcd clickhouse-monitoringbun install
## Set your ClickHouse credentialsexport CLICKHOUSE_HOST='https://clickhouse.example.com:8443'export CLICKHOUSE_USER='monitoring'export CLICKHOUSE_PASSWORD='change-me'
## Build and startbun run buildbun run startOpen http://localhost:3000.
Using .env
Section titled “Using .env”Put env vars in .env.local in the project root (Next.js) or .env for the TanStack app. Never commit credentials.
cat <<'EOF' > .env.localCLICKHOUSE_HOST=https://clickhouse.example.com:8443CLICKHOUSE_USER=monitoringCLICKHOUSE_PASSWORD=change-meCLICKHOUSE_NAME=prodCLICKHOUSE_MAX_EXECUTION_TIME=30CLICKHOUSE_TZ=UTCEOF
bun run startConfigure
Section titled “Configure”ClickHouse connection
Section titled “ClickHouse connection”| Variable | Default | Description |
|---|---|---|
CLICKHOUSE_HOST | — (required) | ClickHouse URL(s), comma-separated |
CLICKHOUSE_USER | default | Username(s), same count as HOST |
CLICKHOUSE_PASSWORD | "" | Password(s), same count as HOST |
CLICKHOUSE_NAME | — | Friendly label(s) for host switcher |
Multiple hosts
Section titled “Multiple hosts”CLICKHOUSE_HOST defines the host count. CLICKHOUSE_USER and CLICKHOUSE_PASSWORD may be a single value (applied to all hosts) or one value per host position. CLICKHOUSE_NAME is optional:
export CLICKHOUSE_HOST='https://ch1:8443,https://ch2:8443'export CLICKHOUSE_USER='monitoring,monitoring'export CLICKHOUSE_PASSWORD='pass1,pass2'export CLICKHOUSE_NAME='shard-1,shard-2'Query / pool tuning
Section titled “Query / pool tuning”| Variable | Default | Description |
|---|---|---|
CLICKHOUSE_MAX_EXECUTION_TIME | 60 | Query timeout in seconds |
CLICKHOUSE_TZ | — | Timezone for queries |
CLICKHOUSE_DATABASE | system | Default database |
CLICKHOUSE_POOL_SIZE | 10 | Connection pool size |
CLICKHOUSE_POOL_TIMEOUT | 300000 | Pool acquire timeout (ms) |
CLICKHOUSE_POOL_CLEANUP_INTERVAL | 60000 | Pool cleanup interval (ms) |
Feature permissions
Section titled “Feature permissions”Via env vars:
export CHM_DISABLED_FEATURES='peerdb,actions'export CHM_AUTH_REQUIRED_FEATURES='agent,settings,mcp'export CHM_FEATURE_AGENT_ACCESS='authenticated'export CHM_FEATURE_SETTINGS_ENABLED='false'Via a config file (TOML):
export CHM_CONFIG_FILE='/etc/chmonitor/config.toml'## /etc/chmonitor/config.toml[features.agent]access = "authenticated"
[features.settings]enabled = false
[features.mcp]access = "authenticated"Feature ids: overview, agent, insights, health, queries, tables, metrics, dashboard, security, logs, settings, cluster, operations, actions, mcp, docs, about.
Authentication
Section titled “Authentication”None (default):
export CHM_AUTH_PROVIDER='none'API key layer:
export CHM_API_KEY_SECRET='a-long-random-secret'Clerk:
export CHM_AUTH_PROVIDER='clerk'export CLERK_SECRET_KEY='sk_live_...'## VITE_* vars must be set at build time, not runtime:## VITE_AUTH_PROVIDER=clerk VITE_CLERK_PUBLISHABLE_KEY=pk_live_... bun run buildProxy — Cloudflare Access:
export CHM_AUTH_PROVIDER='proxy'export CHM_CF_ACCESS_TEAM_DOMAIN='https://yourteam.cloudflareaccess.com'export CHM_CF_ACCESS_AUD='<audience-tag>'Proxy — trusted header (nginx):
Put chmonitor behind nginx. Configure nginx to set an auth header and pass the secret.
export CHM_AUTH_PROVIDER='proxy'export CHM_PROXY_AUTH_HEADER='X-Forwarded-User'export CHM_PROXY_AUTH_SECRET='a-long-random-secret'Without CHM_PROXY_AUTH_SECRET, the trusted-header provider is disabled. See Authentication.
Example nginx config:
upstream chmonitor { server 127.0.0.1:3000;}
server { listen 443 ssl; server_name monitor.example.com;
# Set after your auth module populates $remote_user proxy_set_header X-Forwarded-User $remote_user; proxy_set_header X-Chm-Proxy-Secret "$chm_proxy_secret"; # inject via env/secrets manager, not hardcoded
location / { proxy_pass http://chmonitor; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }}AI agent
Section titled “AI agent”export LLM_API_KEY='sk-...'export LLM_API_BASE='https://openrouter.ai/api/v1'export LLM_MODEL='openrouter/free'export AGENT_API_TOKEN='bearer-token-for-agent-api'export AGENT_ENABLE_CONTROL_TOOLS='false'Keep LLM_API_KEY server-side — never set it as a VITE_* variable.
Conversation store
Section titled “Conversation store”Default: browser localStorage. No server config needed.
Server-side persistence requires VITE_FEATURE_CONVERSATION_DB=true set at build time (a VITE_* build-time variable). Build a custom image or binary with this flag set. At runtime, select the backend:
Postgres store (recommended for self-host):
export CONVERSATION_STORE_BACKEND='postgres'export DATABASE_URL='postgresql://user:pass@host:5432/dbname'AgentState store:
export CONVERSATION_STORE_BACKEND='agentstate'export AGENTSTATE_API_KEY='as_live_...'D1 and Durable Object stores are Cloudflare-only.
Health alerting
Section titled “Health alerting”The health sweep runs at GET /api/cron/health-sweep. Call it from a cron job:
export HEALTH_ALERT_ENABLED='true'export HEALTH_ALERT_WEBHOOK_URL='https://hooks.slack.com/services/...'export HEALTH_ALERT_MIN_SEVERITY='warning'export CRON_SECRET='a-random-secret'Add a crontab entry:
*/5 * * * * curl -sf -H "Authorization: Bearer <CRON_SECRET>" http://localhost:3000/api/cron/health-sweepBranding
Section titled “Branding”Branding vars are inlined at build time:
VITE_TITLE_SHORT=MyCluster VITE_LOGO=/logo.png bun run buildThese are inlined at build time — set them before running bun run build.
systemd unit
Section titled “systemd unit”[Unit]Description=chmonitor ClickHouse dashboardAfter=network.target
[Service]Type=simpleUser=chmonitorWorkingDirectory=/opt/chmonitorEnvironmentFile=/etc/chmonitor/envExecStart=/usr/local/bin/bun run startRestart=alwaysRestartSec=5
[Install]WantedBy=multi-user.targetCreate /etc/chmonitor/env:
CLICKHOUSE_HOST=https://clickhouse.example.com:8443CLICKHOUSE_USER=monitoringCLICKHOUSE_PASSWORD=change-meCHM_AUTH_PROVIDER=noneEnable and start:
systemctl enable --now chmonitorUpgrading
Section titled “Upgrading”cd /opt/chmonitorgit pullbun installbun run buildsystemctl restart chmonitorFor breaking changes between major versions, see Migrating to v0.3.