Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Uptrace Ubuntu
GUIDEInstall Guides

How to Install Uptrace on Ubuntu 24.04 — Self-Hosted OpenTelemetry APM

23 min read

How to Install Uptrace on Ubuntu 24.04 — Self-Hosted OpenTelemetry APM

Application performance monitoring does not have to come with a five-figure invoice. Uptrace is an open-source APM built natively on OpenTelemetry and backed by ClickHouse, the same columnar database that powers observability platforms at Cloudflare and eBay. This tutorial walks through a production-ready install on Ubuntu 24.04: Docker Compose stack, uptrace.yml configuration, Nginx TLS termination, and a worked example of instrumenting a real application with the OpenTelemetry SDK.

Recommended Plan: CloudCore Professional VPS — 6 vCPU, 12 GB RAM, 100 GB NVMe from EUR 19.99/month. Enough headroom for ClickHouse, PostgreSQL, and Nginx in one box.

Table of Contents

  • What is Uptrace?
  • Why Self-Host Instead of Using Datadog or SigNoz Cloud?
  • Prerequisites
  • Step 1: Prepare Ubuntu 24.04
  • Step 2: Install Docker and the Compose Plugin
  • Step 3: Fetch the Uptrace Docker Compose Bundle
  • Step 4: Configure uptrace.yml
  • Step 5: Start the Stack
  • Step 6: Put Nginx in Front with Let's Encrypt TLS
  • Step 7: Instrument Your First Application
  • Step 8: Use the OpenTelemetry Collector as a Gateway
  • Step 9: Retention, Backups, and Upgrades
  • Troubleshooting
  • FAQ
  • Next Steps
  • What is Uptrace?

    Uptrace is an open-source observability platform that accepts OpenTelemetry Protocol (OTLP) data — traces, metrics, and logs — and stores it in ClickHouse for fast, cheap querying. It is written in Go, distributed as a single binary or container, and uses PostgreSQL for configuration and ClickHouse for telemetry. The web UI provides distributed trace views, service maps, metric dashboards, log search, and alerting.

    Unlike traditional APMs that require proprietary agents, Uptrace sits behind the standard OTLP endpoint. Any language that has an OpenTelemetry SDK — Go, Python, Node.js, Java, .NET, Ruby, PHP, Rust — can send data with zero vendor-specific code. Swap Uptrace out for another OTel backend later and your instrumentation does not change.

    The architecture has three runtime components:

    • Uptrace (Go application) — receives OTLP, serves the UI, runs alerts.
    • ClickHouse — columnar database for spans, metrics, and logs. Massive compression (10-20x), subsecond queries over billions of rows.
    • PostgreSQL — stores users, projects, dashboards, saved queries, and alert rules.
    Everything runs happily on a single VPS for small-to-mid traffic workloads. Teams with 50M+ spans/day typically move ClickHouse to a dedicated node.

    Why Self-Host Instead of Using Datadog or SigNoz Cloud?

    Observability is one of the categories where managed SaaS costs balloon faster than anywhere else. A modest fleet of 20 hosts emitting traces and custom metrics on Datadog APM can run USD 1,500-3,000 per month before logs, real-user monitoring, or synthetic checks are factored in. Per-GB ingestion fees punish teams just as they are scaling their observability practice. SigNoz Cloud and New Relic One are less brutal but still priced per host or per ingested gigabyte.

    Self-hosting Uptrace on a single CloudCore Professional VPS at EUR 19.99/month changes the math entirely:

    • Flat-rate cost — EUR 19.99/month regardless of how many spans you send. No per-host billing, no ingestion overage.
    • Data sovereignty — Traces often contain URLs, request bodies, stack traces, and user identifiers. Keeping them in a VPS under your own DPA simplifies GDPR, HIPAA, and internal compliance audits.
    • No sampling anxiety — When storage costs EUR 0 per extra span, you can keep 100% of traces for small services instead of aggressive head-based sampling.
    • Open standards — OTLP in, ClickHouse out. If you outgrow Uptrace, point your collectors at any other OTel backend (SigNoz, Grafana Tempo, Honeycomb, Jaeger) without rewriting a line of instrumentation.
    • Works offline and in air-gapped networks — Useful for on-premises gateways, edge deployments, or regulated environments.

    Cost Comparison: Uptrace vs. Managed APM

    ScenarioDatadog APMSigNoz CloudNew RelicSelf-Hosted Uptrace
    10 hosts, 50M spans/mo~USD 310/mo~USD 199/mo~USD 99+ingestEUR 19.99/mo
    25 hosts, 200M spans/mo~USD 775/mo~USD 499/mo~USD 300+ingestEUR 19.99/mo
    Data residency controlLimited regionsShared infraShared infraFull (your VPS)
    Sampling forced?Often yesOptionalOften yesNo
    Custom ClickHouse queriesNoNoNoYes
    For any team above 5-10 hosts, self-hosting pays for itself in the first month and keeps paying for itself forever.

    Prerequisites

    Before starting, make sure you have:

    • A VPS running Ubuntu 24.04 LTS with root or sudo access. The CloudCore Professional plan (6 vCPU / 12 GB RAM / 100 GB NVMe / EUR 19.99 per month) is the recommended baseline.
    • A domain name you control, with an A record pointing to your VPS public IP (e.g. uptrace.yourdomain.com).
    • SSH access to the server as a user with sudo privileges.
    • At least 8 GB of RAM — ClickHouse and PostgreSQL together are memory-hungry. 12 GB is comfortable.
    • At least 40 GB of free disk space for 30 days of moderate-volume traces. Scale up if you plan to ingest heavily.
    Connect to your server:

    bash
    ssh root@your-server-ip

    Step 1: Prepare Ubuntu 24.04

    Update the package index and upgrade installed packages so dependency resolution runs against current metadata:

    bash
    sudo apt update && sudo apt upgrade -y

    Install baseline utilities you will reach for repeatedly:

    bash
    sudo apt install -y curl ca-certificates gnupg lsb-release ufw git vim

    Configure the firewall. We only expose SSH and HTTPS (443) publicly. Uptrace's OTLP ports stay on loopback, reachable via the reverse proxy:

    bash
    sudo ufw allow OpenSSH
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw --force enable
    sudo ufw status

    If the kernel was upgraded, reboot before continuing:

    bash
    sudo reboot

    Step 2: Install Docker and the Compose Plugin

    Uptrace ships an official Docker Compose bundle. Install the Docker Engine from the Docker repository (the Ubuntu-shipped docker.io package lags behind).

    Add the Docker GPG key and repository:

    bash
    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
      sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    sudo chmod a+r /etc/apt/keyrings/docker.gpg

    echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \ https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

    Install the engine, CLI, and Compose plugin:

    bash
    sudo apt update
    sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

    Verify:

    bash
    docker --version
    docker compose version

    Expected output:

    text
    Docker version 27.3.1, build ce1223035a
    Docker Compose version v2.29.7

    Add your sudo user to the docker group so you do not need sudo for every command:

    bash
    sudo usermod -aG docker $USER
    newgrp docker

    Step 3: Fetch the Uptrace Docker Compose Bundle

    Create a deployment directory and clone the example bundle that the Uptrace team maintains:

    bash
    sudo mkdir -p /opt/uptrace
    sudo chown $USER:$USER /opt/uptrace
    cd /opt/uptrace
    git clone https://github.com/uptrace/uptrace.git source
    cp -r source/example/docker/* .

    You now have the following layout under /opt/uptrace:

    text
    .
    ├── docker-compose.yml
    ├── config/
    │   └── uptrace.yml
    ├── vector.toml
    └── ...

    The docker-compose.yml wires together four services:

    • clickhouse — official ClickHouse server image, listens on port 9000 internally.
    • postgres — PostgreSQL 16 for Uptrace's metadata.
    • uptrace — the Uptrace backend and web UI, listens on 14317 (OTLP/gRPC), 14318 (OTLP/HTTP), and 14319 (web UI).
    • otelcol (optional) — an OpenTelemetry Collector pre-configured to forward to Uptrace.
    Inspect the compose file and adjust image tags if you want to pin specific versions. At the time of writing, pinning uptrace/uptrace:2.2 is recommended over the latest tag for production.

    Step 4: Configure uptrace.yml

    The single source of truth for Uptrace's runtime behaviour is config/uptrace.yml. Open it:

    bash
    vim /opt/uptrace/config/uptrace.yml

    The file is YAML with several sections. The ones you must edit before first boot:

    yaml
    ##
    

    Uptrace configuration

    See https://uptrace.dev/get/install.html for the full reference.

    ##

    PostgreSQL (metadata)

    pg: addr: postgres:5432 user: uptrace password: CHANGE_ME_STRONG_PG_PASSWORD database: uptrace

    ClickHouse (telemetry)

    ch: addr: clickhouse:9000 user: uptrace password: CHANGE_ME_STRONG_CH_PASSWORD database: uptrace

    Listen addresses — keep on loopback; Nginx terminates TLS.

    listen: http: addr: ':14318' grpc: addr: ':14317'

    The external URL users and agents will use.

    site: addr: 'https://uptrace.yourdomain.com'

    Initial admin user created on first boot.

    auth: users: - name: Admin email: [email protected] password: CHANGE_ME_STRONG_ADMIN_PASSWORD # Optional: OIDC / SSO block goes here.

    Projects — each gets a DSN (token) your apps use to send OTLP data.

    projects: - id: 1 name: production token: CHANGE_ME_RANDOM_PROJECT_TOKEN pinned_attrs: - service.name - host.name - deployment.environment

    Data retention and storage engine.

    ch_schema: spans: ttl_delete: 30 DAY metrics: ttl_delete: 90 DAY

    Secret used to sign session cookies.

    secret_key: CHANGE_ME_64_CHAR_RANDOM_STRING

    Alerting channels (optional).

    alerting: create_alerts_from_spans: enabled: true rules: - name: High error rate metrics: - uptrace.tracing.spans query: - group by project.id, service.name, deployment.environment - where span.status_code = 'error' - per_min(count($spans)) > 10 for: 5m

    Generate strong random values for each CHANGE_ME placeholder:

    bash
    openssl rand -hex 32   # use for secret_key and project token
    openssl rand -base64 24  # use for passwords

    Replace the four placeholders in uptrace.yml. Never commit this file to a public repository.

    Update the site URL to the domain you will serve Uptrace on. This address is used in email links, alert notifications, and the CORS config — if it does not match what users type in the browser, login will fail.

    Step 5: Start the Stack

    From /opt/uptrace, launch the full stack in the background:

    bash
    cd /opt/uptrace
    docker compose up -d

    Docker pulls the images (approximately 1.2 GB total across ClickHouse, Postgres, and Uptrace) and starts the containers. After 30-60 seconds, check status:

    bash
    docker compose ps

    Expected output:

    text
    NAME                   IMAGE                                COMMAND                  STATUS
    uptrace-clickhouse-1   clickhouse/clickhouse-server:24.9    "/entrypoint.sh"         Up (healthy)
    uptrace-postgres-1     postgres:16-alpine                   "docker-entrypoint..."   Up (healthy)
    uptrace-uptrace-1      uptrace/uptrace:2.2                  "/uptrace serve"         Up

    Tail the Uptrace logs on first boot. It runs database migrations against both PostgreSQL and ClickHouse:

    bash
    docker compose logs -f uptrace

    You should see lines like:

    text
    INFO migrating database pg...
    INFO migrating database ch...
    INFO listening on :14318 (http)
    INFO listening on :14317 (grpc)
    INFO serving UI on :14319

    Quick health check from the VPS itself:

    bash
    curl -I http://localhost:14319

    Expected output:

    text
    HTTP/1.1 200 OK
    Content-Type: text/html; charset=utf-8

    The UI is alive but not yet reachable from the internet. That is the next step.

    Step 6: Put Nginx in Front with Let's Encrypt TLS

    Never expose Uptrace's HTTP port directly. Terminate TLS at Nginx and keep everything else on localhost.

    Install Nginx and Certbot:

    bash
    sudo apt install -y nginx certbot python3-certbot-nginx

    Create the site config:

    bash
    sudo tee /etc/nginx/sites-available/uptrace > /dev/null <<'EOF'
    

    Uptrace — OpenTelemetry APM

    upstream uptrace_ui { server 127.0.0.1:14319; }

    upstream uptrace_otlp_http { server 127.0.0.1:14318; }

    server { listen 80; server_name uptrace.yourdomain.com; return 301 https://$host$request_uri; }

    server { listen 443 ssl http2; server_name uptrace.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/uptrace.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/uptrace.yourdomain.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options DENY;

    client_max_body_size 50m;

    # OTLP/HTTP ingest — /v1/traces, /v1/metrics, /v1/logs location /v1/ { proxy_pass http://uptrace_otlp_http; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 300s; }

    # Web UI and API location / { proxy_pass http://uptrace_ui; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;

    # Streaming responses and websockets proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_buffering off; proxy_read_timeout 300s; } } EOF

    Enable the site and issue a certificate:

    bash
    sudo ln -s /etc/nginx/sites-available/uptrace /etc/nginx/sites-enabled/
    sudo rm -f /etc/nginx/sites-enabled/default
    sudo nginx -t
    sudo systemctl reload nginx

    sudo certbot --nginx -d uptrace.yourdomain.com \ --non-interactive --agree-tos -m [email protected]

    Certbot edits the 443 server block to inject the correct certificate paths and sets up an auto-renewal timer. Verify the renewal hook:

    bash
    sudo systemctl list-timers | grep certbot

    Open https://uptrace.yourdomain.com in your browser. Log in with the admin credentials from uptrace.yml. You should see an empty Projects dashboard waiting for data.

    For OTLP/gRPC ingestion (port 14317) from external hosts, expose a second TLS endpoint via an Nginx stream block listening on 4317 with SSL passthrough, or simpler, use OTLP/HTTP which is already proxied on port 443 under /v1/.

    Step 7: Instrument Your First Application

    Time to send real telemetry. The pattern is identical across languages: install the OpenTelemetry SDK, point the exporter at Uptrace, add a service.name resource attribute.

    Node.js example

    bash
    npm install @opentelemetry/api \
      @opentelemetry/sdk-node \
      @opentelemetry/auto-instrumentations-node \
      @opentelemetry/exporter-trace-otlp-http \
      @opentelemetry/exporter-metrics-otlp-http

    Create otel.js:

    javascript
    const { NodeSDK } = require('@opentelemetry/sdk-node');
    const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
    const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');
    const { OTLPMetricExporter } = require('@opentelemetry/exporter-metrics-otlp-http');
    const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics');
    const { Resource } = require('@opentelemetry/resources');

    const UPTRACE_DSN = process.env.UPTRACE_DSN; // DSN format: https://<project-token>@uptrace.yourdomain.com/<project-id> const headers = { 'uptrace-dsn': UPTRACE_DSN };

    const sdk = new NodeSDK({ resource: new Resource({ 'service.name': 'web-api', 'service.version': '1.0.0', 'deployment.environment': 'production', }), traceExporter: new OTLPTraceExporter({ url: 'https://uptrace.yourdomain.com/v1/traces', headers, }), metricReader: new PeriodicExportingMetricReader({ exporter: new OTLPMetricExporter({ url: 'https://uptrace.yourdomain.com/v1/metrics', headers, }), exportIntervalMillis: 15000, }), instrumentations: [getNodeAutoInstrumentations()], });

    sdk.start();

    Run your app with --require ./otel.js and hit a few endpoints. Within 15-30 seconds, traces appear in the Uptrace UI under the web-api service.

    Python example

    bash
    pip install opentelemetry-distro opentelemetry-exporter-otlp
    opentelemetry-bootstrap --action=install

    Launch your app with auto-instrumentation:

    bash
    export OTEL_SERVICE_NAME=billing-worker
    export OTEL_RESOURCE_ATTRIBUTES="deployment.environment=production"
    export OTEL_EXPORTER_OTLP_ENDPOINT=https://uptrace.yourdomain.com
    export OTEL_EXPORTER_OTLP_HEADERS="uptrace-dsn=https://[email protected]/1"
    export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf

    opentelemetry-instrument python app.py

    Go example

    go
    import (
        "github.com/uptrace/uptrace-go/uptrace"
        "go.opentelemetry.io/otel"
    )

    uptrace.ConfigureOpentelemetry( uptrace.WithDSN("https://[email protected]/1"), uptrace.WithServiceName("checkout"), uptrace.WithServiceVersion("1.2.0"), uptrace.WithDeploymentEnvironment("production"), ) defer uptrace.Shutdown(ctx)

    tracer := otel.Tracer("checkout") ctx, span := tracer.Start(ctx, "process-order") defer span.End()

    Because everything is standard OTLP, the same pattern applies to Java (OpenTelemetryAgent JAR), .NET (OpenTelemetry.Extensions.Hosting), Ruby, PHP, and Rust.

    Step 8: Use the OpenTelemetry Collector as a Gateway

    For anything beyond a single application, put an OpenTelemetry Collector in front of Uptrace. The collector can:

    • Batch and compress spans before shipping (reduces egress costs).
    • Accept Prometheus scrape, Jaeger, Zipkin, Fluent Forward, and syslog formats and convert them to OTLP.
    • Tail-sample expensive traces (keep 100% of errors, 1% of healthy traffic).
    • Enrich spans with host metadata (Kubernetes labels, AWS instance tags, etc.).
    A minimal gateway config (otel-collector-config.yaml):

    yaml
    receivers:
      otlp:
        protocols:
          grpc: { endpoint: 0.0.0.0:4317 }
          http: { endpoint: 0.0.0.0:4318 }
      prometheus:
        config:
          scrape_configs:
            - job_name: node
              static_configs:
                - targets: ['node-exporter:9100']

    processors: batch: timeout: 5s send_batch_size: 10000 resourcedetection: detectors: [env, system]

    exporters: otlphttp/uptrace: endpoint: https://uptrace.yourdomain.com headers: uptrace-dsn: https://[email protected]/1

    service: pipelines: traces: receivers: [otlp] processors: [batch, resourcedetection] exporters: [otlphttp/uptrace] metrics: receivers: [otlp, prometheus] processors: [batch, resourcedetection] exporters: [otlphttp/uptrace]

    Applications send to the collector on the internal network; only the collector talks to Uptrace over TLS. This is also the recommended way to forward data from existing Prometheus scrape jobs into Uptrace without rewriting exporters.

    Step 9: Retention, Backups, and Upgrades

    Retention

    Data lifetime is controlled by ClickHouse TTLs, set in uptrace.yml under ch_schema. The defaults (30 days for spans, 90 days for metrics) match most teams' needs. If you want 90-day span retention, change:

    yaml
    ch_schema:
      spans:
        ttl_delete: 90 DAY

    Restart Uptrace after edits:

    bash
    docker compose restart uptrace

    Existing rows keep their original TTL; new rows pick up the new policy. To backfill, run an ALTER TABLE ... MODIFY TTL against ClickHouse manually.

    Backups

    Two things to back up:

  • PostgreSQL — small (< 100 MB typically). Dump nightly with pg_dump inside the container:
  • bash
    docker compose exec postgres pg_dump -U uptrace uptrace | gzip > /var/backups/uptrace-pg-$(date +%F).sql.gz
  • ClickHouse — much larger. For most deployments, the pragmatic approach is to rely on retention (old data is already expiring) and replicate to a second ClickHouse node instead of taking full snapshots. For small deployments, BACKUP to an S3-compatible bucket works well:
  • sql
    BACKUP DATABASE uptrace TO S3('https://s3.example.com/uptrace-backup', 'KEY', 'SECRET');

    Schedule both via cron or systemd timers.

    Upgrades

    bash
    cd /opt/uptrace
    git -C source pull
    docker compose pull
    docker compose up -d

    Read the Uptrace release notes before major version jumps. Minor versions run migrations automatically on startup.

    Troubleshooting

    ProblemCauseSolution
    Login page returns 502Uptrace container not ready or wrong upstream portdocker compose ps, check uptrace container is Up, verify Nginx upstream points to 14319
    "invalid DSN" error from SDKDSN format wrongMust be https://<token>@host/<project-id> where project-id is the numeric id from uptrace.yml
    No traces appearing, no errors in SDKClock skew on VPS (> 5 min)timedatectl status, enable systemd-timesyncd or chrony
    ClickHouse container OOM-killedDefault config too aggressive for small VPSSet CLICKHOUSE_MAX_MEMORY_USAGE=4000000000 env var in compose file
    Nginx client_max_body_size errors on bulk ingestLarge batched OTLP payloadsRaise client_max_body_size to 100m in the Uptrace server block
    TLS cert renewal failsPort 80 blocked by firewallsudo ufw allow 80/tcp, Certbot uses HTTP-01 challenge
    Query timeouts in UIClickHouse CPU-bound on large scansAdd an index on service.name, or move ClickHouse to a dedicated VPS
    High disk usage after 30 daysTTL not actually deletingCheck ClickHouse system log: docker compose exec clickhouse clickhouse-client --query "SELECT * FROM system.merges"

    Useful debug commands

    Stream Uptrace logs:

    bash
    docker compose logs -f uptrace

    Inspect what is in ClickHouse:

    bash
    docker compose exec clickhouse clickhouse-client
    sql
    SELECT count(), project_id, service.name
    FROM uptrace.spans_index
    WHERE time > now() - INTERVAL 1 HOUR
    GROUP BY project_id, service.name;

    Test OTLP ingest manually:

    bash
    curl -v https://uptrace.yourdomain.com/v1/traces \
      -H "Content-Type: application/json" \
      -H "uptrace-dsn: https://[email protected]/1" \
      -d '{"resourceSpans":[]}'

    An empty but well-formed payload should return HTTP 200.

    FAQ

    What is Uptrace and how does it differ from SigNoz?

    Uptrace and SigNoz are both open-source, ClickHouse-backed, OpenTelemetry-native APMs — they solve the same problem but made different engineering choices. Uptrace is a single Go service that bundles ingest, query, and UI; it is simpler to run and has a lighter footprint. SigNoz splits query and frontend into separate services and ships a feature-rich alerting and dashboarding experience. Both accept OTLP, so switching between them is a matter of changing an exporter endpoint.

    Why self-host Uptrace instead of using Datadog or SigNoz Cloud?

    Managed APM pricing scales punitively with host count and ingestion volume. A fleet emitting 200M spans per month typically runs USD 500-1,500 per month on Datadog or SigNoz Cloud. The same workload on a CloudCore Professional VPS at EUR 19.99/month is a rounding error — and you keep full control of trace data, which often contains PII, request payloads, and internal URLs that some teams cannot send to third-party SaaS under their compliance posture.

    What are the minimum hardware requirements?

    A 4 vCPU / 8 GB RAM VPS with 100 GB of NVMe storage handles roughly 5-10 million spans per day comfortably. ClickHouse is the main resource consumer — it uses RAM for its marks cache and CPU for compression during inserts. For production workloads above 50M spans/day, scale to 8 vCPU and 32 GB RAM, and mount dedicated storage for the ClickHouse data directory. The CloudCore Professional plan at EUR 19.99/month is a comfortable starting point.

    Can I send data from non-Go applications?

    Yes. Uptrace accepts OTLP over gRPC (port 14317) and HTTP (port 14318) from any OpenTelemetry SDK — Python, Node.js, Java, .NET, Ruby, PHP, Rust, Swift, and more. You can also front it with the OpenTelemetry Collector to receive Prometheus scrape, Jaeger, Zipkin, Fluent Forward, or syslog and convert them to OTLP before forwarding to Uptrace.

    How long is data retained by default?

    Uptrace stores data in ClickHouse with a default TTL of 30 days for spans and 90 days for metrics, configurable in uptrace.yml under ch_schema. Because ClickHouse compresses trace data aggressively (typically 10-20x), 30 days of a mid-sized service fits comfortably under 50 GB on disk. Extending to 90 or 180 days is usually a cheap change.

    Does Uptrace support alerting?

    Yes. Uptrace includes a built-in monitor/alert engine that evaluates metric thresholds, error rates, and span volumes on a schedule. It can send notifications to email, Slack, PagerDuty, Opsgenie, Telegram, and generic webhooks. Alert rules are defined in uptrace.yml under alerting.rules or created through the web UI.

    Can I use Grafana on top of Uptrace data?

    Yes. Because all telemetry lives in ClickHouse, you can point Grafana at the same ClickHouse instance using the official ClickHouse data source and build custom dashboards alongside Uptrace's built-in UI. This is a common pattern for teams who already standardize on Grafana and want a unified pane of glass across traces, metrics, logs, and business data.

    Next Steps

    Now that Uptrace is running, build out the rest of your observability stack:

    • Ship logs too — Uptrace accepts OTLP logs on the same endpoint. Forward application logs through the OpenTelemetry Collector's filelog receiver to correlate logs with traces automatically.
    • Add a collector gateway — Install the OpenTelemetry Collector on each host to batch, sample, and enrich telemetry before sending to Uptrace.
    • Pull Prometheus scrapes in — If you already run Prometheus, configure its remote write or use the collector's prometheus receiver to funnel existing scrape jobs into Uptrace without rewriting exporters.
    • Build custom dashboards in Grafana — Point Grafana at the ClickHouse data source and build team-specific dashboards on top of Uptrace's tables.
    • Wire up alerting channels — Connect Uptrace's alert rules to Slack, PagerDuty, or Opsgenie so on-call engineers see incidents where they already work.
    • Read the official docs — The Uptrace team maintains detailed installation and configuration notes at uptrace.dev/get/install.html. Bookmark it.

    Ready to deploy? Spin up a CloudCore Professional VPS — 6 vCPU, 12 GB RAM, 100 GB NVMe, unmetered bandwidth from EUR 19.99/month. Ubuntu 24.04 LTS images, full root access, and hourly billing. Perfect host for a single-node Uptrace stack.

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket