Observability Azure

Perses on Ubuntu 24.04 on Azure User Guide

| Product: Perses on Ubuntu 24.04 LTS on Azure

Overview

Perses is an open source dashboard and observability visualization platform and a Cloud Native Computing Foundation project. Like Grafana, it renders rich dashboards over your observability data, currently supporting Prometheus metrics, Tempo traces, Loki logs and Pyroscope profiles. What sets Perses apart is its dashboards as code approach: dashboards follow an open, standardized specification and can be authored, validated and version controlled as code with its native CLI and SDKs, making it a natural fit for GitOps workflows. It ships as a single self contained Go server with the React user interface embedded and a file backend for projects and dashboards, so it stays lightweight and starts instantly.

The cloudimg image installs Perses 0.53.1 and puts it behind an nginx reverse proxy that binds the server to loopback. The appliance is secure by default: because a dashboard platform should not be left open, Perses is reachable only through nginx on port 80 behind an HTTP Basic Auth gate whose password is generated uniquely and at random on the first boot of every VM, so no shared or default credential ever ships in the image. A per instance at rest encryption key is generated the same way. A demo project and a sample dashboard are seeded so the interface is populated on first boot, and you can immediately replace them with your own datasources and dashboards.

What is included:

  • Perses 0.53.1 single Go server with the React UI embedded (/opt/perses/perses)
  • percli command line client for dashboards as code (/opt/perses/percli)
  • File backend for projects and dashboards at /opt/perses/data (no external database to maintain)
  • perses.service running as perses, bound to loopback 127.0.0.1:8080
  • nginx.service reverse proxy on TCP 80 with a per VM HTTP Basic Auth gate, TLS ready
  • perses-firstboot.service generating the per VM password and encryption key on first boot
  • A seeded demo project and a welcome dashboard so the UI is populated on first boot
  • An unauthenticated /healthz endpoint for load balancer probes
  • Ubuntu 24.04 LTS base, latest patches, unattended security upgrades enabled
  • 24/7 cloudimg support, 24h response SLA

Prerequisites

An active Azure subscription, an SSH key, and a VNet with a subnet. Recommended VM size: Standard_B2s (Perses is light; 4 GB RAM is plenty).

Step 1: Deploy from the Azure Portal

Search the Azure Marketplace for Perses, choose the plan, and create the VM. In the networking step attach an NSG that allows inbound TCP 22 (SSH) and TCP 80 (the UI, behind Basic Auth) from your client networks only. For production, put a TLS reverse proxy in front of port 80 (Step 16).

Step 2: Deploy from the Azure CLI

RG="perses-prod"; LOCATION="eastus"; VM_NAME="perses-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/perses-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name ps-vnet --address-prefix 10.108.0.0/16 --subnet-name ps-subnet --subnet-prefix 10.108.1.0/24
az network nsg create -g "$RG" --name ps-nsg
az network nsg rule create -g "$RG" --nsg-name ps-nsg --name allow-ssh --priority 100 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp
az network nsg rule create -g "$RG" --nsg-name ps-nsg --name allow-web --priority 110 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 80 --access Allow --protocol Tcp
az vm create -g "$RG" --name "$VM_NAME" --image "$GALLERY_IMAGE_ID" \
  --size Standard_B2s --storage-sku StandardSSD_LRS \
  --admin-username azureuser --ssh-key-values "$SSH_KEY" \
  --vnet-name ps-vnet --subnet ps-subnet --nsg ps-nsg --public-ip-sku Standard

Step 3: Connect via SSH

ssh azureuser@<vm-ip>

perses.service, nginx.service and perses-firstboot.service all start automatically on first boot.

Step 4: Verify the Service

sudo systemctl is-active perses nginx perses-firstboot
sudo test -f /var/lib/cloudimg/perses-firstboot.done && echo FIRSTBOOT_DONE
sudo ss -tlnp | grep -E ':80 |8080'

Expected output — all three services are active, nginx is bound to the public port 80 and Perses is bound to loopback 127.0.0.1:8080 only:

active
active
active
FIRSTBOOT_DONE
LISTEN 0 4096 127.0.0.1:8080 0.0.0.0:*  users:(("perses",...))
LISTEN 0 511  0.0.0.0:80     0.0.0.0:*  users:(("nginx",...))

Perses, nginx and the firstboot service all active, with nginx bound to public port 80 and Perses bound to loopback 127.0.0.1:8080 only

Step 5: Retrieve Your Per-VM Password

The web UI is protected by an HTTP Basic Auth password that is generated uniquely on this VM's first boot. Read it, along with the URL and username, from the root only credentials file:

sudo cat /root/perses-credentials.txt

The file holds the username (admin), this VM's URL and the per VM password. No credential is baked into the image — every VM gets its own — and Perses itself is bound to loopback so the only way in is through the nginx password gate:

PERSES_URL=http://<vm-ip>/
PERSES_USERNAME=admin
PERSES_PASSWORD=<PERSES_PASSWORD>

An unauthenticated request is rejected, and Perses listens only on loopback:

The per VM credentials note with the password, an unauthenticated API request returning 401, and Perses bound to loopback 127.0.0.1:8080 only

Step 6: Open the Perses UI

Open http://<vm-ip>/ in a browser and sign in as admin with the password from Step 5. The home page lists your projects and recently viewed dashboards, and the demo project seeded by the image is already there:

The Perses home page showing the Welcome banner, the seeded demo project and the recently viewed dashboards panel

Step 7: Explore the Demo Project

Click the demo project. A project groups dashboards, variables, datasources and secrets. The seeded Welcome dashboard is listed and ready to open:

The demo project page with the Dashboards, Variables, Datasources and Secrets tabs and the seeded Welcome dashboard listed

Step 8: Open the Welcome Dashboard

Open the Welcome dashboard. It renders the sample Markdown panels seeded by the image, so the interface is populated the moment the VM boots. This is the dashboard view you will use for your own metrics, traces, logs and profiles:

The Welcome dashboard rendering the seeded Markdown panels that introduce Perses and its next steps

Step 9: Edit Dashboards in the Browser

Click Edit to open the dashboard in edit mode. From here you add panels and panel groups, wire them to variables and datasources, and save — the same dashboard model you can also manage as code with percli (Step 12):

The Welcome dashboard in edit mode showing the Add Panel and Add Panel Group toolbar and the per panel edit controls

Step 10: Use the REST API

Everything in the UI is also available through the JSON REST API, behind the same per VM password. List your projects and a project's dashboards:

curl -s -u admin:<PERSES_PASSWORD> http://127.0.0.1/api/v1/projects | jq '[.[].metadata.name]'
curl -s -u admin:<PERSES_PASSWORD> http://127.0.0.1/api/v1/projects/demo/dashboards | jq '[.[].metadata.name]'

The seeded demo project and its welcome dashboard are returned:

[
  "demo"
]
[
  "welcome"
]

The REST API returning the seeded demo project and its welcome dashboard, authenticated with the per VM password

Step 11: Create a Project and Dashboard via the API

You can create resources entirely through the API. This example creates a myteam project and a first dashboard with a Markdown panel, then reads it back:

PW='<PERSES_PASSWORD>'
curl -s -u admin:$PW -H 'Content-Type: application/json' -X POST http://127.0.0.1/api/v1/projects \
  -d '{"kind":"Project","metadata":{"name":"myteam"}}' -o /dev/null -w 'create project: %{http_code}\n'
curl -s -u admin:$PW -H 'Content-Type: application/json' -X POST http://127.0.0.1/api/v1/projects/myteam/dashboards \
  -d '{"kind":"Dashboard","metadata":{"name":"first","project":"myteam"},"spec":{"duration":"1h","panels":{"n":{"kind":"Panel","spec":{"display":{"name":"Notes"},"plugin":{"kind":"Markdown","spec":{"text":"# My first dashboard"}}}}},"layouts":[{"kind":"Grid","spec":{"items":[{"x":0,"y":0,"width":24,"height":6,"content":{"$ref":"#/spec/panels/n"}}]}}]}}' \
  -o /dev/null -w 'create dashboard: %{http_code}\n'
curl -s -u admin:$PW http://127.0.0.1/api/v1/projects/myteam/dashboards/first | jq '.metadata.name'

Both create calls return 200 and the dashboard reads back as "first".

Step 12: Dashboards as Code with percli

Perses ships percli, its command line client, so you can manage dashboards as code and wire them into CI. Point it at your instance (through the password gate) and apply resources from files:

/opt/perses/percli login http://admin:<PERSES_PASSWORD>@127.0.0.1
/opt/perses/percli apply -f my-dashboard.json
/opt/perses/percli get dashboards --project demo

Because a Perses dashboard is a plain declarative document, you keep it in Git, validate it in CI and apply it on merge — the core of the dashboards as code workflow.

Step 13: Add a Datasource

To visualize live data, add a datasource to a project (for example a Prometheus endpoint) from the project's Datasources tab in the UI, or as a resource file. A project scoped Prometheus datasource looks like this:

kind: Datasource
metadata:
  name: prometheus
  project: demo
spec:
  default: true
  plugin:
    kind: PrometheusDatasource
    spec:
      directUrl: http://your-prometheus:9090

Once a datasource exists, add a TimeSeriesChart, StatChart or GaugeChart panel to a dashboard and query it — the panel plugins for metrics, traces, logs and profiles all ship in the image.

Step 14: Server Components

Component Path
Perses server binary /opt/perses/perses
percli client /opt/perses/percli
Config file /etc/perses/config.yaml
File database (projects/dashboards) /opt/perses/data
Bundled plugin archives /opt/perses/plugins-archive
Systemd unit /etc/systemd/system/perses.service
Firstboot script /usr/local/sbin/perses-firstboot.sh
Per VM credentials note /root/perses-credentials.txt (mode 0600)
nginx Basic Auth file /etc/nginx/.perses.htpasswd (per VM bcrypt)
ls -1 /opt/perses/perses /opt/perses/percli /etc/perses/config.yaml /opt/perses/data
curl -sI http://127.0.0.1/healthz | head -1

The installed Perses component paths, the count of bundled panel and query plugins loaded, and the health probe returning 200

Step 15: Managing the Service

sudo systemctl restart perses.service
sudo journalctl -u perses.service --no-pager -n 15

Perses is a single binary with a local file database, so it restarts in a second or two. The service is hardened with NoNewPrivileges, ProtectSystem=full and ProtectHome, and only has write access to its own directory.

Step 16: Add TLS (Optional)

For production, terminate TLS at nginx. Point a DNS record at the VM, then use the packaged nginx with a certificate from Let's Encrypt:

sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain>

certbot installs the certificate, rewrites the nginx server block to listen on 443 and sets up automatic renewal. Keep the Basic Auth gate in place so the UI stays private over HTTPS.

Step 17: Change or Rotate the Password

The password lives in the nginx Basic Auth file. To set a new one, regenerate the entry with htpasswd (bcrypt) and reload nginx:

sudo htpasswd -B /etc/nginx/.perses.htpasswd admin
sudo systemctl reload nginx

Update /root/perses-credentials.txt if you want the note to reflect the new value. The password is only ever stored on this VM.

Step 18: Security Recommendations

  • Restrict the NSG so ports 80 and 22 only reach trusted networks.
  • Terminate TLS at nginx (Step 16) so the UI and API travel encrypted.
  • Keep Perses on loopback — it is served only through the nginx password gate; do not bind it to a public interface.
  • Rotate the password (Step 17) and store it in your secrets manager.
  • Back up /opt/perses/data to Azure Blob so your projects and dashboards survive a rebuild.
  • Patch the OS monthly with sudo apt-get update && sudo apt-get upgrade; unattended security upgrades are already enabled.

Step 19: Support and Licensing

Perses is licensed under the Apache License 2.0 — no per CPU or per user fee. cloudimg provides commercial support separately.

  • Email: support@cloudimg.co.uk
  • Website: www.cloudimg.co.uk
  • Support hours: 24/7, 24h response SLA

Deploy on Azure

Launch Perses on Ubuntu 24.04 with 24/7 support from cloudimg.

View on Marketplace

Need Help?

Our support team is available 24/7. support@cloudimg.co.uk