P6
Observability AWS

Pulse 6.5.0 on AWS User Guide

| Product: Pulse 6.5.0 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and verifying Pulse 6.5.0 on Ubuntu 24.04 from cloudimg on Amazon EC2. It is one version of the cloudimg Hardened Uptime Kuma, Gatus & Uptime and Status Pages AMIs listing on AWS Marketplace; you pick it as the software version when you subscribe and launch. The other products in the listing are described on the listing's guide hub.

Pulse is an open source monitoring server for home labs and infrastructure teams. You connect it to your Proxmox VE clusters, Proxmox Backup Server and Mail Gateway with an API token, or install the small Pulse agent on Docker, Podman, Kubernetes and plain Linux hosts, and it shows live CPU, memory, disk and network for every node, VM, container and storage pool in one dashboard, together with backup status, alert rules and notifications by email, webhook or Apprise. TrueNAS SCALE and VMware vCenter (preview) are supported too.

The image runs Pulse 6.5.0 compiled by cloudimg from the official 6.5.0 source with Go 1.27.3 and updated golang.org/x/net and golang.org/x/crypto modules. The web interface is built from the same source with updated libraries. The upstream 6.5.0 release binary was built with Go 1.26.8 and golang.org/x/net 0.58.0, against which govulncheck lists 14 known advisories; this build has none that govulncheck finds reachable. The build is reproducible, and its record ships with the image. The base is a fully patched Ubuntu 24.04 LTS, and unattended security upgrades stay on for your instance.

What is on the image:

  • Pulse 6.5.0 (pulse.service) running as the unprivileged pulse user, listening on 127.0.0.1:7655 only
  • nginx publishing Pulse over HTTPS on port 443 with a certificate created on your instance's first boot; port 80 redirects to HTTPS
  • A local admin account with a password unique to your instance, created on first boot
  • An empty data directory /etc/pulse: no monitored systems, no tokens and no history ship. Pulse creates its own encryption key there on its first start on your instance.
  • pulse-set-hostname, a helper to serve Pulse under your own DNS name
  • The build record (BUILD-INFO.txt), go.mod, go.sum, the web interface's package lock, the govulncheck and npm audit results and the MIT licence in /usr/share/doc/pulse/

Default user: ubuntu · Architecture: x86_64 · Root volume: 8 GiB gp3

Security posture

  • No open dashboard. A fresh Pulse install with no account accepts anonymous requests from the machine itself and offers a setup wizard. This image never runs Pulse without an account: a check before every start refuses to launch it until first boot has created the admin account. The first-run setup wizard is closed, so nobody else can claim your instance.
  • Per-instance password. The admin password is generated on each instance's first boot. Pulse's configuration (/etc/pulse/.env, readable only by the pulse account) holds only its bcrypt hash; the plain text is written to /root/pulse-credentials.txt (mode 0600, root only). No password or hash ships in the image.
  • Per-instance encryption key. Pulse encrypts the Proxmox, Backup Server, TrueNAS and vSphere credentials you add with an AES-256 key in /etc/pulse/.encryption.key. The image ships no key; Pulse creates it on its first start on your instance, so no two instances share one.
  • Loopback only. Pulse listens on 127.0.0.1 only. nginx on 443 is the only way in.
  • HTTPS on first boot. nginx serves Pulse with a TLS key and self-signed certificate created on your instance (TLS 1.2 and 1.3 only). Port 80 only redirects to HTTPS. Pulse adds its own content security policy, HSTS and frame-blocking headers.
  • Fixed host name. Pulse is served under a name taken from the instance metadata at first boot (or one you set), never from the request. Requests for any other host name are dropped, and cross-site form posts and WebSocket connections are refused, both by nginx and by Pulse's own origin check.
  • Real client addresses. nginx passes the connecting address to Pulse and ignores any X-Forwarded-For header a client sends, so Pulse's login lockout (5 failed attempts) and its logs see who really connected.
  • Local recovery stays local. Pulse's account-recovery endpoint is refused through nginx; it works only from a shell on the instance.
  • No telemetry, no update checks. Pulse's outbound usage telemetry (on by default upstream) is turned off, the hourly update check against GitHub is off, and network discovery does not scan your VPC unless you turn it on.
  • No metadata access. Pulse connects to whatever Proxmox, webhook and AI provider addresses you enter, so pulse.service and nginx.service are blocked from reaching the instance metadata service (169.254.169.254 and fd00:ec2::254). Amazon Time Sync keeps working.
  • Least privilege. pulse.service runs with no Linux capabilities, a read-only system (ProtectSystem=strict) except /etc/pulse, and its own private /tmp. Pulse's ping checks use unprivileged ICMP sockets that the image allows for the pulse group only.
  • IMDSv2 required. The AMI is registered with ImdsSupport v2.0, so instances launched from it refuse token-less (IMDSv1) metadata requests.
  • Per-instance identity. SSH host keys and the machine ID are generated fresh on every instance.

Known advisory in a bundled library

govulncheck reports no vulnerability reachable from Pulse. It lists one advisory at module level only, GO-2026-5932: the golang.org/x/crypto/openpgp package is deprecated and described by the Go team as unsafe by design, and it has no fixed version. That package is not compiled into Pulse at all; it is only part of the golang.org/x/crypto module that Pulse uses for bcrypt and SSH. The build fails if the package is ever linked. The binary also contains one private-key block that is not a secret: the public test key that the crewjam/saml library (used for SAML sign-in) ships for its fuzz tests. It is the same in every build of that library, including upstream's release binaries, and Pulse never uses it. The full output ships in /usr/share/doc/pulse/govulncheck-binary.txt and govulncheck-source.txt, and the web interface's npm audit --omit=dev result (0 vulnerabilities) in npm-audit-production.txt.

Community edition

This is the MIT-licensed community Pulse server. Pulse also has paid Relay, Pro and Cloud plans sold by its developer; this build cannot activate them (it carries no licence verification key), and none of their features are part of this image. Everything in the community edition works: monitoring, alerts and notifications, the API, the agents and Patrol with your own AI provider.

Prerequisites

  1. An AWS account and permission to launch EC2 instances
  2. An EC2 key pair in the Region you launch in
  3. A subnet that gives the instance a public IPv4 address (or private connectivity from where you will use the dashboard), and network access from the instance to the Proxmox, Backup Server or agent hosts you want to monitor (for example a VPN or AWS Direct Connect link to your data centre)

Recommended instance type: m5.large. Pulse is a single Go process with SQLite storage; a smaller burstable type also works for a few nodes.

Connecting to your instance

Version Operating system SSH user
Pulse 6.5.0 on Ubuntu 24.04 Ubuntu 24.04 LTS ubuntu

Step 1: Launch the instance

Option A: AWS Marketplace console

  1. Open the cloudimg Hardened Uptime Kuma, Gatus & Uptime and Status Pages AMIs listing on AWS Marketplace and choose View purchase options, then Subscribe. One subscription covers every version in the listing.
  2. Once the subscription is active, choose Launch your software.
  3. Choose One-click launch from AWS Marketplace (or Launch from EC2 Console for the full launch wizard). In Version, choose Pulse 6.5.0 on Ubuntu 24.04, then choose your Region.
  4. Pick an instance type (m5.large recommended; the software charge is $0.04 per vCPU per hour) and your key pair.
  5. Security group: the listing's default group allows SSH (22), HTTP (80) and HTTPS (443). Restrict SSH to your own IP address, and 80/443 to the people who need the dashboard.
  6. Choose your VPC and a subnet that gives the instance a public IP, leave the metadata defaults (the image already requires IMDSv2), then choose Launch.

Option B: AWS CLI

Run this on your own workstation. It creates a security group that allows SSH and the dashboard from your management address only, then launches the instance. Replace the AMI ID with the one shown for your Region on the Marketplace launch page, and the VPC, subnet, key pair and CIDR with your own:

SG=$(aws ec2 create-security-group --group-name pulse \
  --description "Pulse" --vpc-id vpc-0123456789abcdef0 \
  --query GroupId --output text)
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 22 --cidr <your-mgmt-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 443 --cidr <your-mgmt-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 80 --cidr <your-mgmt-cidr>
aws ec2 run-instances \
  --image-id ami-0123456789abcdef0 \
  --instance-type m5.large \
  --key-name my-key-pair \
  --security-group-ids "$SG" \
  --subnet-id subnet-0123456789abcdef0 \
  --associate-public-ip-address \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=pulse}]'

You do not need --metadata-options: the AMI already makes IMDSv2 required.

Step 2: Connect and read your login

Connect as ubuntu with the key pair you chose:

ssh -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip>

First boot finishes within a minute of launch. It creates the HTTPS certificate and the admin password, then starts Pulse and nginx. Your login is in a root-only file:

sudo cat /root/pulse-credentials.txt
# Pulse - generated on first boot by pulse-firstboot.service
# These credentials are unique to this instance. Store them somewhere safe.

PULSE_URL=https://ec2-100-53-99-69.compute-1.amazonaws.com/
PULSE_USERNAME=admin
PULSE_PASSWORD=<PULSE_PASSWORD>
#
# Open PULSE_URL in a browser (self-signed certificate minted on this instance's first boot; port 80 redirects to
# https) and sign in with the username and password above. Then add your Proxmox VE / Backup Server nodes (API
# token), or install the Pulse agent on your Docker, Kubernetes or Linux hosts, from Settings.
# Change the name it is served as:  sudo pulse-set-hostname <your-dns-name>
# Restrict 80/443 in the security group to the people who need the dashboard.
# Full deployment guide: https://www.cloudimg.co.uk/guides/pulse-6-5-0-on-ubuntu-24-04-aws/

PULSE_PASSWORD holds your instance's own password.

Step 3: Confirm the services are running

First boot, Pulse and nginx are active, Pulse runs as the unprivileged pulse user, and its health endpoint reports healthy:

systemctl is-active pulse-firstboot.service pulse.service nginx.service
ps -o user= -C pulse
curl -sk https://localhost/api/health | jq -e '.status == "healthy"'
active
active
active
pulse
true

/api/health needs no login, so you can use it for a load balancer health check over HTTPS. Everything else needs a signed-in session.

These are the only ports the instance listens on:

sudo ss -Hltnu | awk '{print $1, $5}' | sort -u
tcp 0.0.0.0:22
tcp 0.0.0.0:443
tcp 0.0.0.0:80
tcp 127.0.0.1:7655
tcp 127.0.0.1:9091
tcp 127.0.0.53%lo:53
tcp 127.0.0.54:53
tcp [::]:22
tcp [::]:443
tcp [::]:80
udp 127.0.0.1:323
udp 127.0.0.53%lo:53
udp 127.0.0.54:53
udp 172.31.94.54%ens5:68
udp [::1]:323

Pulse (7655) and its Prometheus metrics endpoint (9091) listen on loopback only; nginx publishes Pulse on 443. The loopback port 53 entries are Ubuntu's local stub resolver (systemd-resolved), 323 is chrony's local control socket and 68 is the DHCP client.

The binary is the reproducible cloudimg build of the 6.5.0 source, and it is the only program in /opt/pulse/bin (no agent binaries ship). Its record ships with the image:

sha256sum /opt/pulse/bin/pulse
grep -E '^(source|binary|govulncheck) ' /usr/share/doc/pulse/BUILD-INFO.txt
ls /opt/pulse/bin
c8255cc44aa5f26536fd9e829cd724678055dee0675bb253701d9f1e6ac2bbfb  /opt/pulse/bin/pulse
source            https://github.com/rcourtman/Pulse/archive/refs/tags/v6.5.0.tar.gz
source sha256     e5473d7d447825946154101220ad6e74f55eec0abb52dfe52cacfbe6fd500c58 (tag commit 38c981a397c7a37f469b619200b5035bfc60b328)
binary sha256     c8255cc44aa5f26536fd9e829cd724678055dee0675bb253701d9f1e6ac2bbfb (reproducible)
govulncheck       v1.9.0 -mode=binary and source mode: 0 reachable vulnerabilities (DB updated: 2026-10-21 00:27:29 +0000 UTC)
pulse

Step 4: Sign in to Pulse

Browse to the PULSE_URL from Step 2, for example https://ec2-100-53-99-69.compute-1.amazonaws.com/. The certificate is self-signed, so your browser warns once; accept it, or install your own certificate (Step 7). Pulse shows its sign-in page:

The Pulse sign-in page asking for a username and password

Sign in as admin with the password from Step 2. On a new instance Pulse opens Settings → Infrastructure, where you add the systems to monitor (Step 5):

Pulse Settings, Infrastructure page with no systems connected yet and the Add infrastructure button

Port 80 only redirects to the HTTPS address:

curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' http://localhost/
301 https://ec2-100-53-99-69.compute-1.amazonaws.com/

You can check the login from the command line too. These requests go to nginx on the instance itself: the monitoring state needs a session, a wrong password is refused, and the instance's own password (read from the credentials file and passed to curl on standard input, never on the command line) signs in and reads the state. The block stops with an error if any answer is not the expected one:

H=$(sudo sed -n 's/^set $pulse_host "\(.*\)";$/\1/p' /etc/nginx/pulse-host.conf)
PW() { sudo sed -n 's/^PULSE_PASSWORD=//p' /root/pulse-credentials.txt; }
J=$(mktemp); trap 'rm -f "$J"' EXIT
U=$(curl -sk --resolve "$H:443:127.0.0.1" -o /dev/null -w '%{http_code}' "https://$H/api/state")
W=$(printf '{"username":"admin","password":"not-the-password"}' | curl -sk --resolve "$H:443:127.0.0.1" -o /dev/null -w '%{http_code}' \
    -H 'Content-Type: application/json' -H "Origin: https://$H" --data-binary @- "https://$H/api/login")
A=$(printf '{"username":"admin","password":"%s"}' "$(PW)" | curl -sk --resolve "$H:443:127.0.0.1" -c "$J" -o /dev/null -w '%{http_code}' \
    -H 'Content-Type: application/json' -H "Origin: https://$H" --data-binary @- "https://$H/api/login")
S=$(curl -sk --resolve "$H:443:127.0.0.1" -b "$J" -o /dev/null -w '%{http_code}' "https://$H/api/state")
echo "no session      : $U"; echo "wrong password  : $W"; echo "admin login     : $A"; echo "with session    : $S"
[ "$U" = 401 ] && [ "$W" = 401 ] && [ "$A" = 200 ] && [ "$S" = 200 ]
no session      : 401
wrong password  : 401
admin login     : 200
with session    : 200

Pulse locks an account, and the address it is used from, for 15 minutes after 5 failed sign-ins, so mistype the password sparingly.

The first-run setup is closed: an anonymous request to set up an account is refused, no setup token exists, and the account-recovery endpoint is refused through nginx. Pulse itself reports that authentication is required:

H=$(sudo sed -n 's/^set $pulse_host "\(.*\)";$/\1/p' /etc/nginx/pulse-host.conf)
QS=$(curl -sk --resolve "$H:443:127.0.0.1" -o /dev/null -w '%{http_code}' -X POST -H 'Content-Type: application/json' -H "Origin: https://$H" \
    --data '{"username":"someone","password":"Someone-Else-123"}' "https://$H/api/security/quick-setup")
BT=$(curl -sk --resolve "$H:443:127.0.0.1" -o /dev/null -w '%{http_code}' -X POST -H "Origin: https://$H" "https://$H/api/security/validate-bootstrap-token")
RC=$(curl -sk --resolve "$H:443:127.0.0.1" -o /dev/null -w '%{http_code}' -X POST -H "Origin: https://$H" --data '{"action":"disable_auth"}' "https://$H/api/security/recovery")
curl -sk --resolve "$H:443:127.0.0.1" "https://$H/api/security/status" | jq -c '{hasAuthentication, requiresAuth}'
echo "anonymous setup    : $QS"; echo "bootstrap token    : $BT"; echo "remote recovery    : $RC"
[ "$QS" = 401 ] && [ "$BT" = 409 ] && [ "$RC" = 403 ]
{"hasAuthentication":true,"requiresAuth":true}
anonymous setup    : 401
bootstrap token    : 409
remote recovery    : 403

Step 5: Add your infrastructure

In Settings → Infrastructure, choose Add infrastructure. You can paste a hostname or URL and let Pulse detect the platform, install the Pulse agent on a host, or pick a source type: Proxmox VE, TrueNAS SCALE, Unraid, and, under Show 5 more sources, further types such as Proxmox Backup Server, Proxmox Mail Gateway and VMware vCenter (preview):

The Pulse Add infrastructure dialog offering Detect API platform, Install Pulse Agent and the Proxmox VE, TrueNAS SCALE and Unraid sources

Pulse connects out from this instance, so it needs a network path to each system (a VPN, AWS Direct Connect, or systems that run in AWS).

Proxmox VE, Backup Server and Mail Gateway are monitored through their API. In the Proxmox VE form, enter a node name and the endpoint URL (for example https://<your-proxmox-host>:8006) and keep API Token (Recommended):

The Pulse Add Proxmox VE form with the node name, endpoint URL, API token authentication and the Connect via API, Host Telemetry Agent and Manual Token Setup options

  • Connect via API shows one command to run on the Proxmox VE server. It creates the monitoring user pulse-monitor@pve with an API token and read-only permissions (PVEAuditor, guest agent access and backup visibility) and registers the node with Pulse. The Proxmox server must be able to reach this instance on port 443 for that.
  • Manual Token Setup is the alternative when it cannot: create the user and token yourself on the Proxmox node, then paste the token ID and secret into the form:
pveum user add pulse-monitor@pve
pveum aclmod / -user pulse-monitor@pve -role PVEAuditor
pveum user token add pulse-monitor@pve pulse --privsep 0

Under SSL settings, turn off Verify SSL certificate or enter the node's certificate fingerprint if your Proxmox node uses its default self-signed certificate. Pulse stores the token secret encrypted with your instance's own key.

Docker, Podman, Kubernetes and Linux, macOS, Windows or Unraid hosts are monitored by the Pulse agent: choose Install Pulse Agent and run the installer command Pulse shows on that host. The installer comes from this instance, and the agent binary is the official signed 6.5.0 release, which Pulse fetches from GitHub for you. Agents connect to Pulse on port 443 at the PULSE_PUBLIC_URL (Step 7), so allow 443 from those hosts in the security group, and install your own certificate (Step 7) before you install agents so they can trust it.

Alerts and notifications: alert thresholds are under Alerts; email, webhook and Apprise destinations are in the alert settings. Webhooks to private addresses are blocked unless you allow them.

Step 6: Read the monitoring state from the API

Everything in the dashboard comes from Pulse's REST API. With a session (or an API token from Settings → API Access) you can read it from scripts. On a new instance no systems are configured, so the node list is empty and there are no alerts:

H=$(sudo sed -n 's/^set $pulse_host "\(.*\)";$/\1/p' /etc/nginx/pulse-host.conf)
PW() { sudo sed -n 's/^PULSE_PASSWORD=//p' /root/pulse-credentials.txt; }
J=$(mktemp); trap 'rm -f "$J"' EXIT
printf '{"username":"admin","password":"%s"}' "$(PW)" | curl -sk --resolve "$H:443:127.0.0.1" -c "$J" -o /dev/null \
    -H 'Content-Type: application/json' -H "Origin: https://$H" --data-binary @- "https://$H/api/login"
curl -sk --resolve "$H:443:127.0.0.1" -b "$J" "https://$H/api/config/nodes" | jq -c '{configured_nodes: length}'
curl -sk --resolve "$H:443:127.0.0.1" -b "$J" "https://$H/api/state" | jq -e -c '{active_alerts: (.activeAlerts | length)}'
curl -sk --resolve "$H:443:127.0.0.1" -b "$J" "https://$H/api/version" | jq -e -c '{version}'
{"configured_nodes":0}
{"active_alerts":0}
{"version":"6.5.0"}

Step 7: HTTPS certificate and host name

The certificate was created on your instance's first boot for the instance's public DNS name, public IP, private IP and localhost. The key, Pulse's configuration and encryption key, and the credentials file are readable only by their owners, and the configuration holds the password only as a bcrypt hash:

sudo openssl x509 -in /etc/ssl/pulse/pulse.crt -noout -subject -dates -ext subjectAltName
sudo stat -c '%a %U:%G %n' /etc/ssl/pulse/pulse.key /etc/ssl/pulse/pulse.crt /etc/pulse/.env /etc/pulse/.encryption.key /root/pulse-credentials.txt
sudo sed -E -n "s/^(PULSE_AUTH_USER=.*)/\1/p; s/^(PULSE_AUTH_PASS=')(.{7}).*/\1\2.../p" /etc/pulse/.env
cat /etc/cloudimg/pulse-host.env
subject=CN = ec2-100-53-99-69.compute-1.amazonaws.com, O = cloudimg
notBefore=Oct 21 14:45:59 2026 GMT
notAfter=Jan 23 14:45:59 2029 GMT
X509v3 Subject Alternative Name: 
    DNS:ec2-100-53-99-69.compute-1.amazonaws.com, IP Address:100.53.99.69, IP Address:172.31.94.54, IP Address:127.0.0.1, DNS:localhost
600 root:root /etc/ssl/pulse/pulse.key
644 root:root /etc/ssl/pulse/pulse.crt
600 pulse:pulse /etc/pulse/.env
600 pulse:pulse /etc/pulse/.encryption.key
600 root:root /root/pulse-credentials.txt
PULSE_AUTH_USER='admin'
PULSE_AUTH_PASS='$2y$12$...
PULSE_PUBLIC_URL=https://ec2-100-53-99-69.compute-1.amazonaws.com/
ALLOWED_ORIGINS=https://ec2-100-53-99-69.compute-1.amazonaws.com,https://100.53.99.69,https://172.31.94.54,https://127.0.0.1,https://localhost

PULSE_PUBLIC_URL is the address Pulse puts in agent install commands and notification links. To serve Pulse under your own DNS name (for example pulse.example.com, pointed at this instance), run the helper. It records the name, creates a new self-signed certificate for it, updates nginx and Pulse's public URL, restarts Pulse and rewrites the URL in the credentials file:

sudo pulse-set-hostname pulse.example.com

If the instance's public address changes after a stop and start, run the helper again so the certificate names the new address too. To use a certificate from your own certificate authority, replace /etc/ssl/pulse/pulse.key (keep it 0600 root) and /etc/ssl/pulse/pulse.crt, then run sudo systemctl reload nginx.

Step 8: Telemetry, updates and metadata

Pulse's environment turns off outbound telemetry and network discovery, binds Pulse to loopback and trusts forwarded headers from the local nginx only; the marker file turns off the update check. Pulse's log confirms it, including that no paid-plan licence can be activated on this build:

systemctl show -p Environment pulse.service | tr ' ' '\n' | grep -E '^(BIND_ADDRESS|PULSE_TELEMETRY|PULSE_TRUSTED_PROXY_CIDRS|DISCOVERY_ENABLED)='
sudo journalctl -u pulse.service -o cat --no-pager | grep -oE '"message":"(Outbound usage telemetry is disabled|discovery service disabled by configuration|no license public key configured)' | sort -u
head -1 /opt/pulse/BUILD_FROM_SOURCE
BIND_ADDRESS=127.0.0.1
PULSE_TRUSTED_PROXY_CIDRS=127.0.0.1/32
PULSE_TELEMETRY=false
DISCOVERY_ENABLED=false
"message":"Outbound usage telemetry is disabled
"message":"discovery service disabled by configuration
"message":"no license public key configured
cloudimg source build of Pulse v6.5.0 (see /usr/share/doc/pulse/BUILD-INFO.txt).

pulse.service and nginx.service carry a systemd IPAddressDeny rule for the instance metadata addresses, so no Proxmox address, webhook or AI provider URL entered in Pulse can reach the metadata service. Each entry is a single address, so the Amazon Time Sync Service at 169.254.169.123 keeps working, as chrony shows. Pulse also runs with no capabilities:

systemctl show -p IPAddressDeny pulse.service nginx.service
chronyc -n sources | grep 169.254
grep CapEff /proc/$(systemctl show -p MainPID --value pulse.service)/status
IPAddressDeny=168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128

IPAddressDeny=168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128
^* 169.254.169.123               3   4   377     3    -10us[-9823ns] +/-  558us
CapEff: 0000000000000000

Maintenance

  • Password: change the admin password in Settings → Authentication (Pulse stores the new bcrypt hash in /etc/pulse/.env), then update /root/pulse-credentials.txt or delete it. Single sign-on (OIDC) is available in Settings → Single Sign-On.
  • Locked out: if you lose the password, Pulse's recovery endpoint works from a shell on the instance only: see curl -s http://127.0.0.1:7655/api/security/recovery and the Pulse recovery documentation.
  • Backups: everything Pulse knows lives in /etc/pulse, including the encryption key that protects your stored credentials. Back up the whole directory with Pulse stopped (sudo systemctl stop pulse), and keep the backup as safe as the credentials themselves: without the key, the stored node credentials cannot be decrypted.
  • Upgrades: this build does not update itself. To move to a newer Pulse release, launch the newer version from the listing when it is published and restore your /etc/pulse backup.
  • Telemetry: to send Pulse's anonymous usage data to its developer, set PULSE_TELEMETRY=true with sudo systemctl edit pulse and restart it; the image keeps it off.
  • Security patches: unattended-upgrades remains enabled so the OS keeps receiving security updates.

Security recommendations

  • Keep the security group tight. Open 22 only to your management address, and 80/443 only to the people and agent hosts that need the dashboard.
  • Use read-only tokens. Give Pulse a Proxmox token with PVEAuditor unless you want it to act on your systems.
  • Use your own certificate if other people sign in, or before you install agents, so browsers and agents trust it without exceptions.
  • Keep Pulse on loopback. Leave BIND_ADDRESS=127.0.0.1 and reach Pulse through nginx; nginx is what keeps forwarded headers honest and the recovery endpoint local.

Support and licensing

Pulse is developed by Richard Courtman (Pulse Monitoring Ltd) and contributors and distributed under the MIT License. This image ships a binary that cloudimg compiled from the unmodified 6.5.0 source with Go 1.27.3, updated Go modules and updated web interface libraries; the build record and licence are in /usr/share/doc/pulse/. cloudimg provides the packaging, the hardening, first-boot HTTPS and per-instance credentials, and 24/7 support. Pulse's paid plans are sold separately by its developer and are not part of this image.

cloudimg is not affiliated with or endorsed by the Pulse project or Pulse Monitoring Ltd. Product names are marks of their owners and are used here only to identify the software.

For help with deployment or configuration, email support@cloudimg.co.uk or visit cloudimg support.