Deployment guide

Uptrace

Overview

Uptrace is an open-source application performance monitoring and observability platform built around OpenTelemetry. Your applications and agents send traces, metrics and logs to its OTLP endpoints. Uptrace stores them in a columnar backend, so you can search spans, chart metrics and correlate a slow trace with the logs and metrics around it, all from one web interface.

This image runs the full stack behind nginx over HTTPS. The Uptrace server is published on the loopback interface only, and nginx terminates TLS in front of it.

What you get:

  • Uptrace v2.0.3 from the official pinned container image uptrace/uptrace:2.0.3, baked into the image and published on loopback 127.0.0.1:8080
  • Its backing stores, all pinned and baked in: ClickHouse 26.3 (telemetry store, memory-capped to fit a 4 GiB VM), PostgreSQL 17 (metadata store) and Redis 7 (query cache), on a private container network
  • nginx terminating TLS on :443 in front of Uptrace (UI and OTLP HTTP), with :80 redirecting to HTTPS, and OTLP gRPC on :4317
  • A per-VM administrator account, per-VM database passwords, a per-VM OTLP ingest token and a per-VM signing secret, all generated on first boot. No default or shared credential ships in the image, and the upstream default admin@uptrace.local login never exists
  • docker.service, uptrace-firstboot.service, uptrace.service and nginx.service as systemd units, enabled and active
  • 24/7 SecureAnyCloud support
  • Uptrace is distributed under the AGPL-3.0 open-source license

Secure by default: per-VM credentials

This image ships with no default or shared secret: no databases, no user accounts, no ingest token and no signing secret ship in the image. On first boot, a one-shot service resolves your public URL and regenerates a per-VM TLS certificate. It mints a unique ClickHouse password, PostgreSQL password, administrator password, OTLP project token and service signing secret, and renders them into the configuration before anything is reachable.

The Uptrace stack is held back until that has happened, so a fresh VM is never reachable with a well-known default login. Retrieve the credentials over SSH, and change the password after your first login.

Prerequisites

Before you deploy, you need:

  • An active Azure subscription, an SSH key pair, and a VNet and subnet in the target region.
  • A Standard_B2s VM (2 vCPU / 4 GiB RAM) as a starting point. The full stack idles at roughly 1.2 GiB with ClickHouse memory-capped. Scale up for heavier ingest volumes.
  • NSG inbound rules that allow 22/tcp from your management network, 80/tcp and 443/tcp from wherever you browse the UI and send OTLP-over-HTTP, and 4317/tcp from wherever your applications send OTLP-over-gRPC (:80 only redirects to :443).

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Uptrace by SecureAnyCloud, and select Create. On the Basics tab, 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), HTTP (80) and HTTPS (443). Then click Review + create and Create. If you will send OTLP over gRPC, open 4317/tcp afterwards.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name uptrace \
  --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 uptrace --port 80 --priority 1010
az vm open-port --resource-group <your-rg> --name uptrace --port 443 --priority 1020
az vm open-port --resource-group <your-rg> --name uptrace --port 4317 --priority 1030

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

The message of the day shows your VM's Uptrace URL, administrator email and OTLP endpoints.

Step 4 - Confirm the services are running

Uptrace runs as systemd units: the Docker engine, the first-boot provisioner, the compose stack and nginx:

systemctl is-active docker.service uptrace.service nginx.service
active active active

Docker compose manages four containers: Uptrace and its ClickHouse, PostgreSQL and Redis backends. Uptrace is published only on the loopback interface, and the databases are on a private network with no host ports:

cd /opt/uptrace-appliance && sudo docker compose ps --format 'table {{.Service}}\t{{.Status}}'
SERVICE STATUS clickhouse Up (healthy) postgres Up (healthy) redis Up (healthy) uptrace Up

nginx is the only service bound to public web ports (:80 and :443). The Uptrace UI is on loopback, and OTLP gRPC is on :4317:

sudo ss -tln | grep -E ':(80|443|4317|8080) '
LISTEN 0 4096 127.0.0.1:8080 0.0.0.0:* LISTEN 0 4096 0.0.0.0:4317 0.0.0.0:* LISTEN 0 511 0.0.0.0:443 0.0.0.0:* LISTEN 0 511 0.0.0.0:80 0.0.0.0:*

The web UI is served over HTTPS, and plain HTTP redirects to it:

curl -sk -o /dev/null -w 'https:// -> %{http_code}\n' https://127.0.0.1/
curl -s -o /dev/null -w 'http:// -> %{http_code}\n' http://127.0.0.1/
https:// -> 200 http:// -> 301

Step 5 - Read the per-VM credentials

On first boot, the VM writes a root-only file with your Uptrace URL, the administrator email, the OTLP ingest token and the OTLP endpoints:

sudo grep -E '^UPTRACE_URL=|^UPTRACE_ADMIN_EMAIL=|^UPTRACE_OTLP_GRPC=' /root/uptrace-credentials.txt
UPTRACE_URL=https://<vm-public-ip> UPTRACE_ADMIN_EMAIL=admin@sac.local UPTRACE_OTLP_GRPC=<vm-public-ip>:4317

The UPTRACE_ADMIN_PASSWORD and UPTRACE_OTLP_TOKEN lines in that file hold your unique password and ingest token. Only the per-VM credential authenticates. A wrong password and the upstream default admin@uptrace.local / admin are both rejected:

E=$(sudo grep '^UPTRACE_ADMIN_EMAIL=' /root/uptrace-credentials.txt | cut -d= -f2-)
P=$(sudo grep '^UPTRACE_ADMIN_PASSWORD=' /root/uptrace-credentials.txt | cut -d= -f2-) L() { curl -sk -o /dev/null -w "$1 -> HTTP %{http_code}\n" -X POST https://127.0.0.1/internal/v1/users/login \
  -H 'Content-Type: application/json' --data "$2"; } L 'per-VM password' "{\"email\":\"$E\",\"password\":\"$P\"}" L 'wrong password ' "{\"email\":\"$E\",\"password\":\"wrong-nope\"}" L 'upstream default' '{"email":"admin@uptrace.local","password":"admin"}'
per-VM password -> HTTP 200 wrong password -> HTTP 400 upstream default -> HTTP 400

Step 6 - First login

Open Uptrace in your browser. Accept the self-signed certificate warning, or install a trusted certificate first (see Enabling a trusted TLS certificate):

https://<vm-public-ip>/

Enter the administrator email (admin@sac.local) and the UPTRACE_ADMIN_PASSWORD from Step 5, then sign in. Immediately after your first sign-in, change your password from your profile settings.

Step 7 - Send telemetry to Uptrace

Uptrace ingests OpenTelemetry data over OTLP: gRPC on :4317 and HTTP on :443 (/v1/traces, /v1/metrics, /v1/logs). Every request is authenticated by your project's DSN, which embeds the per-VM ingest token. The DSN is written to your credentials file:

sudo grep '^UPTRACE_DSN=' /root/uptrace-credentials.txt
UPTRACE_DSN=https://<uptrace-otlp-token>@<vm-public-ip>?grpc=4317

Verify the pipeline end to end from the VM itself. Send a test span over OTLP-HTTP with your token and a current timestamp, and Uptrace accepts it (HTTP 200):

T=$(sudo grep '^UPTRACE_OTLP_TOKEN=' /root/uptrace-credentials.txt | cut -d= -f2-)
NOW=$(date +%s)000000000 curl -sk -o /dev/null -w 'OTLP ingest -> HTTP %{http_code}\n' https://127.0.0.1/v1/traces \
  -H 'Content-Type: application/json' \
  -H "uptrace-dsn: https://$T@127.0.0.1?grpc=4317" \
  -d "{\"resourceSpans\":[{\"resource\":{\"attributes\":[{\"key\":\"service.name\",\"value\":{\"stringValue\":\"demo\"}}]},\"scopeSpans\":[{\"spans\":[{\"traceId\":\"c0ffee00038103d269b633813f0000aa\",\"spanId\":\"dec0de7ec3c100aa\",\"name\":\"demo-span\",\"kind\":2,\"startTimeUnixNano\":\"$NOW\",\"endTimeUnixNano\":\"$NOW\"}]}]}]}"
OTLP ingest -> HTTP 200

An OTLP request with a bad token is rejected (HTTP 403), so telemetry ingest is authenticated:

curl -sk -o /dev/null -w 'bad token -> HTTP %{http_code}\n' https://127.0.0.1/v1/traces \
  -H 'Content-Type: application/json' \
  -H 'uptrace-dsn: https://deadbeefdeadbeef@127.0.0.1?grpc=4317' \
  -d '{"resourceSpans":[{"resource":{"attributes":[]},"scopeSpans":[{"spans":[{"traceId":"c0ffee00038103d269b633813f0000bb","spanId":"dec0de7ec3c100bb","name":"x","kind":2,"startTimeUnixNano":"1","endTimeUnixNano":"1"}]}]}]}'
bad token -> HTTP 403

To send data from your own applications, point any OpenTelemetry SDK or the OpenTelemetry Collector at the DSN above. For example, use the OTLP exporter environment variables:

OTEL_EXPORTER_OTLP_ENDPOINT=https://<vm-public-ip>:4317 OTEL_EXPORTER_OTLP_HEADERS=uptrace-dsn=https://<uptrace-otlp-token>@<vm-public-ip>?grpc=4317 OTEL_EXPORTER_OTLP_PROTOCOL=grpc

Use current timestamps in your telemetry. Uptrace applies retention to stored data, so spans stamped far in the past are dropped.

Exploring traces and metrics

Once telemetry is flowing, the Traces & Logs view lists incoming spans with their service, operation, duration and status. You can filter and group them with the Uptrace query language:

Select a trace to open the full span tree. You can see where time went across services and drill into the attributes of an individual span:

Use the Metrics explorer to chart any metric you have ingested and to build dashboards and alerts alongside your traces:

Step 8 - The official pinned container images

Uptrace and its backends run from official upstream container images, each pinned to an exact version and baked into the VM image (no runtime pull):

cd /opt/uptrace-appliance && sudo docker compose images
CONTAINER REPOSITORY TAG PLATFORM IMAGE ID SIZE uptrace-clickhouse-1 clickhouse/clickhouse-server 26.3 linux/amd64 2ef11bbe2e44 266MB uptrace-postgres-1 postgres 17-alpine linux/amd64 742f40ea20b9 117MB uptrace-redis-1 redis 7-alpine linux/amd64 e7723ff73d96 16.3MB uptrace-uptrace-1 uptrace/uptrace 2.0.3 linux/amd64 5e42ea5f3bb9 57.1MB

Adding projects and rotating the ingest token

Uptrace groups telemetry into projects, each with its own ingest token. The image ships one project ("Project1") with your per-VM token. To add projects, change token values or add users, edit the seed data in /opt/uptrace-appliance/config.yml (the seed_data: block). Then apply the change with cd /opt/uptrace-appliance && sudo docker compose restart uptrace. Administrators can also manage users from the UI.

Security updates

The image is patched at build time, including Ubuntu phased updates, and unattended-upgrades stays enabled, so later security patches reach your VM. No packages should be held back:

apt-mark showhold

systemd units manage the docker and nginx packages. The applications themselves are the pinned container images described above.

Your data

Uptrace stores telemetry in the ClickHouse volume and metadata in the PostgreSQL volume, both docker-managed on the VM's OS disk:

sudo docker volume ls --filter name=uptrace_

To back up your telemetry, snapshot the OS disk of the VM in Azure. For a finer-grained schedule, use ClickHouse and PostgreSQL backup tooling.

Enabling a trusted TLS certificate

The image ships a per-VM self-signed certificate so HTTPS works out of the box. Browsers warn until you install a trusted certificate. To install one, point a DNS A record at the public IP of the VM and make sure 443/tcp is open in the NSG. Then install certbot and let it manage the nginx certificate. Replace the example values with your own domain and email:

sudo apt-get update
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.example.com -m you@example.com --agree-tos

certbot configures the HTTPS server block and sets up automatic renewal. After it completes, set site.url in /opt/uptrace-appliance/config.yml to https://your-domain.example.com and run cd /opt/uptrace-appliance && sudo docker compose restart uptrace. Uptrace is then available at your domain with a trusted certificate.

Upgrading Uptrace

Uptrace runs from pinned container images. To upgrade, edit the image tag in /opt/uptrace-appliance/docker-compose.yml. Then run cd /opt/uptrace-appliance && sudo docker compose pull uptrace && sudo docker compose up -d. The database schema migrates automatically on start. Always snapshot the OS disk first. SecureAnyCloud support can assist with planning and performing upgrades.

Support

This image is backed by 24/7 SecureAnyCloud support covering deployment, upgrades, OpenTelemetry integration, TLS termination and user administration. Contact us by email and chat.

Uptrace is a trademark of its respective owner. All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.

Deploy on Azure

Launch Uptrace on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View on Marketplace

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure