mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-26 13:39:47 +00:00
8a99b16d6c
Audited the customer-facing docs against the code: about 5,200 concrete claims (env vars, endpoints, flags, defaults, ports, UI labels), plus every environment variable the code reads. Each discrepancy was re-verified against the source before editing, and every edit was reviewed again. What users would have hit following the old text: - UI paths and labels that no longer exist (Settings > Relay, Platform connections, Access Control, SSO Providers, Create Organization) and Patrol mode names (now Ask first, Safe auto-fix, Autopilot). - Wrong values and behaviour: LOG_MAX_AGE=0 does not disable cleanup, Patrol evidence budget is 10 calls and 12 turns, ALLOW_UNPROTECTED_EXPORT covers private networks too, PULSE_AUDIT_ASYNC defaults on. - Agent install: install.sh ignores PULSE_ENABLE_KUBERNETES and PULSE_ENABLE_PROXMOX, rejects --disable-auto-update, and the token fallback lives in the state directory. - API: audit endpoints answer 402 on Community, onboarding QR is GET, type=container is rejected, several routes need admin plus a scope. - HTTP_REDIRECT_PORT was not documented anywhere. Docs are mirrored under frontend-modern/public/docs, so each change is applied to both copies. The tests that pinned the old wording (including three that asserted claims the code contradicts) are updated alongside. Contract-Neutral: Customer docs corrected to match shipped behaviour; no runtime, API or contract change.
433 lines
22 KiB
Markdown
433 lines
22 KiB
Markdown
# Pulse Server Automatic Updates
|
|
|
|
Pulse supports one-click server updates for supported deployment types. This
|
|
document describes the Pulse server runtime, not installed Pulse Agents.
|
|
|
|
See [Releases and update channels](RELEASE_PROCESS.md) for Stable and Preview
|
|
expectations, beta and RC testing stages, and the checks required before a release
|
|
becomes stable.
|
|
|
|
Eligible v6 agents update asynchronously through their own update client. A
|
|
server update changes their target version but does not prove fleet convergence.
|
|
For v5, PVE, disabled, or failed agent updates, use **Agent Doctor** at
|
|
`/settings/infrastructure?agentDoctor=1` or the installer in
|
|
**Settings → Infrastructure → Install on a host**. See
|
|
[Unified Agent](UNIFIED_AGENT.md#auto-update).
|
|
|
|
## Supported Deployment Types
|
|
|
|
| Deployment | Auto-Update | Method |
|
|
|------------|-------------|--------|
|
|
| **ProxmoxVE LXC** | ✅ Yes | In-app update button |
|
|
| **Systemd Service** | ✅ Yes | In-app update button |
|
|
| **Docker** | ❌ Manual | Pull new image |
|
|
| **Source Build** | ❌ Manual | Build, then install through the existing deployment procedure |
|
|
|
|
## Using One-Click Updates
|
|
|
|
### When an Update is Available
|
|
|
|
1. Navigate to **Settings → System → Updates**
|
|
2. If an update is available, you'll see an **"Install Update"** button
|
|
3. Click the button to open the confirmation dialog
|
|
4. Review the update details:
|
|
- Current version → New version
|
|
- Major-version or pre-release warning, when the update carries one
|
|
- Estimated time and prerequisites, when listed
|
|
- Root-access notice, when the update requires root
|
|
- Automatic backup notice, when rollback is supported
|
|
5. Click **"Start Update"** in the confirmation dialog to begin
|
|
|
|
### Update Process
|
|
|
|
1. **Download**: New version is downloaded, its signature and checksum are verified
|
|
2. **Validate**: The new binary is executed with `--version` to prove it runs on this host and reports the expected version, before anything is touched
|
|
3. **Backup**: Current installation is backed up
|
|
4. **Apply**: Files are updated
|
|
5. **Restart**: Service restarts automatically
|
|
6. **Verify**: Health check confirms success
|
|
|
|
### Progress Tracking
|
|
|
|
A real-time progress modal shows:
|
|
- Current step
|
|
- Download progress
|
|
- Any warnings or errors
|
|
- Automatic page reload on success
|
|
|
|
## Configuration
|
|
|
|
### Update Preferences
|
|
|
|
In **Settings → System → Updates**:
|
|
|
|
| Setting | Description |
|
|
|---------|-------------|
|
|
| **Update Channel** | Stable (recommended for production) or Preview (opt-in beta builds and release candidates) |
|
|
| **Automatic Stable Updates** | Allow unattended stable updates on supported host installations with an installed update timer |
|
|
|
|
The update timer must already be installed and enabled for unattended updates.
|
|
Saving the UI preference does not provision or start a missing timer. Check the
|
|
existing deployment rather than editing `system.json` or creating another
|
|
update service to make the preference take effect.
|
|
|
|
For a failed or uncertain unattended update, use
|
|
[timer-only containment](#pause-further-unattended-attempts-without-stopping-pulse)
|
|
to pause further scheduled attempts without stopping Pulse.
|
|
|
|
### Stored Settings (system.json)
|
|
|
|
Auto-update preferences are stored in `system.json` and edited via the UI.
|
|
|
|
```json
|
|
{
|
|
"autoUpdateEnabled": false,
|
|
"updateChannel": "stable"
|
|
}
|
|
```
|
|
|
|
**Note:** The update schedule itself lives in the systemd timer (daily at 02:00 plus up to 4 hours of random delay), not in `system.json`. The legacy `autoUpdateCheckInterval` and `autoUpdateTime` fields were never consumed by anything and are ignored if present in older files.
|
|
|
|
**Channel policy note:** `stable` is the default and only recommended channel for paid or production environments. `rc` remains the internal channel key, but the user-facing meaning is an explicit pre-release preview path. In v6, unattended systemd auto-updates remain `stable`-only even if `updateChannel` is set to `rc`.
|
|
|
|
## Manual Update Methods
|
|
|
|
Before updating, record the running server version and edition, preserve the
|
|
existing deployment definition privately, and keep a consistent
|
|
[full-state backup](MIGRATION.md#full-state-recovery) with its matching keys.
|
|
An update interrupts monitoring and alert delivery. Follow
|
|
[update preparation and recovery limits](DEPLOYMENT_MODELS.md#updates-by-model);
|
|
do not update during a backup, freeze/thaw or an unresponsive-guest incident.
|
|
|
|
### Docker
|
|
|
|
Use [Docker server updates](DOCKER.md#-updates). Change the configured image to
|
|
the exact release first, then pull and recreate only the Pulse service with the
|
|
same mounted data. Pulling another tag alone does not change the image in your
|
|
Compose file. Do not run `docker compose down` for a Pulse-only update or remove
|
|
its data volume.
|
|
|
|
Private Pro installs must keep the private image supplied by the
|
|
[download page](https://pulserelay.pro/download.html); replacing it with
|
|
`rcourtman/pulse` changes the runtime edition. Server updates and monitored
|
|
container updates are separate operations.
|
|
|
|
### ProxmoxVE LXC (Manual)
|
|
|
|
Work **inside the existing Pulse LXC**, not on the Proxmox host or a monitored
|
|
guest. Follow the [existing-installation update procedure](INSTALL.md#-updates),
|
|
including its helper-ownership check. On a community-scripts installation,
|
|
`/bin/update` can be a different updater; its filename does not establish that
|
|
it uses Pulse's signed installer or accepts an exact target version.
|
|
|
|
### Systemd Service (Manual)
|
|
|
|
Follow the [existing-installation update procedure](INSTALL.md#-updates) using
|
|
the actual installed server service, paths and update helper. Do not run a
|
|
helper whose owner is unknown or apply default installation paths over a
|
|
custom deployment. Server updates do not install or update `pulse-agent`;
|
|
agent installation commands come from **Settings → Infrastructure → Install
|
|
on a host**.
|
|
|
|
### A helper selects a Helm-chart release
|
|
|
|
A Pulse server release uses a tag such as `vX.Y.Z`. A `helm-chart-*` release
|
|
contains a Kubernetes chart, not the Linux server archive. A helper selecting
|
|
a chart does not establish that Pulse's server release is missing or that
|
|
GitHub's latest-release pointer is wrong; preserve the selected tag and error.
|
|
|
|
Do not supply a GitHub personal access token, bypass signatures or change
|
|
permissions to make that helper continue. An unknown helper may ignore
|
|
`--version`; even a Pulse-owned helper must download its installer before the
|
|
installer can apply that option. Adding the flag is not proof of an exact or
|
|
successful update.
|
|
|
|
Before another attempt, check the running version and service health and
|
|
preserve the existing container, configuration, keys and history. Do not
|
|
recreate the LXC or install a second server to recover from release selection.
|
|
For a public Community server, the
|
|
[existing-installation procedure](INSTALL.md#-updates) links the signed
|
|
server-installer flow with an exact `PULSE_VERSION`; use it only after checking
|
|
the installed service and paths. Private Pro installations must retain their
|
|
private runtime, not substitute that public installer. Use
|
|
[update failure checks](#update-failed) if the attempted update's result is
|
|
uncertain. Guidance is not confirmation that the helper or installation is
|
|
repaired.
|
|
|
|
### Source Build
|
|
|
|
`make build` writes a `pulse` binary in the source checkout. It does not install
|
|
that binary into the running service's executable path. Restarting the service
|
|
after a build can therefore restart the old installed binary; if the service
|
|
runs directly from the checkout, building there can instead overwrite its live
|
|
executable. Do not build in the active installation directory.
|
|
|
|
For a production update, prefer the exact signed release and the
|
|
[existing-installation update procedure](INSTALL.md#-updates).
|
|
Keep private Pro installations on their private runtime; a public source build
|
|
is not a replacement for it.
|
|
|
|
If you intentionally maintain a source-built deployment:
|
|
|
|
1. Select the intended source tag or commit explicitly in a separate build
|
|
checkout, preserving local changes. A moving `main` branch is development
|
|
source, not the latest published stable release.
|
|
2. Use that checkout's declared toolchain and locked dependencies. Build and
|
|
check the resulting binary's version before stopping the running service;
|
|
a successful build alone is not an installed update.
|
|
3. Install through your existing deployment procedure, preserving its service
|
|
identity, executable path, configuration, credentials and data. Stage the
|
|
replacement separately; do not copy onto a running executable or remove
|
|
the previous binary and recovery snapshots first. If the active executable
|
|
path or recovery procedure is unknown, stop before changing the service.
|
|
4. Restore only a service that was active before the update, then confirm the
|
|
running version, ordinary collection and notification delivery. Retain the
|
|
previous binary and state backup until recovery is verified; a restart or
|
|
version check alone does not establish healthy monitoring.
|
|
|
|
Do not pull, rebuild or restart just to reproduce an update failure. Follow
|
|
[update preparation and recovery limits](DEPLOYMENT_MODELS.md#updates-by-model) before another attempt.
|
|
|
|
## Rollback
|
|
|
|
An update error or a stuck progress modal does not prove that the old version
|
|
is still running. Check the running version and service health before retrying
|
|
or restoring anything; preserve the update error, logs and history. Do not run
|
|
another update just to reproduce a failure.
|
|
|
|
Before any rollback, take a consistent private backup of the current state and
|
|
check the proposed backup's scope. Keep the failed installation and update
|
|
snapshots until recovery is verified. Returning to an older binary is not a
|
|
full-state recovery. Restoring a matching data snapshot can discard settings,
|
|
alert changes and history written since that snapshot.
|
|
|
|
### Automatic Rollback
|
|
|
|
The in-app updater creates an installation snapshot before applying files. If
|
|
applying files fails, it attempts to restore that snapshot and logs any restore
|
|
error. This is not a guarantee that every update failure restores all state or
|
|
restarts successfully. Confirm the running version, connections and service
|
|
health afterwards; a progress message alone is not recovery evidence.
|
|
|
|
### Roll back from Update History
|
|
|
|
If your installed version offers it, open **Settings → System → Updates →
|
|
Update History**. **Roll back** is offered for a successful in-app update with
|
|
a retained backup. The confirmation names the version before that update and
|
|
Pulse restarts to use the restored binary. Check that version and the actual
|
|
backup contents before confirming.
|
|
|
|
**Update History is not a full-state recovery tool.** Its restore scope depends
|
|
on the installed updater. Older updaters may replace `data/`, `config/` and
|
|
`.env` under the installation directory, but omit active data stored elsewhere.
|
|
Do not assume later settings and alert changes will be reverted, even if the
|
|
confirmation says so. If active data shares those installation paths, do not
|
|
restore it while Pulse is running; use the stopped-service procedure in
|
|
[Manual Rollback](#manual-rollback).
|
|
|
|
Older versions may not have this control. An absent button or backup does not
|
|
justify deleting data or creating an empty configuration. Docker server installs
|
|
use their previous image and matching data backup, not this in-app rollback.
|
|
|
|
### What an update snapshot contains
|
|
|
|
In-app snapshots normally live at `backup-<timestamp>/` under the runtime data
|
|
directory (usually `/etc/pulse`), with `/tmp/pulse-backup-<timestamp>` as a
|
|
low-space fallback. Use the `backup_path` recorded for the actual update in
|
|
`update-history.jsonl`, rather than guessing a timestamp. The updater retains
|
|
the most recent three snapshots; a `/tmp` snapshot may also be lost on reboot.
|
|
|
|
Snapshot scope is version-specific. The published **v6.4.5** and
|
|
**v6.4.6-rc.1** in-app updaters use the limited installation snapshot described
|
|
below. Do not assume a backup made by another updater version has the same
|
|
contents or restore behaviour.
|
|
|
|
The limited snapshot copies the running server binary, available `VERSION` and
|
|
`.env` files, and available `data/` and `config/` directories under
|
|
`PULSE_INSTALL_DIR` (default `/opt/pulse`). It is not necessarily a complete
|
|
backup of the active `PULSE_DATA_DIR`, external metrics/audit stores, service
|
|
units, bundled agents or update helpers. Copy errors can leave a partial
|
|
snapshot: a recorded path is not proof that every file was saved.
|
|
|
|
A backup's existence, or the presence of a database file, does not establish
|
|
completeness, consistency or that Update History will restore it. A snapshot
|
|
that includes active data still needs a verified, stopped-service recovery
|
|
procedure; its presence is not permission to rewind live runtime stores.
|
|
|
|
Verify the backup against your effective service paths and update logs. Preserve
|
|
the active data directory, matching `.encryption.key`, audit history and its
|
|
signing key together, including custom paths and organisation directories. Use
|
|
a stopped, consistent filesystem/volume backup; copying a live `.db` file alone
|
|
can omit SQLite sidecar files. Keep these backups private, not in an issue or
|
|
diagnostic attachment. See [configuration paths](CONFIGURATION.md) and
|
|
[audit storage and safe recovery](AUDIT_LOGGING.md#storage).
|
|
|
|
### Manual Rollback
|
|
|
|
If Pulse cannot start, work inside the Pulse host or LXC, not on the Proxmox host
|
|
itself. Start with read-only service discovery:
|
|
|
|
```bash
|
|
systemctl is-active pulse
|
|
systemctl show pulse --property=FragmentPath --property=DropInPaths
|
|
```
|
|
|
|
An inactive service makes `is-active` return non-zero; that is useful evidence,
|
|
not a reason to reset it. Inspect the named unit and drop-ins locally for the
|
|
effective executable, `PULSE_INSTALL_DIR` and `PULSE_DATA_DIR`. Do not post full
|
|
service environments or `.env` contents; they may contain credentials.
|
|
|
|
1. Stop Pulse before taking the failed-state backup or replacing files. Preserve
|
|
the actual executable, distribution files, unit/drop-ins and every active
|
|
data path, not just a guessed `/opt/pulse/data` directory.
|
|
2. Match the retained backup to the intended pre-update version. Check its
|
|
files and the update log for missing/copy-failed entries. If the backup is
|
|
missing, partial or has the wrong scope, stop here; do not delete live
|
|
directories to make a restore fit.
|
|
3. Prefer restoring a verified pre-update filesystem/volume snapshot with your
|
|
host backup tooling. Check it in an isolated recovery instance first, with
|
|
no access to monitored systems or notification destinations. Do not start a
|
|
second connected copy with the same agent identities.
|
|
4. For a file-level repair, stage verified replacements and keep reversible
|
|
copies of the failed state. Restore only the confirmed paths, ownership and
|
|
permissions for this deployment. Do not merge unrelated snapshots, delete
|
|
data/configuration directories, or regenerate encryption or signing keys.
|
|
5. Start Pulse and verify the running version and edition, service health,
|
|
saved connections, agent identities and retained history. If any check fails,
|
|
preserve the error and backups rather than retrying the update blindly.
|
|
|
|
For Docker, change the configured image back to the recorded previous tag or
|
|
digest and recreate only Pulse with its existing volume. An older image may not
|
|
understand data migrated by the newer version; use a verified matching data
|
|
backup when required. Never remove the volume or initialise a fresh one as a
|
|
rollback shortcut. An image change alone is not a data rollback.
|
|
|
|
## Update History
|
|
|
|
History entries are stored in `update-history.jsonl` under the Pulse data directory (`/etc/pulse` or `/data`), and exposed via `GET /api/updates/history` (admin auth required).
|
|
|
|
Systemd/LXC update runs write detailed logs to `/var/log/pulse/update-<timestamp>.log`.
|
|
|
|
## Troubleshooting
|
|
|
|
### Update button not showing
|
|
1. Check if your deployment supports auto-update
|
|
2. Verify an update is actually available
|
|
3. Ensure you have the latest frontend loaded (hard refresh)
|
|
|
|
### Update failed
|
|
|
|
First identify what was updated: this guide covers the **Pulse server**.
|
|
An installed agent has its [own update path](UNIFIED_AGENT.md#auto-update).
|
|
For a monitored Docker workload, use the [failed or pending workload checks](DOCKER.md#check-a-failed-or-pending-workload-update)
|
|
on that workload's host, not inside Pulse.
|
|
|
|
Keep the original target version, attempt time, last displayed step and redacted
|
|
error from the progress modal or updater log. If Pulse still opens, check
|
|
**Settings → System → Updates** for its running version and retain the existing
|
|
**Update History** entry when available. Check the ordinary UI and monitoring
|
|
freshness too. A failed updater exit, disconnected progress stream or stuck
|
|
modal does not establish which version is running or whether rollback succeeded.
|
|
Do not rerun an update, restart or reinstall merely to obtain evidence.
|
|
|
|
For server logs, use the [bounded Pulse log readers](TROUBLESHOOTING.md#inspect-notification-logs)
|
|
for the actual deployment. Run them on the Pulse host, or inside the Pulse LXC,
|
|
not on a monitored guest. They have a deadline as well as time and record limits;
|
|
do not substitute a log-follow command or an unbounded reader if they fail.
|
|
Inspect the relevant part of the original `/var/log/pulse/update-<timestamp>.log`
|
|
privately when that systemd/LXC update produced one; a server journal alone may
|
|
not contain the installer failure. Missing logs are unavailable evidence, not
|
|
proof that no change occurred. Do not enable Debug or repeat the failing action.
|
|
|
|
If the error names disk space, check headroom on the actual staging, installation
|
|
and data filesystems before planning another attempt; the release payload and
|
|
rollback snapshot both need space. Do not delete configuration backups, keys or
|
|
history to clear the error. A download error needs its original HTTP, connectivity
|
|
or certificate evidence; do not disable TLS verification or switch a paid Pro
|
|
installation to the public Community runtime as a workaround.
|
|
|
|
Share only the relevant times, versions, failed step and redacted error. Keep
|
|
full logs, service environments, configuration, credentials and private backup
|
|
paths out of public reports.
|
|
|
|
### Pause further unattended attempts without stopping Pulse
|
|
|
|
If an automatic server update failed or its result is uncertain, you can pause
|
|
the existing update timer while keeping Pulse's monitoring service running.
|
|
This is containment, not rollback or a fix. It does not cancel an updater
|
|
already running, prevent a manual or in-app update, or recover a stopped LXC.
|
|
Do not stop the updater midway through replacement merely to collect evidence.
|
|
|
|
Work on the **Pulse server**, inside its LXC when applicable, not on the Proxmox
|
|
host or a monitored guest. First identify the timer from the existing
|
|
deployment. The default signed installation uses `pulse-update.timer`;
|
|
legacy installations may use `pulse-backend-update.timer`, and custom names
|
|
can differ. A name alone does not establish ownership. If the timer's identity
|
|
is unknown, stop here; do not try every matching unit or run the installer to
|
|
create one.
|
|
|
|
For the confirmed default timer, privately record its state before changing it:
|
|
|
|
```bash
|
|
timeout --signal=TERM --kill-after=1s 5s systemctl show pulse-update.timer \
|
|
--property=LoadState --property=ActiveState --property=UnitFileState \
|
|
--property=Triggers
|
|
```
|
|
|
|
Use the actual known timer name in both commands on a legacy or custom install.
|
|
This read prints only unit state and trigger names, not service environments.
|
|
`LoadState=not-found`, a failed read or a timeout is not an inactive timer:
|
|
stop rather than guessing. If `timeout` is unavailable, do not substitute an
|
|
unbounded reader. Keep a masked timer masked; an inactive or disabled timer
|
|
must not be enabled just to follow these instructions. Enabled state and
|
|
current active state are separate; preserve both for later recovery. If the
|
|
timer is runtime-enabled or managed by another scheduler, use that deployment's
|
|
pause procedure instead of assuming the default command applies.
|
|
|
|
To pause that confirmed timer, use your authorised administrative account:
|
|
|
|
```bash
|
|
sudo systemctl disable --now pulse-update.timer
|
|
```
|
|
|
|
This stops and disables **only the timer**, not `pulse.service`,
|
|
`pulse-backend.service` or `pulse-update.service`. Re-read its bounded state
|
|
above: it should be inactive and disabled, or remain masked. If the command
|
|
fails or its result is uncertain, retain the error and current state; do not
|
|
assume the schedule was paused or issue broader stop/reset commands. Keep
|
|
independent monitoring and notifications available if Pulse itself is down.
|
|
|
|
Retain the original update's starting and intended versions, last recorded
|
|
result, time and timezone, and any recovery already performed. Today's running
|
|
version is not proof of the version at failure. A verified signature is not a
|
|
completed install or rollback; `Broken pipe` does not explain a host stop, and
|
|
a later boot does not supply its time or cause. If the whole LXC or host stopped,
|
|
use only an already available, relevant Proxmox task or host event to distinguish
|
|
that from a Pulse-service failure; keep unknowns unknown. Do not repeat the
|
|
update, reboot, run Diagnostics or delete rollback backups to fill these gaps.
|
|
|
|
After the incident is understood and recovery is verified, restore the
|
|
separately recorded enabled and active states through the existing deployment:
|
|
enable only if previously enabled, and start only if previously active. Do not
|
|
unmask a unit, enable a previously disabled timer or create a second schedule.
|
|
A paused timer does not undo the saved
|
|
**Automatic Stable Updates** preference; restoring the schedule may allow the
|
|
next stable update. Keep configuration, keys, history and backups private and
|
|
preserved until recovery is verified.
|
|
|
|
### Service won't restart after update
|
|
|
|
Distinguish the **Pulse service** from the separate updater service: a failed
|
|
`pulse-update.service` is not proof that `pulse` is stopped. Use the read-only
|
|
service discovery in [Manual Rollback](#manual-rollback), substituting the actual
|
|
service name (`pulse-backend` on some older installs), and the bounded log readers
|
|
above. For Docker, use the [current container-state and image checks](DOCKER.md#check-a-failed-or-pending-workload-update)
|
|
with the Pulse server's container name. A running process or container alone is
|
|
not proof that the UI, saved connections and history are healthy.
|
|
|
|
If recovery is needed, follow [Manual Rollback](#manual-rollback): preserve the
|
|
failed state, verify the intended backup's version and complete scope, and use
|
|
the stopped-service recovery procedure. An absent or partial backup is a reason
|
|
to stop, not to overwrite live data, create an empty data directory or retry the
|
|
update. Do not restore a guessed snapshot just because the progress modal failed.
|