OpenObserve on Ubuntu 24.04 on Azure User Guide
Overview
OpenObserve is an open source, high performance observability platform that brings your logs, metrics and traces together in one place with a rich, built in web interface. It ships as a single self contained Go binary that stores data on local disk, so a single node runs the full search, dashboard and alerting experience with no external object store required and roughly a tenth of the storage footprint of Elasticsearch. The cloudimg image installs the pinned OpenObserve 0.91.1 binary and runs it as the openobserve systemd service, bound to loopback 127.0.0.1:5080 so it is never exposed directly, with an nginx reverse proxy on port 80 in front of it. OpenObserve has native user accounts: a root user is created uniquely on the first boot of every VM, and all ingest and REST APIs use HTTP Basic Auth with those per-VM credentials. Anonymous telemetry is disabled by default, so this VM observes your data privately out of the box. The local store (ingested logs, metrics and traces plus the metadata database) lives on a dedicated Azure data disk mounted at /var/lib/openobserve. Backed by 24/7 cloudimg support.
What is included:
- OpenObserve 0.91.1 installed as a single Go binary and running as the
openobservesystemd service - Logs, metrics and traces with a built in web UI on
:80, fronted by nginx with OpenObserve bound to loopback only - Native per-VM root account, with a unique password generated on first boot; all APIs use HTTP Basic Auth
- OpenObserve is bound to
127.0.0.1:5080- the app is never exposed to the network directly - Anonymous telemetry disabled by default for a private, self hosted setup
- A dedicated Azure data disk at
/var/lib/openobserveholding the local store and metadata database - The nginx proxy forwards the WebSocket upgrade OpenObserve uses for live tail
openobserve.service+nginx.serviceas systemd units, enabled and active- An unauthenticated
/healthzendpoint for Azure Load Balancer health probes - 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a comfortable starting point for evaluation and light workloads; scale up the VM and the data disk as your ingest volume grows. NSG inbound: allow 22/tcp from your management network, 80/tcp for the web UI and ingest, and 443/tcp if you add TLS. OpenObserve serves plain HTTP on port 80; for production use, terminate TLS in front of it with your own domain and restrict access to trusted IP ranges (see Maintenance).
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for OpenObserve by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Review the dedicated data disk on the Disks tab, then Review + create -> Create.
Step 2 - Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name openobserve \
--image <marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name openobserve --port 80 --priority 1010
Step 3 - Connect to your VM
ssh azureuser@<vm-public-ip>
Step 4 - Confirm the services are running
systemctl is-active openobserve.service nginx.service
Both report active. OpenObserve stores and serves logs, metrics and traces on the loopback connector 127.0.0.1:5080; nginx fronts it on port 80. The local store lives on the dedicated Azure data disk mounted at /var/lib/openobserve.

Step 5 - Retrieve your root login
OpenObserve has native user accounts. A root user is created on the first boot of your VM and its email and unique password are written to a root-only file:
sudo cat /root/openobserve-credentials.txt
This file contains OPENOBSERVE_USERNAME (the root email, admin@openobserve.local), OPENOBSERVE_PASSWORD and the OPENOBSERVE_URL to open in a browser. The password is only read at first start from a separate 0640 env file (/etc/openobserve/root-user.env), so no plaintext password ships in the image. Store the password somewhere safe.

Step 6 - Confirm the health endpoint
nginx proxies an unauthenticated health endpoint for load balancers and probes:
curl -s -o /dev/null -w '%{http_code}\n' http://localhost/healthz
It returns 200. This endpoint never requires authentication, so it is safe for an Azure Load Balancer health probe.
Step 7 - Confirm authentication and the streams API
Because the root user is set on first boot, an unauthenticated API request returns HTTP 401, so nobody reaches your data without credentials. The following reads the per-VM password from the credentials file and proves the round-trip - unauthenticated is rejected, a wrong password is rejected, the correct password authenticates, and an authenticated call to the streams API returns JSON:
PW=$(sudo grep '^OPENOBSERVE_PASSWORD=' /root/openobserve-credentials.txt | cut -d= -f2-)
E=admin@openobserve.local
echo "unauth : $(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1/api/default/streams)"
echo "wrongpw : $(curl -s -o /dev/null -w '%{http_code}' -u $E:wrong-pw http://127.0.0.1/api/default/streams)"
echo "authed : $(curl -s -o /dev/null -w '%{http_code}' -u $E:$PW http://127.0.0.1/api/default/streams)"
echo "streams : $(curl -s -u $E:$PW http://127.0.0.1/api/default/streams | python3 -c 'import sys,json;print(len(json.load(sys.stdin).get("list",[])),"stream(s)")')"
It prints unauth : 401, wrongpw : 401, authed : 200, then the stream count. Every API, like the whole UI, is only reachable with the per-VM credentials because OpenObserve itself is bound to loopback and nginx is the only way in.

Step 8 - Sign in to the web UI
Browse to http://<vm-public-ip>/. OpenObserve shows its sign in page: enter the root email admin@openobserve.local and the password from Step 5, then select Login. OpenObserve opens on its home view, with Logs, Metrics, Traces, Dashboards, Alerts and Streams in the left menu.

Step 9 - Search your logs
Open Logs from the left menu, pick a stream (for example app_logs) and a time range, then select Run query. OpenObserve shows an interactive histogram of matching events over time, a searchable field list on the left (level, service, status, duration and more), and the raw log records below - each expandable to its full JSON. Type a query in the search bar to filter by field or full text, and drag on the histogram to zoom into a window.

Step 10 - Ship your own data
OpenObserve ingests over a simple HTTP API and via OpenTelemetry (OTLP), Fluent Bit, Vector, Filebeat, Logstash and more. The Data sources page under Data gives you ready made snippets for each. The quickest test is a single log line over the JSON ingest API using the per-VM credentials:
PW=$(sudo grep '^OPENOBSERVE_PASSWORD=' /root/openobserve-credentials.txt | cut -d= -f2-)
E=admin@openobserve.local
curl -s -o /dev/null -w 'ingest -> %{http_code}\n' -u $E:$PW \
-H 'Content-Type: application/json' \
-d '[{"level":"info","service":"my-app","message":"hello from my application"}]' \
http://127.0.0.1/api/default/my_app_logs/_json
It prints ingest -> 200, and a new my_app_logs stream appears in Logs immediately. Point your applications, OpenTelemetry collectors or log shippers at this host on port 80 and search everything from one place.

Step 11 - Manage your streams
Open Streams under Data. Each stream (a named collection of logs, metrics or traces) is listed with its type, event count and on-disk size, and you can filter by Logs, Metrics, Traces or Metadata. From here you configure retention, user defined schemas and field settings per stream.

Step 12 - Confirm the store lives on the dedicated disk
OpenObserve keeps its local store - the write ahead log, the compacted parquet data files and the metadata database - under /var/lib/openobserve on the dedicated Azure data disk, so your observability history survives OS changes and the disk can be resized independently:
findmnt /var/lib/openobserve
The mount is backed by a separate Azure data disk captured into the image and re-provisioned on every VM. The store grows under /var/lib/openobserve as you ingest data.

Maintenance
- Password and users: the root password is set on first boot and read only at first start from
/etc/openobserve/root-user.env. Create additional users and rotate credentials from IAM / Users in the web UI once you are signed in as root. - Restrict access: OpenObserve serves plain HTTP on port 80. For production, restrict the UI to trusted IP ranges in your Network Security Group, and front it with TLS (for example certbot with your own domain) terminating on
:443. - Loopback binding: OpenObserve is bound to
127.0.0.1:5080viaZO_HTTP_ADDR/ZO_HTTP_PORTin/etc/openobserve/openobserve.env, so nginx is the only path in. Keep it that way - do not change the bind address to a public interface. - Scale out: a single node stores everything on local disk. For larger deployments, point OpenObserve at object storage (S3 or Azure Blob) and an external metadata database, and run it in cluster mode - see the OpenObserve documentation.
- Ingest: send data over the HTTP JSON API, OpenTelemetry (OTLP), Fluent Bit, Vector, Filebeat, Logstash and more; the Data sources page in the UI has copy-paste snippets for each.
- Storage: all OpenObserve state lives under
/var/lib/openobserveon the data disk; back up that volume to protect your observability history, and resize the disk as ingest grows. - Telemetry: anonymous telemetry is disabled by default via
ZO_TELEMETRY=falsein/etc/openobserve/openobserve.envfor a fully self hosted, private setup. - Licensing (AGPL-3.0): OpenObserve is licensed under the GNU Affero General Public License v3.0. The image ships the unmodified upstream binary. Under the AGPL, if you modify OpenObserve and offer the modified version to users over a network, you must also offer them the corresponding source of your modifications; running the unmodified binary carries no such obligation.
- Security patches: unattended-upgrades remains enabled so the OS continues to receive security updates automatically.
Support
cloudimg provides 24/7 expert support for this image. Contact support@cloudimg.co.uk.