From 3b55639fbe5b75fc09c9e242296411b5e493a2d1 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Fri, 19 Dec 2025 17:01:58 +0000 Subject: [PATCH] fix(agent): support PULSE_AGENT_CONNECT_URL and improve detection --- docs/CONFIGURATION.md | 5 ++- .../src/components/Settings/UnifiedAgents.tsx | 33 +++++++++++-------- frontend-modern/src/types/config.ts | 1 + 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 745d5ff..c55bbb9 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -100,7 +100,10 @@ Environment variables take precedence over `system.json`. | `debug` | Verbose output including per-guest/storage polling details | > **Tip**: If your syslog is being flooded with Pulse messages, set `LOG_LEVEL=warn` to significantly reduce log volume while still capturing important events. -| `PULSE_PUBLIC_URL` | Public URL for notifications/OIDC | `""` | + +| Variable | Description | Default | +|----------|-------------|---------| +| `PULSE_PUBLIC_URL` | URL for agent install commands, notifications, and OIDC. **Important for reverse proxy setups**: Set this to your internal Pulse URL (e.g., `http://192.168.1.10:7655`) so agents connect directly instead of through the proxy. | Auto-detected | | `ALLOWED_ORIGINS` | CORS allowed domains | `""` (Same origin) | | `DISCOVERY_ENABLED` | Auto-discover nodes | `false` | | `PULSE_ENABLE_SENSOR_PROXY` | Enable legacy `pulse-sensor-proxy` endpoints (deprecated, unsupported) | `false` | diff --git a/frontend-modern/src/components/Settings/UnifiedAgents.tsx b/frontend-modern/src/components/Settings/UnifiedAgents.tsx index 92440fa..6d199f1 100644 --- a/frontend-modern/src/components/Settings/UnifiedAgents.tsx +++ b/frontend-modern/src/components/Settings/UnifiedAgents.tsx @@ -14,7 +14,6 @@ import { getPulseBaseUrl } from '@/utils/url'; import { logger } from '@/utils/logger'; const TOKEN_PLACEHOLDER = ''; -const pulseUrl = () => getPulseBaseUrl(); const buildDefaultTokenName = () => { const now = new Date(); @@ -25,14 +24,16 @@ const buildDefaultTokenName = () => { type AgentPlatform = 'linux' | 'macos' | 'windows'; -const commandsByPlatform: Record< +// Generate platform-specific commands with the appropriate Pulse URL +// Uses agentUrl from API (PULSE_PUBLIC_URL) if configured, otherwise falls back to window.location +const buildCommandsByPlatform = (url: string): Record< AgentPlatform, { title: string; description: string; snippets: { label: string; command: string; note?: string | any }[]; } -> = { +> => ({ linux: { title: 'Install on Linux', description: @@ -40,7 +41,7 @@ const commandsByPlatform: Record< snippets: [ { label: 'Install', - command: `curl -fsSL ${pulseUrl()}/install.sh | sudo bash -s -- --url ${pulseUrl()} --token ${TOKEN_PLACEHOLDER} --interval 30s`, + command: `curl -fsSL ${url}/install.sh | sudo bash -s -- --url ${url} --token ${TOKEN_PLACEHOLDER} --interval 30s`, note: ( Automatically detects your init system (systemd, OpenRC, Unraid, Synology) and configures the appropriate service. Works on Debian, Ubuntu, Fedora, Alpine, Gentoo, Unraid, Synology, and more. @@ -56,7 +57,7 @@ const commandsByPlatform: Record< snippets: [ { label: 'Install with launchd', - command: `curl -fsSL ${pulseUrl()}/install.sh | sudo bash -s -- --url ${pulseUrl()} --token ${TOKEN_PLACEHOLDER} --interval 30s`, + command: `curl -fsSL ${url}/install.sh | sudo bash -s -- --url ${url} --token ${TOKEN_PLACEHOLDER} --interval 30s`, note: ( Creates /Library/LaunchDaemons/com.pulse.agent.plist and starts the agent automatically. @@ -72,7 +73,7 @@ const commandsByPlatform: Record< snippets: [ { label: 'Install as Windows Service (PowerShell)', - command: `irm ${pulseUrl()}/install.ps1 | iex`, + command: `irm ${url}/install.ps1 | iex`, note: ( Run in PowerShell as Administrator. The script will prompt for the Pulse URL and API token, download the agent binary, and install it as a Windows service with automatic startup. @@ -81,7 +82,7 @@ const commandsByPlatform: Record< }, { label: 'Install with parameters (PowerShell)', - command: `$env:PULSE_URL="${pulseUrl()}"; $env:PULSE_TOKEN="${TOKEN_PLACEHOLDER}"; irm ${pulseUrl()}/install.ps1 | iex`, + command: `$env:PULSE_URL="${url}"; $env:PULSE_TOKEN="${TOKEN_PLACEHOLDER}"; irm ${url}/install.ps1 | iex`, note: ( Non-interactive installation. Set environment variables before running to skip prompts. @@ -90,7 +91,7 @@ const commandsByPlatform: Record< }, ], }, -}; +}); export const UnifiedAgents: Component = () => { const { state } = useWebSocket(); @@ -118,12 +119,16 @@ export const UnifiedAgents: Component = () => { } }); - const commandSections = createMemo(() => - Object.entries(commandsByPlatform).map(([platform, meta]) => ({ + // Use agentUrl from API (PULSE_PUBLIC_URL) if configured, otherwise fall back to window.location + const agentUrl = () => securityStatus()?.agentUrl || getPulseBaseUrl(); + + const commandSections = createMemo(() => { + const commands = buildCommandsByPlatform(agentUrl()); + return Object.entries(commands).map(([platform, meta]) => ({ platform: platform as AgentPlatform, ...meta, - })), - ); + })); + }); const connectedFromStatus = (status: string | undefined | null) => { if (!status) return false; @@ -238,7 +243,7 @@ export const UnifiedAgents: Component = () => { const getCurlInsecureFlag = () => insecureMode() ? '-k' : ''; const getUninstallCommand = () => { - return `curl ${getCurlInsecureFlag()}-fsSL ${pulseUrl()}/install.sh | sudo bash -s -- --uninstall`; + return `curl ${getCurlInsecureFlag()}-fsSL ${agentUrl()}/install.sh | sudo bash -s -- --uninstall`; }; // Track previously seen host types to prevent flapping when one source temporarily has no data @@ -370,7 +375,7 @@ export const UnifiedAgents: Component = () => { const getUpgradeCommand = (_hostname: string) => { const token = resolvedToken(); - return `curl ${getCurlInsecureFlag()}-fsSL ${pulseUrl()}/install.sh | sudo bash -s -- --url ${pulseUrl()} --token ${token}${getInsecureFlag()}`; + return `curl ${getCurlInsecureFlag()}-fsSL ${agentUrl()}/install.sh | sudo bash -s -- --url ${agentUrl()} --token ${token}${getInsecureFlag()}`; }; const handleRemoveAgent = async (id: string, type: 'host' | 'docker' | 'kubernetes') => { diff --git a/frontend-modern/src/types/config.ts b/frontend-modern/src/types/config.ts index dc7a780..fe428c3 100644 --- a/frontend-modern/src/types/config.ts +++ b/frontend-modern/src/types/config.ts @@ -123,6 +123,7 @@ export interface SecurityStatus { deprecatedDisableAuth?: boolean; message?: string; hideLocalLogin?: boolean; // Hide local login form + agentUrl?: string; // URL for agent install commands (from PULSE_PUBLIC_URL or auto-detected) } /**