Comprehensive documentation updates: API.md: - Add /api/security/change-password endpoint - Add AI provider test endpoints - Add assistant chat & session management endpoints - Add legacy chat sessions endpoints - Add alert investigation and patrol autonomy endpoints - Add findings & investigations endpoints - Add approvals & command execution endpoints - Add remediation plans endpoints - Add intelligence & forecasting endpoints - Add knowledge base endpoints - Add debug endpoint - Add Socket.IO compatibility endpoint Config files: - Document sso.enc, ai_chat_sessions.json - Document profile-versions.json, profile-changelog.json, profile-deployments.json
21 KiB
⚙️ Configuration Guide
Pulse uses a split-configuration model to ensure security and flexibility.
| File | Purpose | Security Level |
|---|---|---|
.env |
Authentication & Secrets | 🔒 Critical (Read-only by owner) |
.encryption.key |
Encryption key for .enc files |
🔒 Critical |
.audit-signing.key |
Audit log signing key (Pulse Pro, encrypted) | 🔒 Sensitive |
system.json |
General Settings | 📝 Standard |
nodes.enc |
Node Credentials | 🔒 Encrypted (AES-256-GCM) |
alerts.json |
Alert Rules | 📝 Standard |
email.enc |
SMTP settings | 🔒 Encrypted |
webhooks.enc |
Webhook URLs + headers | 🔒 Encrypted |
apprise.enc |
Apprise notification config | 🔒 Encrypted |
oidc.enc |
OIDC provider config | 🔒 Encrypted |
sso.enc |
SAML/SSO provider config | 🔒 Encrypted |
api_tokens.json |
API token records (hashed) | 🔒 Sensitive |
env_token_suppressions.json |
Suppressed legacy env tokens (migration aid) | 📝 Standard |
ai.enc |
AI settings and credentials | 🔒 Encrypted |
ai_findings.json |
AI Patrol findings | 📝 Standard |
ai_patrol_runs.json |
AI Patrol run history | 📝 Standard |
ai_usage_history.json |
AI usage history | 📝 Standard |
ai_chat_sessions.json |
Legacy AI chat sessions (UI sync) | 📝 Standard |
license.enc |
Pulse Pro license key | 🔒 Encrypted |
host_metadata.json |
Host notes, tags, and AI command overrides | 📝 Standard |
docker_metadata.json |
Docker metadata cache | 📝 Standard |
guest_metadata.json |
Guest notes and metadata | 📝 Standard |
agent_profiles.json |
Agent configuration profiles (Pulse Pro) | 📝 Standard |
agent_profile_assignments.json |
Agent profile assignments (Pulse Pro) | 📝 Standard |
profile-versions.json |
Agent profile version history (Pulse Pro) | 📝 Standard |
profile-deployments.json |
Agent profile deployment status (Pulse Pro) | 📝 Standard |
profile-changelog.json |
Agent profile change log (Pulse Pro) | 📝 Standard |
recovery_tokens.json |
Recovery tokens (short-lived) | 🔒 Sensitive |
sessions.json |
Persistent sessions (includes OIDC refresh tokens) | 🔒 Sensitive |
update-history.jsonl |
Update history log (in-app updates) | 📝 Standard |
metrics.db |
Persistent metrics history (SQLite) | 📝 Standard |
audit.db |
Audit log database (Pulse Pro, SQLite) | 🔒 Sensitive |
baselines.json |
AI baseline data for anomaly detection | 📝 Standard |
ai_correlations.json |
AI correlation analysis cache | 📝 Standard |
ai_patterns.json |
AI pattern detection data | 📝 Standard |
ai_remediations.json |
AI remediation suggestions | 📝 Standard |
ai_incidents.json |
AI incident tracking | 📝 Standard |
org.json |
Organization metadata (multi-tenant) | 📝 Standard |
Guest metadata entries are keyed by the canonical guest ID format instance:node:vmid (for example, pve1:node1:100). Legacy dash-separated keys are migrated automatically.
All files are located in /etc/pulse/ (Systemd) or /data/ (Docker/Kubernetes) by default.
Path overrides:
PULSE_DATA_DIRsets the base directory forsystem.json, encrypted files, and the bootstrap token.
Multi-tenant layout:
- Default org uses the root data directory for backward compatibility.
- Non-default orgs store data under
/orgs/<org-id>/. - Migration may create
/orgs/default/and symlinks in the root data directory.
🔐 Authentication (.env)
This file controls access to Pulse. It is never exposed to the UI.
# /etc/pulse/.env
# Admin Credentials (bcrypt hashed; plain text auto-hashes on startup)
PULSE_AUTH_USER='admin'
PULSE_AUTH_PASS='$2a$12$...'
# Legacy API tokens (deprecated, auto-migrated to api_tokens.json)
API_TOKEN='token1'
API_TOKENS='token2,token3'
Advanced: Automated Setup (Skip UI)
You can pre-configure Pulse by setting environment variables. Plain text credentials are automatically hashed on startup.
# Docker Example
docker run -d \
-e PULSE_AUTH_USER=admin \
-e PULSE_AUTH_PASS=secret123 \
-e API_TOKENS=ci-token,agent-token \
rcourtman/pulse:latest
Advanced: OIDC / SSO
Configure Single Sign-On in Settings → Security → Single Sign-On, or use environment variables to lock the configuration.
See OIDC Documentation and Proxy Auth for details.
Environment overrides (lock the corresponding UI fields):
| Variable | Description |
|---|---|
OIDC_ENABLED |
Enable OIDC (true/false) |
OIDC_ISSUER_URL |
Issuer URL from your IdP |
OIDC_CLIENT_ID |
Client ID |
OIDC_CLIENT_SECRET |
Client secret |
OIDC_REDIRECT_URL |
Override redirect URL (defaults to <public-url>/api/oidc/callback) |
OIDC_LOGOUT_URL |
Optional logout URL |
OIDC_SCOPES |
Space or comma-separated scopes |
OIDC_USERNAME_CLAIM |
Claim for username (default: preferred_username) |
OIDC_EMAIL_CLAIM |
Claim for email (default: email) |
OIDC_GROUPS_CLAIM |
Claim for groups |
OIDC_ALLOWED_GROUPS |
Allowed groups (space or comma-separated) |
OIDC_ALLOWED_DOMAINS |
Allowed email domains (space or comma-separated) |
OIDC_ALLOWED_EMAILS |
Allowed emails (space or comma-separated) |
OIDC_GROUP_ROLE_MAPPINGS |
Comma-separated group=role mappings (Pulse Pro) |
OIDC_CA_BUNDLE |
Custom CA bundle path |
Legacy token flag (backwards compatibility):
| Variable | Description |
|---|---|
API_TOKEN_ENABLED |
Legacy toggle for API token auth (defaults to enabled when tokens exist) |
Note
:
API_TOKEN/API_TOKENSare legacy and will be migrated intoapi_tokens.jsonon startup. Manage API tokens in the UI for long-term support.
🖥️ System Settings (system.json)
Controls runtime behavior like logging, polling intervals, and UI preferences. Legacy port fields in system.json are ignored; use FRONTEND_PORT instead.
Example system.json
{
"pvePollingInterval": 10, // Seconds
"backendPort": 3000, // Legacy (unused)
"frontendPort": 7655, // Legacy (ignored; use FRONTEND_PORT)
"logLevel": "info", // debug, info, warn, error
"autoUpdateEnabled": false, // Enable auto-update checks
"adaptivePollingEnabled": false, // Smart polling for large clusters
"allowedOrigins": "", // CORS allowlist (single origin or "*")
"allowEmbedding": false, // Allow iframe embedding
"allowedEmbedOrigins": "", // Comma-separated origins for iframe embedding
"webhookAllowedPrivateCIDRs": "" // Allowlist for private webhook targets
}
Note
:
logFormatis only configurable via theLOG_FORMATenvironment variable, not insystem.json. Note:autoUpdateTimeis stored by the UI, but the systemd timer uses its own schedule.
Supported system.json Keys
Numeric intervals are seconds unless noted otherwise.
| Key | Description |
|---|---|
pvePollingInterval |
PVE polling interval |
pbsPollingInterval |
PBS polling interval |
pmgPollingInterval |
PMG polling interval |
backupPollingInterval |
Backup polling interval (0 = auto) |
backupPollingEnabled |
Enable backup polling |
adaptivePollingEnabled |
Enable adaptive polling |
adaptivePollingBaseInterval |
Base interval for adaptive polling |
adaptivePollingMinInterval |
Minimum adaptive polling interval |
adaptivePollingMaxInterval |
Maximum adaptive polling interval |
connectionTimeout |
API connection timeout |
logLevel |
Server log level (debug, info, warn, error) |
allowedOrigins |
CORS allowlist (single origin or *) |
allowEmbedding |
Allow iframe embedding |
allowedEmbedOrigins |
Comma-separated frame-ancestors allowlist |
webhookAllowedPrivateCIDRs |
Allowlist for private webhook targets |
updateChannel |
Update channel (stable or rc) |
autoUpdateEnabled |
Allow one-click updates |
autoUpdateCheckInterval |
Update check interval (hours) |
autoUpdateTime |
UI-stored preferred update time |
publicURL |
Public URL used in links/notifications |
hideLocalLogin |
Hide username/password login form |
temperatureMonitoringEnabled |
Enable temperature monitoring (where supported) |
dnsCacheTimeout |
DNS cache timeout |
sshPort |
Default SSH port for temperature collection |
discoveryEnabled |
Enable auto-discovery |
discoverySubnet |
CIDR or auto |
discoveryConfig |
Discovery tuning object (see below) |
theme |
UI theme (light, dark, or empty for system) |
fullWidthMode |
UI layout preference |
metricsRetentionRawHours |
Raw metrics retention (hours) |
metricsRetentionMinuteHours |
Minute metrics retention (hours) |
metricsRetentionHourlyDays |
Hourly metrics retention (days) |
metricsRetentionDailyDays |
Daily metrics retention (days) |
disableDockerUpdateActions |
Hide Docker update actions in UI |
backendPort |
Legacy (unused) |
frontendPort |
Legacy (ignored; use FRONTEND_PORT) |
discoveryConfig supports:
environment_override,subnet_allowlist,subnet_blocklist,ip_blocklistmax_hosts_per_scan,max_concurrent,enable_reverse_dns,scan_gatewaysdial_timeout_ms,http_timeout_ms
Common Overrides (Environment Variables)
Environment variables take precedence over system.json.
| Variable | Description | Default |
|---|---|---|
FRONTEND_PORT |
Public listening port | 7655 |
PORT |
Legacy alias for FRONTEND_PORT |
(unset) |
LOG_LEVEL |
Log verbosity (see below) | info |
LOG_FORMAT |
Log output format (auto, json, console) |
auto |
LOG_FILE |
Log file path (enables file logging) | (unset) |
LOG_MAX_SIZE |
Log rotation size (MB) | 100 |
LOG_MAX_AGE |
Keep rotated logs for N days (0 disables cleanup) |
30 |
LOG_COMPRESS |
Gzip rotated logs | true |
Log Levels
| Level | Description |
|---|---|
error |
Only errors and critical issues |
warn |
Errors + warnings (recommended for minimal logging) |
info |
Standard operational messages (startup, connections, alerts) |
debug |
Verbose output including per-guest/storage polling details |
Tip
: If your syslog is being flooded with Pulse messages, set
LOG_LEVEL=warnto significantly reduce log volume while still capturing important events.
| Variable | Description | Default |
|---|---|---|
PULSE_PUBLIC_URL |
URL for UI links, notifications, and OIDC. For reverse proxies, keep this as the public URL and use PULSE_AGENT_CONNECT_URL for agent installs if you need a direct/internal address. |
Auto-detected |
PULSE_AGENT_CONNECT_URL |
Dedicated direct URL for agents (overrides PULSE_PUBLIC_URL for agent install commands). Alias: PULSE_AGENT_URL. |
(unset) |
PULSE_AGENT_CONFIG_SIGNING_KEY |
Base64 Ed25519 private key used to sign remote agent config payloads. | (unset) |
PULSE_AGENT_CONFIG_PUBLIC_KEYS |
Comma-separated base64 Ed25519 public keys (raw 32-byte or PKIX-encoded) trusted by agents. | (unset) |
PULSE_AGENT_CONFIG_SIGNATURE_REQUIRED |
Require signed remote config payloads (set on Pulse and agents). | false |
ALLOWED_ORIGINS |
CORS allowed origin (* or a single origin). Empty = same-origin only. |
(unset) |
DISCOVERY_ENABLED |
Auto-discover nodes | false |
DISCOVERY_SUBNET |
CIDR or auto |
auto |
DISCOVERY_ENVIRONMENT_OVERRIDE |
Force discovery environment (auto, native, docker_host, docker_bridge, lxc_privileged, lxc_unprivileged) |
auto |
DISCOVERY_SUBNET_ALLOWLIST |
Comma-separated CIDRs allowed for discovery | (empty) |
DISCOVERY_SUBNET_BLOCKLIST |
Comma-separated CIDRs excluded from discovery | 169.254.0.0/16 |
DISCOVERY_MAX_HOSTS_PER_SCAN |
Max hosts to scan per run | 1024 |
DISCOVERY_MAX_CONCURRENT |
Max concurrent discovery probes | 50 |
DISCOVERY_ENABLE_REVERSE_DNS |
Enable reverse DNS lookup (true/false) |
true |
DISCOVERY_SCAN_GATEWAYS |
Include gateway IPs in discovery (true/false) |
true |
DISCOVERY_DIAL_TIMEOUT_MS |
TCP dial timeout (ms) | 1000 |
DISCOVERY_HTTP_TIMEOUT_MS |
HTTP probe timeout (ms) | 2000 |
PULSE_AUTH_HIDE_LOCAL_LOGIN |
Hide username/password form | false |
DEMO_MODE |
Enable read-only demo mode | false |
PULSE_TRUSTED_PROXY_CIDRS |
Comma-separated IPs/CIDRs trusted to supply X-Forwarded-For/X-Real-IP |
(unset) |
PULSE_TRUSTED_NETWORKS |
Comma-separated CIDRs treated as trusted local networks (does not bypass auth) | (unset) |
ALLOW_UNPROTECTED_EXPORT |
Allow unauthenticated config export on public networks when no auth is configured (use with caution) | false |
Iframe Embedding (system.json)
Embedding is controlled by system.json and the UI (Settings → System → Network):
allowEmbedding(boolean): enables iframe embeddingallowedEmbedOrigins(comma-separated): restrictsframe-ancestorswhen embedding is enabled
When allowEmbedding is false, Pulse sends X-Frame-Options: DENY and frame-ancestors 'none'.
Monitoring Overrides
| Variable | Description | Default |
|---|---|---|
PVE_POLLING_INTERVAL |
PVE metrics polling frequency | 10s |
PBS_POLLING_INTERVAL |
PBS metrics polling frequency | 60s |
PMG_POLLING_INTERVAL |
PMG metrics polling frequency | 60s |
CONNECTION_TIMEOUT |
API connection timeout | 60s |
BACKUP_POLLING_CYCLES |
Poll cycles between backup checks | 10 |
ENABLE_BACKUP_POLLING |
Enable backup job monitoring | true |
BACKUP_POLLING_INTERVAL |
Backup polling frequency | 0 (Auto) |
ENABLE_TEMPERATURE_MONITORING |
Enable temperature monitoring (where supported) | true |
SSH_PORT |
SSH port for temperature collection over SSH | 22 |
ADAPTIVE_POLLING_ENABLED |
Enable smart polling for large clusters | false |
ADAPTIVE_POLLING_BASE_INTERVAL |
Base interval for adaptive polling | 10s |
ADAPTIVE_POLLING_MIN_INTERVAL |
Minimum adaptive polling interval | 5s |
ADAPTIVE_POLLING_MAX_INTERVAL |
Maximum adaptive polling interval | 5m |
GUEST_METADATA_MIN_REFRESH_INTERVAL |
Minimum refresh for guest metadata | 2m |
GUEST_METADATA_REFRESH_JITTER |
Jitter for guest metadata refresh | 45s |
GUEST_METADATA_RETRY_BACKOFF |
Retry backoff for guest metadata | 30s |
GUEST_METADATA_MAX_CONCURRENT |
Max concurrent guest metadata fetches | 4 |
DNS_CACHE_TIMEOUT |
Cache TTL for DNS lookups | 5m |
MAX_POLL_TIMEOUT |
Maximum time per polling cycle | 3m |
PULSE_DISABLE_DOCKER_UPDATE_ACTIONS |
Hide Docker update buttons (read-only mode) | false |
Logging Overrides
| Variable | Description | Default |
|---|---|---|
LOG_FILE |
Log file path (empty = stderr only) | (unset) |
LOG_MAX_SIZE |
Log file max size (MB) | 100 |
LOG_MAX_AGE |
Log file retention (days, 0 disables cleanup) |
30 |
LOG_COMPRESS |
Compress rotated logs | true |
Update Settings (system.json)
These are stored in system.json and managed via the UI.
| Key | Description | Default |
|---|---|---|
updateChannel |
Update channel (stable or rc) |
stable |
autoUpdateEnabled |
Allow one-click updates | false |
autoUpdateCheckInterval |
Background update check interval in hours (0 disables) |
24 |
autoUpdateTime |
Stored UI preference (systemd timer has its own schedule) | 03:00 |
Note
: Update settings are stored in
system.json. Legacy.enventries (UPDATE_CHANNEL,AUTO_UPDATE_ENABLED,AUTO_UPDATE_CHECK_INTERVAL,AUTO_UPDATE_TIME) are kept in sync for backwards compatibility but are not read at runtime.
Auto-Import (Bootstrap)
You can auto-import an encrypted backup on first startup. This is useful for automated provisioning and test environments.
| Variable | Description |
|---|---|
PULSE_INIT_CONFIG_DATA |
Base64 or raw contents of an export bundle (auto-imports on first start) |
PULSE_INIT_CONFIG_FILE |
Path to an export bundle on disk (auto-imports on first start) |
PULSE_INIT_CONFIG_PASSPHRASE |
Passphrase for the export bundle (required) |
Note
:
PULSE_INIT_CONFIG_URLis only supported by the hiddenpulse config auto-importcommand, not by the server startup auto-import.
Developer/Test Overrides (Environment Variables)
These are primarily for development or test harnesses and should not be used in production.
| Variable | Description | Default |
|---|---|---|
PULSE_UPDATE_SERVER |
Override update server base URL (testing only) | (unset) |
PULSE_UPDATE_STAGE_DELAY_MS |
Adds artificial delays between update stages (testing only) | (unset) |
PULSE_ALLOW_DOCKER_UPDATES |
Expose update UI/actions in Docker (debug only) | false |
PULSE_DEV_ALLOW_CONTAINER_SSH |
Allow SSH-based temperature collection from containers (dev/test only) | false |
PULSE_AI_ALLOW_LOOPBACK |
Allow AI tool HTTP fetches to loopback addresses | false |
PULSE_LICENSE_PUBLIC_KEY |
Override embedded license public key (base64, dev only) | (unset) |
PULSE_LICENSE_DEV_MODE |
Skip license verification (development only) | false |
Metrics Retention (Tiered)
Persistent metrics history uses tiered retention windows. These values are stored in system.json and can be adjusted for storage vs history depth:
metricsRetentionRawHoursmetricsRetentionMinuteHoursmetricsRetentionHourlyDaysmetricsRetentionDailyDays
See METRICS_HISTORY.md for details.
🔔 Alerts (alerts.json)
Pulse uses a powerful alerting engine with hysteresis (separate trigger/clear thresholds) to prevent flapping.
Managed via UI: Alerts → Thresholds
Manual Configuration (JSON)
{
"guestDefaults": {
"cpu": { "trigger": 90, "clear": 80 },
"memory": { "trigger": 85, "clear": 72.5 }
},
"schedule": {
"quietHours": {
"enabled": true,
"start": "22:00",
"end": "06:00"
}
}
}
🔒 HTTPS / TLS
Enable HTTPS by providing certificate files via environment variables.
# Systemd
HTTPS_ENABLED=true
TLS_CERT_FILE=/etc/pulse/cert.pem
TLS_KEY_FILE=/etc/pulse/key.pem
# Docker
docker run --init -e HTTPS_ENABLED=true \
-v /path/to/certs:/certs \
-e TLS_CERT_FILE=/certs/cert.pem \
-e TLS_KEY_FILE=/certs/key.pem ...
Important (Docker with HTTPS): Always use
--init(orinit: truein docker-compose) when enabling HTTPS. The Alpine-based healthcheck uses busyboxwget, which spawnsssl_clientsubprocesses. Without an init process to reap them, these become zombie processes over time.
🛡️ Security Best Practices
- Permissions: Ensure
.envandnodes.encare600(read/write by owner only). - Backups: Back up
.envseparately fromsystem.json. - Tokens: Use scoped API tokens for agents instead of the admin password.
🔑 API Tokens
API tokens provide scoped, revocable access to Pulse. Manage tokens in Settings → Security → API Tokens.
Token Scopes
| Scope | Description |
|---|---|
* (Full access) |
All permissions (legacy, not recommended) |
monitoring:read |
View dashboards, metrics, alerts |
monitoring:write |
Acknowledge/silence alerts |
docker:report |
Container agent telemetry submission |
docker:manage |
Container lifecycle actions (restart, stop) |
kubernetes:report |
Kubernetes agent telemetry submission |
kubernetes:manage |
Kubernetes cluster management |
host-agent:report |
Host agent metrics submission |
host-agent:config:read |
Read host-agent config payloads |
host-agent:manage |
Manage host agents (unlink/delete/config) |
settings:read |
Read configuration |
settings:write |
Modify configuration |
Presets
The UI offers quick presets for common use cases:
| Preset | Scopes | Use Case |
|---|---|---|
| Kiosk / Dashboard | monitoring:read |
Read-only dashboard displays |
| Host agent | host-agent:report |
Host agent authentication |
| Container report | docker:report |
Container agent (read-only) |
| Container manage | docker:report, docker:manage |
Container agent with actions |
| Settings read | settings:read |
Read-only config access |
| Settings admin | settings:read, settings:write |
Full config access |
Kiosk Mode
For unattended displays (wall monitors, dashboards), use a kiosk token to avoid cookie persistence issues:
- Go to Settings → Security → API Tokens
- Click New token and select the Kiosk / Dashboard preset
- Copy the generated token
- Access Pulse via URL with token:
https://your-pulse-url/?token=YOUR_TOKEN_HERE
Kiosk tokens:
- Grant read-only dashboard access (
monitoring:readscope) - Hide the Settings tab automatically
- Work without cookies (token in URL)
- Can be revoked anytime from the UI
Security note: URL tokens appear in browser history and server logs. Use only for read-only dashboard access on trusted networks.