# Uptrace Configuration Reference

> Reference guide for every Uptrace configuration option from file management to environment variables and ClickHouse tuning.

All Uptrace settings live in a single YAML file. This page documents every option — databases, networking, TLS, authentication, processing pipelines, and features.

## Configuration file

### Creating the config file

Generate a default configuration file:

```shell
./uptrace config create -config=/path/to/config.yml
```

Specify the config file location using either method:

```shell
# CLI argument (recommended)
uptrace --config=/etc/uptrace/config.yml serve

# Environment variable
export UPTRACE_CONFIG=/etc/uptrace/config.yml
uptrace serve
```

If no path is specified, Uptrace defaults to `/etc/uptrace/config.yml`.

### Environment variables

Use environment variables in your YAML configuration for secrets and per-environment overrides:

```yml
pg:
  addr: ${UPTRACE_PG_ADDR:localhost:5432}
  user: ${UPTRACE_PG_USER:uptrace}
  password: ${UPTRACE_PG_PASSWORD}
  database: ${UPTRACE_PG_DATABASE:uptrace}
```

<table>
<thead>
  <tr>
    <th>
      Syntax
    </th>
    
    <th>
      Behavior
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        ${ENV_VAR_NAME}
      </code>
    </td>
    
    <td>
      Simple substitution
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ${ENV_VAR_NAME:default_value}
      </code>
    </td>
    
    <td>
      Substitution with fallback
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        $$
      </code>
    </td>
    
    <td>
      Literal <code>
        $
      </code>
    </td>
  </tr>
</tbody>
</table>

Variables are expanded using Go's [os.Expand](https://pkg.go.dev/os#Expand) before YAML parsing.

## Database configuration

Uptrace uses PostgreSQL for metadata (users, projects, dashboards, alerts) and ClickHouse for high-volume telemetry (spans, logs, metrics).

### PostgreSQL

PostgreSQL stores application metadata. This database typically requires only a few megabytes of storage.

```yml
pg:
  addr: localhost:5432
  user: uptrace
  password: uptrace
  database: uptrace

  #tls:
  #  insecure_skip_verify: true  # Only for self-signed certificates
```

**With read replicas:**

```yml
pg:
  addr: primary-host:5432
  user: uptrace
  password: uptrace
  database: uptrace

  replicas:
    - standby-host1:5432
    - standby-host2:5432
```

**Using a connection string:**

```yaml
pg:
  dsn: postgresql://user:password@host:5432/database?sslmode=verify-full
```

### ClickHouse

ClickHouse stores telemetry data — spans, logs, and metrics. It's optimized for analytical queries and time-series data.

```yml
ch_cluster:
  cluster: 'uptrace1'
  replicated: false   # Enable for automatic failover
  distributed: false  # Enable for horizontal scaling (Premium only)

  shards:
    - replicas:
        - addr: localhost:9000
          user: default
          password: ''
          database: uptrace
          dial_timeout: 3s
          write_timeout: 5s
          max_retries: 3
          max_execution_time: 15s
```

**With replication (3 nodes):**

```yml
ch_cluster:
  cluster: 'uptrace1'
  replicated: true

  shards:
    - replicas:
        - addr: clickhouse-1:9000
          user: default
          password: ''
          database: uptrace

        - addr: clickhouse-2:9000
          user: default
          password: ''
          database: uptrace

        - addr: clickhouse-3:9000
          user: default
          password: ''
          database: uptrace
```

**Using a connection string:**

```yaml
ch_cluster:
  shards:
    - replicas:
        - dsn: clickhouse://your_username:your_password@your_host:9000/your_database
          dial_timeout: 3s
          write_timeout: 5s
          max_retries: 3
          max_execution_time: 15s
```

### Advanced ClickHouse settings

**Query settings:**

```yml
ch_cluster:
  shards:
    - replicas:
        - addr: localhost:9000
          query_settings:
            async_insert: 1
            wait_for_async_insert: 1
            max_memory_usage: 10000000000 # 10 GB per query
```

**TLS — ClickHouse server side:**

```xml
<?xml version="1.0" ?>
<clickhouse>
  <tcp_port_secure>9440</tcp_port_secure>

  <openSSL>
    <server>
      <certificateFile>/etc/clickhouse/certs/chnode.crt</certificateFile>
      <privateKeyFile>/etc/clickhouse/certs/chnode.key</privateKeyFile>
      <verificationMode>relaxed</verificationMode>
      <caConfig>/etc/clickhouse/certs/Uptrace_CA.crt</caConfig>
      <cacheSessions>true</cacheSessions>
      <disableProtocols>sslv2,sslv3</disableProtocols>
      <preferServerCiphers>true</preferServerCiphers>
    </server>
  </openSSL>
</clickhouse>
```

**TLS — Uptrace side:**

```yml
ch_cluster:
  shards:
    - replicas:
        - addr: localhost:9440
          user: default
          database: uptrace

          tls:
            ca_file: /etc/clickhouse/certs/Uptrace_CA.crt
            cert_file: /etc/clickhouse/certs/chnode.crt
            key_file: /etc/clickhouse/certs/chnode.key
            insecure_skip_verify: false
```

**ClickHouse Cloud:**

```yml
ch_cluster:
  shards:
    - replicas:
        - addr: tm849a32za.us-central1.gcp.clickhouse.cloud:9440
          user: default
          password: your_cloud_password
          database: uptrace
          tls:
            server_name_override: 'tm849a32za.us-central1.gcp.clickhouse.cloud'
```

## Database management

### Resetting ClickHouse

Reset the ClickHouse database to apply schema changes or start fresh:

```shell
uptrace ch reset
```

This is equivalent to running `uptrace ch rollback` followed by `uptrace ch migrate`.

**Warning:** This deletes all telemetry data (spans, logs, metrics).

### Resetting PostgreSQL

Reset the PostgreSQL database to clear metadata:

```shell
uptrace pg reset
```

This is equivalent to running `uptrace pg rollback` followed by `uptrace pg migrate`.

**Warning:** This deletes all metadata including users, projects, dashboards, and alerts.

## Schema configuration

Customize ClickHouse schema settings for performance and storage efficiency. Schema changes require a database reset (`uptrace ch reset`) and **delete all existing data**.

### Storage and compression

```yml
ch_schema:
  # LZ4: fast, moderate ratio. ZSTD(1): better ratio, slightly slower.
  compression: ZSTD(1)

  # Storage policies — map tables to storage tiers (SSD, HDD, S3)
  spans_index: { storage_policy: hot_storage }
  spans_data: { storage_policy: warm_storage }
  span_links: { storage_policy: cold_storage }
  logs_index: { storage_policy: hot_storage }
  logs_data: { storage_policy: warm_storage }
  events_index: { storage_policy: hot_storage }
  events_data: { storage_policy: warm_storage }
  metrics: { storage_policy: hot_storage }
```

### Replication setup

**Step 1:** Configure the ClickHouse cluster with at least 3 replicas. Set `internal_replication = true` to prevent data duplication.

```xml
<clickhouse>
  <remote_servers>
    <uptrace1>
      <shard>
        <internal_replication>true</internal_replication>
        <replica>
          <host>clickhouse-1</host>
          <port>9000</port>
        </replica>
        <replica>
          <host>clickhouse-2</host>
          <port>9000</port>
        </replica>
        <replica>
          <host>clickhouse-3</host>
          <port>9000</port>
        </replica>
      </shard>
    </uptrace1>
  </remote_servers>
</clickhouse>
```

**Step 2:** Enable replication in Uptrace:

```yml
ch_cluster:
  cluster: 'uptrace1'
  replicated: true

  shards:
    - replicas:
        - addr: clickhouse-1:9000
        - addr: clickhouse-2:9000
        - addr: clickhouse-3:9000
```

**Step 3:** Apply with `uptrace ch reset`.

**Step 4:** Verify replication status:

```sql
SELECT
    database,
    table,
    is_leader,
    replica_is_active
FROM system.replicas;
```

Expected output:

```text
┌─database─┬─table───────────┬─is_leader─┬─replica_is_active────────────────────────┐
│ uptrace  │ spans_data      │         1 │ {'replica1':1,'replica2':1,'replica3':1} │
│ uptrace  │ spans_index     │         1 │ {'replica1':1,'replica2':1,'replica3':1} │
└──────────┴─────────────────┴───────────┴──────────────────────────────────────────┘
```

## Network configuration

### Ports

```yml
listen:
  http:
    addr: ':80'    # OTLP/HTTP, REST API, web UI

  grpc:
    addr: ':4317'  # OTLP/gRPC

  #tls:
  #  cert_file: /etc/uptrace/uptrace.crt
  #  key_file: /etc/uptrace/uptrace.key
```

### gRPC transport and stream lifetime

The gRPC listener accepts OTLP and [OTel Arrow](/ingest/otelarrow) telemetry. These transport options rarely need tuning, but are available under `listen.grpc`:

```yml
listen:
  grpc:
    addr: ':4317'

    # Largest message the server accepts (default: 64MiB).
    max_recv_msg_size: 67108864

    # Per-connection read/write buffers (defaults: 64KiB / 16KiB).
    read_buffer_size: 65536
    write_buffer_size: 16384

    # Reuse write buffers across connections to lower heap pressure (default: true).
    shared_write_buffer: true

    # Close each connection once it reaches this age, forcing OTel Arrow
    # streams to rotate so load balancers can redistribute clients evenly
    # (default: 5m).
    max_connection_age: 5m
```

<table>
<thead>
  <tr>
    <th>
      Option
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        max_recv_msg_size
      </code>
    </td>
    
    <td>
      <code>
        64MiB
      </code>
    </td>
    
    <td>
      Maximum message size the server accepts
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        read_buffer_size
      </code>
    </td>
    
    <td>
      <code>
        64KiB
      </code>
    </td>
    
    <td>
      Per-connection read buffer
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        write_buffer_size
      </code>
    </td>
    
    <td>
      <code>
        16KiB
      </code>
    </td>
    
    <td>
      Per-connection write buffer
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        shared_write_buffer
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Reuse write buffers across connections
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        max_connection_age
      </code>
    </td>
    
    <td>
      <code>
        5m
      </code>
    </td>
    
    <td>
      Age at which a connection is closed, bounding OTel Arrow stream lifetime
    </td>
  </tr>
</tbody>
</table>

`max_connection_age` is the server-side bound on how long an OTel Arrow stream can live. After a connection reaches this age the server sends a gRPC `GOAWAY` and, following a one-minute grace period for in-flight requests, closes it. This recycles long-lived Arrow streams so an L4/L7 load balancer can rebalance clients across Uptrace instances and so dictionary state stays bounded. See the [OTel Arrow in production](https://opentelemetry.io/blog/2024/otel-arrow-production/#experiment-compression-as-a-function-of-stream-lifetime) experiment for the rationale.

When sending data with the OTel Arrow exporter, keep the client's `arrow.max_stream_lifetime` below this value so streams recycle gracefully — see [Ingesting telemetry using OTel Arrow](/ingest/otelarrow#stream-lifetime).

### Domain and URL

```yml
site:
  # Used for dashboard links, CORS, and auth redirects.
  # Must match your reverse proxy setup.
  url: https://uptrace.mycompany.com

  # Optional: dedicated ingestion endpoint.
  # Defaults to site.url if not set.
  ingest_url: https://ingest.mycompany.com
```

## TLS configuration

### Automatic TLS with Let's Encrypt

```yml
certmagic:
  enabled: true
  staging_ca: false           # Set true for testing
  http_challenge_addr: ':80'  # Port for HTTP-01 challenge
```

### Manual TLS certificates

Generate a self-signed certificate for development:

```shell
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
  -keyout uptrace.key -out uptrace.crt -subj "/CN=localhost" \
  -addext "subjectAltName=DNS:localhost,DNS:uptrace.local"
```

Add to the system trust store:

```shell
sudo cp uptrace.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
```

Configure Uptrace:

```yml
listen:
  grpc:
    addr: ':4317'
  http:
    addr: ':443'
  tls:
    cert_file: /etc/uptrace/tls/uptrace.crt
    key_file: /etc/uptrace/tls/uptrace.key
    min_version: '1.2'

site:
  url: 'https://uptrace.mycompany.com'
```

### Database TLS

Full TLS client options (PostgreSQL example):

```yml
pg:
  addr: localhost:5432
  user: uptrace
  password: uptrace
  database: uptrace
  tls:
    cert_file: /etc/uptrace/client.crt
    key_file: /etc/uptrace/client.key
    ca_file: /etc/uptrace/ca.crt
    min_version: '1.2'
    max_version: '1.3'
    insecure_skip_verify: false
    server_name_override: ''
```

Common shortcuts:

```yml
# Use system certificate store
pg:
  tls: {}

# Skip certificate verification (testing only)
pg:
  tls:
    insecure_skip_verify: true

# Disable TLS entirely
pg:
  tls:
    insecure: true
```

## Authentication

### Seed data

Initial users, organizations, and projects are created on first startup and can be modified through the UI afterward:

```yml
seed_data:
  users:
    - key: admin_user
      name: System Administrator
      email: admin@mycompany.com
      password: ChangeThisPassword123!
      email_confirmed: true

  user_tokens:
    - key: admin_token
      user: admin_user
      token: secure_admin_token_here

  orgs:
    - key: main_org
      name: My Company

  org_users:
    - key: admin_org_membership
      org: main_org
      user: admin_user
      role: owner  # owner, admin, member

  projects:
    - key: production_project
      name: Production Environment
      org: main_org

  project_tokens:
    - key: prod_token
      project: production_project
      token: prod_telemetry_secret  # Used in OTLP DSN

  project_users:
    - key: admin_project_access
      project: production_project
      user: admin_user
      perm_level: admin  # admin, editor, viewer
```

### Auth settings

```yml
auth:
  # Disable built-in password auth (use SSO only)
  #disabled: true

  # Block new registrations
  #sign_up_disabled: true

  # Block all sign-ins (maintenance mode)
  #sign_in_disabled: true

  # Restrict registration to a domain
  #email_regexp: '^.+@mycompany\.com$'
```

<table>
<thead>
  <tr>
    <th>
      Scenario
    </th>
    
    <th>
      Setting
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      SSO only
    </td>
    
    <td>
      <code>
        disabled: true
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      No new registrations
    </td>
    
    <td>
      <code>
        sign_up_disabled: true
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Maintenance mode
    </td>
    
    <td>
      <code>
        sign_in_disabled: true
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Restrict to company domain
    </td>
    
    <td>
      <code>
        email_regexp: '^.+@mycompany\.com$'
      </code>
    </td>
  </tr>
</tbody>
</table>

### Single Sign-On

Uptrace supports enterprise identity providers:

- **Okta**
- **Keycloak**
- **Google Workspace**

## Processing pipelines

Uptrace processes telemetry through parallel pipelines — one each for spans, span links, logs, events, and metrics. For detailed tuning guidance, see [Scaling Uptrace](/get/hosted/scale).

```yml
spans:
  max_threads: 16             # Processing goroutines (default: CPU cores)
  ch_max_insert_size: 10000   # Records per INSERT batch
  max_buffered_bytes: 536870912  # 512 MiB buffer cap

span_links:
  disabled: false
  max_threads: 2
  ch_max_insert_size: 5000
  max_buffered_bytes: 67108864  # 64 MiB

logs:
  max_threads: 12
  ch_max_insert_size: 15000
  max_buffered_bytes: 402653184  # 384 MiB

events:
  max_threads: 4
  ch_max_insert_size: 5000
  max_buffered_bytes: 134217728  # 128 MiB

metrics:
  max_threads: 8
  ch_max_insert_size: 10000
  max_buffered_bytes: 268435456  # 256 MiB
  max_cumulative_timeseries: 2000000  # Cumulative-to-delta conversion limit
```

### Query limits

Prevent resource exhaustion from expensive queries:

```yml
trace:
  query_limit: 500000             # Max spans per query
  max_memory_usage_bytes: 500000000  # 500 MB per query
```

### Redis cache

```yml
redis_cache:
  addrs:
    alpha: redis-1:6379
    bravo: redis-2:6379
  username: ''
  password: 'redis_password'
  db: 0
  dial_timeout: 5s
  read_timeout: 3s
  write_timeout: 3s
  #tls:
  #  insecure_skip_verify: false
```

## Features

### Alerting and service graph

```yml
alerting:
  #disabled: true  # Disable the alerting system

service_graph:
  #disabled: true  # Disable service graph processing

self_monitoring:
  disabled: false
  dsn: http://project1_secret@uptrace.local/2?grpc=4317
```

### Source maps

Configure [JavaScript source map processing](/features/sourcemaps) to resolve minified stack traces:

```yml
sourcemaps:
  #disabled: true
  #upload_disabled: true
  #http_timeout: 5s
  #source_cache_size: 100000
  #consumer_cache_size: 4
  #error_cache_size: 100000
```

<table>
<thead>
  <tr>
    <th>
      Option
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        disabled
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Disable all sourcemap processing
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        upload_disabled
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Disable user-uploaded source maps (storage and resolution)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        http_timeout
      </code>
    </td>
    
    <td>
      <code>
        5s
      </code>
    </td>
    
    <td>
      Timeout for fetching discovered source maps over HTTP (max <code>
        30s
      </code>
      
      )
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        source_cache_size
      </code>
    </td>
    
    <td>
      scales with CPU
    </td>
    
    <td>
      Max resolved source positions to cache
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        consumer_cache_size
      </code>
    </td>
    
    <td>
      scales with CPU
    </td>
    
    <td>
      Max parsed source map files in memory
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        error_cache_size
      </code>
    </td>
    
    <td>
      scales with CPU
    </td>
    
    <td>
      Max failed lookups to cache
    </td>
  </tr>
</tbody>
</table>

## Notifications

### Email (SMTP)

```yml
mailer:
  smtp:
    enabled: false
    host: localhost
    port: 1025
    username: mailhog
    password: mailhog
    from: no-reply@uptrace.local
    #tls: { insecure: true }
```

**Gmail example:**

1. Generate an app-specific password in Gmail settings.
2. Configure Uptrace:

```yml
mailer:
  smtp:
    enabled: true
    host: smtp.gmail.com
    port: 587
    username: youraccount@gmail.com
    password: your_app_specific_password
    from: 'youraccount@gmail.com'
```

### Telegram

```yml
telegram:
  bot_token: 'your_telegram_bot_token'
```

Setup guide: [BotFather](https://core.telegram.org/bots#6-botfather).

## System settings

### Logging

```yml
logging:
  level: INFO  # DEBUG, INFO, WARN, ERROR
```

### Premium license

```yml
license:
  key: 'your_premium_license_key'
```

Premium features: ClickHouse distributed tables, advanced SSO, priority support.

## Deployment

### Production checklist

**Security:**

- Change all default passwords and tokens in `seed_data`
- Configure TLS for all connections
- Set up auth restrictions (`auth.email_regexp`)
- Configure firewall rules

**High availability:**

- Deploy multiple Uptrace instances behind a load balancer
- Configure PostgreSQL with read replicas
- Set up ClickHouse replication (minimum 3 nodes)
- Configure Redis for caching and session storage
- Set up database backups

**Performance:**

- Tune processing pipelines based on ingestion volume (see [Scaling Uptrace](/get/hosted/scale))
- Configure data retention policies
- Set up monitoring for Uptrace itself

### Reverse proxy

```yml
site:
  url: https://uptrace.mycompany.com       # Main deployment
  # url: https://mycompany.com/uptrace     # Subpath deployment
```

When deploying under a subpath (e.g., `/uptrace`), the reverse proxy must strip the prefix before forwarding. Rewrite `/uptrace(/|$)(.*)` to `/$2`:

<code-group>

```nginx [Nginx]
location ~ ^/uptrace(/|$) {
    rewrite ^/uptrace$ / break;
    rewrite ^/uptrace(/.*)$ $1 break;
    proxy_pass http://uptrace:14318;
    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;
}
```

```haproxy [HAProxy]
frontend http_front
    bind *:80
    acl is_uptrace path_beg /uptrace
    use_backend uptrace_backend if is_uptrace

backend uptrace_backend
    http-request replace-path /uptrace(/|$)(.*) /\2
    http-request set-header X-Forwarded-Proto https
    http-request set-header X-Forwarded-For %[src]
    server uptrace uptrace:14318 check
```

```yaml [Traefik]
labels:
  - "traefik.enable=true"
  - "traefik.http.routers.uptrace.rule=PathPrefix(`/uptrace`)"
  - "traefik.http.routers.uptrace.middlewares=uptrace-strip"
  - "traefik.http.middlewares.uptrace-strip.stripprefix.prefixes=/uptrace"
  - "traefik.http.services.uptrace.loadbalancer.server.port=14318"
```

</code-group>

**Health check endpoint:** `GET /api/health` → `200 OK`

### Scaling

For processing pipeline tuning, ClickHouse insert optimization, sharding, and resource sizing, see [Scaling Uptrace](/get/hosted/scale).
