# Self-Hosted ClickStack Observability

**A fully self-hosted observability stack in a single container.**

This guide walks you through setting up Qtap with [ClickStack](https://clickhouse.com/clickstack) — a self-contained observability stack that bundles ClickHouse, an OTel collector, and the HyperDX UI into a single Docker image. Events and artifacts flow through OpenTelemetry, with no S3 setup required.

{% hint style="success" %}
**Quick version:** Run ClickStack, point Qtap at it, see traffic in your browser. Total setup time: \~5 minutes.
{% endhint %}

***

## What You'll Get

| Component      | What It Does                                      | Port             |
| -------------- | ------------------------------------------------- | ---------------- |
| **ClickStack** | ClickHouse + OTel collector + HyperDX UI          | 8080, 4317, 4318 |
| **Qtap**       | eBPF agent capturing traffic and sending via OTel | —                |

Both events (connection metadata, HTTP transactions) and objects (request/response headers and bodies) are sent through the same OTel endpoint. No separate object storage to configure.

***

## Prerequisites

* Docker installed
* Linux host with kernel 5.8+ (for eBPF)
* Root or `CAP_BPF` + `CAP_SYS_ADMIN` capabilities

***

## Step 1: Start ClickStack

```bash
docker run -d --name clickstack \
   -p 8080:8080 \
   -p 4317:4317 \
   -p 4318:4318 \
   -e BETA_CH_OTEL_JSON_SCHEMA_ENABLED=true \
   clickhouse/clickstack-local:latest
```

Wait for it to be ready:

```bash
docker logs -f clickstack
```

Once you see the startup complete, visit <http://localhost:8080> to access the HyperDX UI.

***

## Step 2: Create the Qtap Configuration

Create a file called `qtap-clickstack.yaml`:

```yaml
version: 2
services:
    event_stores:
        - type: otel
          endpoint: "localhost:4317"
          protocol: grpc
          service_name: "qtap"
          environment: "production"
          tls:
              enabled: false
    object_stores:
        - type: otel
          otel_endpoint: "localhost:4317"
          protocol: grpc
          service_name: "qtap"
          environment: "production"
          tls:
              enabled: false
stacks:
    basic_reporting:
        plugins:
            - type: http_capture
              config:
                  level: full
                  format: json
            - type: report_usage
tap:
    direction: egress
    ignore_loopback: true
    audit_include_dns: false
    http:
        stack: basic_reporting
```

This configuration:

* Sends **events** (connection metadata, HTTP transaction summaries) to ClickStack via OTel
* Sends **objects** (full request/response headers and bodies) to ClickStack via OTel
* Captures **all egress HTTP traffic** at full detail level
* Both stores share the same OTel endpoint — no S3 credentials needed

{% hint style="info" %}
This replaces many small S3 files with batched OTLP log records, which ClickHouse ingests efficiently.
{% endhint %}

***

## Step 3: Start Qtap

```bash
docker run -d --name qtap \
  --user 0:0 --privileged \
  --pid=host --network=host \
  -v /sys:/sys \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v "$(pwd)/qtap-clickstack.yaml:/app/config/qtap.yaml" \
  -e TINI_SUBREAPER=1 \
  --ulimit=memlock=-1 \
  us-docker.pkg.dev/qpoint-edge/public/qtap:v0 \
  --log-level=info \
  --log-encoding=console \
  --config="/app/config/qtap.yaml"
```

Verify Qtap is running and connected:

```bash
docker logs qtap 2>&1 | tail -20
```

You should see the eventstore and objectstore initialize successfully:

```
INFO    eventstore.otel initialized
INFO    objectstore.otel initialized
```

***

## Step 4: Generate Traffic and View

Generate some traffic:

```bash
curl https://httpbin.org/get
curl https://api.github.com
curl -X POST https://httpbin.org/post -d '{"test": "data"}'
```

Open <http://localhost:8080> in your browser. In the HyperDX UI, create a source with table name `otel_logs` to view captured events and artifacts.

You'll see:

* **Connection events** — TCP connections with protocol detection, TLS info, process attribution
* **HTTP transaction summaries** — method, URL, status, duration, content type
* **Full request/response data** — headers and bodies captured by the `http_capture` plugin

***

## How It Works

```
Your Applications
       │
       │  (HTTP/HTTPS traffic)
       ▼
    Qtap (eBPF)
       │
       ├── Events ──→ OTel (gRPC :4317) ──→ ClickStack ──→ ClickHouse
       │
       └── Objects ──→ OTel (gRPC :4317) ──→ ClickStack ──→ ClickHouse
```

Qtap captures traffic using eBPF and exports both event metadata and full artifacts as OpenTelemetry Logs. ClickStack receives them through its built-in OTel collector and stores everything in ClickHouse.

***

## Configuration Options

### Capture Level

Control how much detail is captured per request:

| Level     | What's Captured                    |
| --------- | ---------------------------------- |
| `none`    | Connection metadata only           |
| `summary` | HTTP method, URL, status, duration |
| `details` | Summary + headers                  |
| `full`    | Summary + headers + bodies         |

Change the level in the `http_capture` plugin:

```yaml
plugins:
    - type: http_capture
      config:
          level: summary    # Less data, lower storage
          format: json
```

### Traffic Direction

Control which traffic is captured:

| Direction         | What's Captured            |
| ----------------- | -------------------------- |
| `egress`          | All outbound traffic       |
| `egress-external` | Only external destinations |
| `egress-internal` | Only internal destinations |

***

## Cleanup

```bash
docker rm -f qtap clickstack
```

***

## Next Steps

* [Storage Configuration](https://docs.qpoint.io/getting-started/qtap/configuration/storage-configuration) — Compare OTel vs S3 object storage options
* [Traffic Processing with Plugins](https://docs.qpoint.io/getting-started/qtap/configuration/traffic-processing-with-plugins) — Filter and transform captured traffic
* [OTel Object Store Release Notes](https://docs.qpoint.io/release-notes/otel-object-store) — Feature details
* [Sample Configuration](https://github.com/qpoint-io/qtap/blob/main/examples/sample-otel-objectstore-clickstack.yaml) — Reference config on GitHub
