Gigapipe (qryn) on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of Gigapipe (qryn) on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Gigapipe, formerly known as qryn, is an open source polyglot observability backend. One lightweight service ingests logs, metrics, traces and profiles through the APIs your tooling already speaks, including Loki push, Prometheus remote write, Tempo and Zipkin, OpenTelemetry (OTLP) over HTTP, InfluxDB line protocol, Datadog and Elastic bulk formats, and stores everything in ClickHouse. You query it with LogQL, PromQL and TraceQL from the built in explorer or from any Grafana compatible client, with no plugins required, and correlate logs, metrics and traces in one place.
The cloudimg image ships the free and open source, AGPL-3.0 licensed Gigapipe 5.4.4 release, installed from the project's official GitHub release (the statically linked binary, pinned by SHA-256), together with the explorer UI from the matching qryn-view release, on box ClickHouse 26.8 LTS from the official ClickHouse repository, and the OpenTelemetry Collector Contrib 0.160.0 from its official release. Gigapipe and ClickHouse bind to the loopback interface only, and nginx terminates TLS and enforces HTTP basic authentication as the single public listener. The collector ships the VM's own systemd journal and host metrics into Gigapipe, so the explorer already shows live data when you first sign in. Everything unique is minted per VM on first boot: the ClickHouse passwords (the default user is never without one), the basic authentication password, a self signed TLS certificate, and the ClickHouse schema itself. Backed by 24/7 cloudimg support.
Gigapipe and qryn are names of their respective owners. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by Gigapipe, HEPVEST BV, Grafana Labs, ClickHouse Inc. or The Linux Foundation. Loki, Tempo and Grafana are trademarks of Grafana Labs; Prometheus and OpenTelemetry of The Linux Foundation; ClickHouse of ClickHouse Inc.; each is named only to identify a compatible API. The image ships the free and open source AGPL-3.0 licensed software, unmodified; the corresponding source is available at https://github.com/metrico/gigapipe and https://github.com/metrico/qryn-view.

What is included:
- Gigapipe 5.4.4 — the official release binary, pinned by SHA-256, run unmodified as an unprivileged service account on loopback port 3100
- The Gigapipe explorer (qryn-view 3.3.2) — the official release bundle, served by nginx on the same origin, for LogQL, PromQL and TraceQL queries
- ClickHouse 26.8 LTS — the storage engine, bound to loopback only, crash reporting and telemetry disabled, memory capped to share the VM
- OpenTelemetry Collector Contrib 0.160.0 — ships the VM's own journal (as OTLP logs) and host metrics (as OTLP metrics) into Gigapipe; opens no network port of its own
- nginx — the single public listener, terminating TLS, enforcing basic authentication on every API and the explorer, with WebSocket support for live tail
- First boot secret generation — ClickHouse administrator and application passwords, the basic authentication password and the TLS certificate, all unique to each VM
- A bundled self test — pushes a log line and a metric through the real APIs and queries both back, proving the whole stack end to end
Prerequisites
- An Azure subscription with permission to create virtual machines
- An SSH key pair for administrative access
- A network security group allowing inbound TCP 22 (SSH) and TCP 443 (HTTPS) from your own address ranges
Standard_B2ms(2 vCPU, 8 GB RAM) or larger; ClickHouse and Gigapipe share the memory, so choose more RAM and a larger or separate data disk as your ingest volume and retention grow
Step 1: Deploy from the Azure Portal
- Open the Azure Marketplace and search for Gigapipe (qryn) on Ubuntu 24.04 LTS by cloudimg.
- Select Create, then choose your subscription, resource group and region.
- Pick a VM size of
Standard_B2msor larger. - Under Administrator account, select SSH public key and supply your public key.
- Under Inbound port rules, allow SSH (22) and HTTPS (443).
- Select Review + create, then Create.
Step 2: Deploy from the Azure CLI
az group create --name gigapipe-rg --location eastus
az vm create \
--resource-group gigapipe-rg \
--name gigapipe-vm \
--image cloudimg:qryn-ubuntu-24-04:default:latest \
--size Standard_B2ms \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
az vm open-port --resource-group gigapipe-rg --name gigapipe-vm --port 443 --priority 1010
Step 3: Connect to your VM
ssh azureuser@<vm-ip>
Step 4: Confirm the services are running
Gigapipe runs as a systemd service on loopback behind nginx, with ClickHouse on box and the OpenTelemetry Collector feeding it. Two one shot units run on boot: qryn-tls mints the per VM TLS certificate before nginx starts, and qryn-firstboot (first boot only) generates the secrets, opens the gate that lets Gigapipe start, and runs the self test.
systemctl is-active clickhouse-server nginx gigapipe otelcol-contrib
Expected output:
active
active
active
active
The one shot units report active (exited) after a successful run, and the first boot unit disables itself afterwards so it can never run twice:
systemctl --no-pager --plain --no-legend list-units 'qryn*' 'gigapipe*'
Expected output:
gigapipe.service loaded active running Gigapipe (qryn) polyglot observability backend (loopback :3100) (cloudimg)
qryn-firstboot.service loaded active exited Gigapipe (qryn) first-boot setup (per-VM secrets, schema, self-test) (cloudimg)
qryn-tls.service loaded active exited Mint the per-VM self-signed TLS certificate for the Gigapipe (qryn) front door (cloudimg)
Gigapipe and ClickHouse listen only on the loopback interface, and nginx is the single public listener on ports 80 (which redirects to HTTPS) and 443. Rather than grepping for the ports you expect, list every socket that is bound to something other than loopback, so anything unexpected has nowhere to hide:
sudo ss -ltn | awk 'NR>1{print $4}' | grep -vE '^(127\.|\[::1\])' | sort -u
Expected output:
0.0.0.0:22
0.0.0.0:443
0.0.0.0:80
[::]:22
[::]:443
[::]:80

The only entries are 22 (SSH) and 80 and 443 (nginx), on both IPv4 and IPv6. Everything else the image runs, Gigapipe on 127.0.0.1:3100 and ClickHouse on 127.0.0.1:8123, 127.0.0.1:9000 and 127.0.0.1:9009, is bound to loopback and is not reachable from off the box, and the collector opens no listening port at all. Because this lists the full set rather than a filtered subset, it is also the check to re run after you install anything else on the VM.
The front door itself answers over HTTPS, and only with the credential. This reads the per instance password from the root only credentials file, then probes the readiness endpoint with and without it, and plain HTTP:
QP=$(sudo awk -F= '/^QRYN_PASSWORD=/{print $2}' /root/qryn-credentials.txt)
curl -sk -o /dev/null -w 'https /ready with credential -> %{http_code}\n' -u "admin:${QP}" https://127.0.0.1/ready
curl -sk -o /dev/null -w 'https /ready without credential -> %{http_code}\n' https://127.0.0.1/ready
curl -s -o /dev/null -w 'http / -> %{http_code}\n' http://127.0.0.1/
Expected output:
https /ready with credential -> 200
https /ready without credential -> 401
http / -> 301
Step 5: Retrieve your per instance credentials
Every VM generates its own secrets on first boot. They are written to a root only file:
sudo cat /root/qryn-credentials.txt
This file contains:
QRYN_USER/QRYN_PASSWORD— the HTTP basic authentication credential for the explorer and every APIQRYN_URL— the HTTPS URL of your instanceCLICKHOUSE_ADMIN_USER/CLICKHOUSE_ADMIN_PASSWORD— the ClickHousedefaultuser, for administering the database from the VMCLICKHOUSE_APP_USER/CLICKHOUSE_APP_PASSWORD— thegigapipeClickHouse user the service connects with, limited to thegigapipedatabaseCLICKHOUSE_DB— the database that holds every log, metric, trace and profile

The same basic authentication credential is enforced twice, by nginx (/etc/nginx/qryn.htpasswd) and by Gigapipe itself (QRYN_LOGIN and QRYN_PASSWORD in /etc/gigapipe/gigapipe.env), and the collector uses it too (/etc/otelcol-contrib/otelcol-contrib.conf). Keep the file safe; the section on rotating the credential below explains how to change it.
Step 6: Understand the security model
Nothing usable is baked into the image. Everything security sensitive is generated uniquely on the first boot of every VM, before Gigapipe is allowed to start:
- the ClickHouse
default(administrator) password, so the database is never without one - the ClickHouse
gigapipeapplication password, for a user that only has rights on thegigapipedatabase - the 24 character basic authentication password for the explorer and every ingest and query API
- a per instance self signed TLS certificate
- the ClickHouse schema itself, created by Gigapipe's first start on your VM, so the database holds only your data
Gigapipe and ClickHouse bind to loopback and the collector opens no port, so nginx on 443 is the only network facing surface, and it asks for the credential on every path except the unauthenticated /healthz liveness probe. You can verify the whole model end to end with the bundled self test. It proves the front door works over TLS, that requests without a credential or with a wrong password are refused both at nginx and on loopback, that the explorer is served, that a log line pushed through the Loki API is found again with LogQL, that a metric pushed through the OTLP API is found again with PromQL, that the VM's own journal and host metrics from the collector are queryable, that ClickHouse refuses a password less default login and accepts the per VM credentials, and that the exposed port set is exactly 22, 80 and 443:
sudo /usr/local/bin/qryn-selftest
Expected output:
OK qryn self-test passed: healthz 200, :80 301, unauthenticated 401 (edge + loopback), wrong password 401, /ready 200 + explorer UI served, Loki push -> LogQL round-trip OK (cloudimg-qryn-selftest-...), OTLP metric -> PromQL round-trip OK (...), collector journald + host metrics queryable, ClickHouse default refuses no-password + per-VM creds OK + schema present (29 tables), exposed ports exactly {22,80,443}, gigapipe/ClickHouse loopback-only, collector listens nowhere, no swap

ClickHouse really does refuse a login without a password, even from the VM itself, and accepts the per instance one:
clickhouse-client -q 'SELECT 1' >/dev/null 2>&1 && echo 'no password -> accepted' || echo 'no password -> refused'
CP=$(sudo awk -F= '/^CLICKHOUSE_ADMIN_PASSWORD=/{print $2}' /root/qryn-credentials.txt)
clickhouse-client --password "${CP}" -q "SELECT concat('per VM password -> ClickHouse ', version())"
Expected output:
no password -> refused
per VM password -> ClickHouse 26.8.2.7
Step 7: Open the explorer
Open your instance in a browser:
https://<vm-ip>/
Because the TLS certificate is self signed and per VM, your browser will warn once. Accept it to continue, or install a CA issued certificate as described below to remove the warning. The browser then asks for the basic authentication credential: sign in as QRYN_USER with QRYN_PASSWORD from your credentials file. On a successful sign in, nginx sets an HttpOnly session cookie for the explorer, so its queries are authenticated for the rest of the browser session without entering the credential again.
You land on the explorer's search view with the Logs data source selected. The data sources point at the same origin you signed in to, so nothing needs configuring: the collector has already been shipping this VM's journal and host metrics since first boot, and the label browser is populated.

Enter a LogQL stream selector and press Show Results. {service_name="journald"} returns the VM's own systemd journal: every line carries the unit, syslog_identifier, level, host_name and service_name labels the collector attached, so {service_name="journald", unit="ssh.service"} shows SSH logins, {service_name="journald", level=~"WARN|ERROR"} shows anything that went wrong, and the query below narrows the journal to the appliance's own service units.

The Labels button opens the label browser, which lists every label the collector attached and their values, so you can build a stream selector by clicking rather than typing.

Switch the data source to Metrics and enter a PromQL expression. The collector scrapes host metrics every 15 seconds, so system_memory_usage_bytes{state="used"}, avg(system_cpu_utilization{state!="idle"}), system_filesystem_usage_bytes{mountpoint="/", state="used"} and rate(system_network_io_bytes_total[5m]) all chart immediately.

The Data Sources settings page (/#/datasources) shows the Logs, Metrics and Traces sources all pointing at the address you signed in on, which is your own instance. Nothing needs to be entered there: the explorer authenticates through the session your browser established when it answered the credential prompt. This page is where you would point the explorer at a second Gigapipe instead, or add request headers.

Step 8: Query from the command line
Every API is available from the VM at https://127.0.0.1/ and from your workstation at https://<vm-ip>/ (the QRYN_URL value from your credentials file), always with the basic authentication credential and, until you install a CA issued certificate, curl -k. The Loki label API lists what the collector has produced so far:
QP=$(sudo awk -F= '/^QRYN_PASSWORD=/{print $2}' /root/qryn-credentials.txt)
curl -sk -u "admin:${QP}" https://127.0.0.1/loki/api/v1/labels | jq -c .data
curl -sk -u "admin:${QP}" https://127.0.0.1/loki/api/v1/label/level/values | jq -c .data
Expected output:
["host_name","level","os_type","service_name","syslog_identifier","unit","job","source"]
["INFO","WARN"]
A LogQL range query returns the VM's own SSH log lines. Gigapipe requires both start and end (nanoseconds) on range queries:
QP=$(sudo awk -F= '/^QRYN_PASSWORD=/{print $2}' /root/qryn-credentials.txt)
curl -sk -u "admin:${QP}" -G https://127.0.0.1/loki/api/v1/query_range \
--data-urlencode 'query={service_name="journald", unit="ssh.service"}' \
--data-urlencode "start=$(( $(date +%s) - 3600 ))000000000" \
--data-urlencode "end=$(( $(date +%s) + 60 ))000000000" \
--data-urlencode 'limit=2' | jq -r '.data.result[].values[][1]'
Expected output:
pam_unix(sshd:session): session opened for user azureuser(uid=1000) by azureuser(uid=0)
Accepted publickey for azureuser from 203.0.113.10 port 49497 ssh2: RSA SHA256:...
A PromQL instant query returns the latest host metric sample. The job label is hostmetrics for everything the collector scrapes:
QP=$(sudo awk -F= '/^QRYN_PASSWORD=/{print $2}' /root/qryn-credentials.txt)
curl -sk -u "admin:${QP}" -G https://127.0.0.1/api/v1/query \
--data-urlencode 'query=system_memory_usage_bytes{state="used"}' \
| jq -c '.data.result[0] | {name: .metric.__name__, job: .metric.job, state: .metric.state, bytes: .value[1]}'
curl -sk -u "admin:${QP}" -G https://127.0.0.1/api/v1/label/__name__/values \
--data-urlencode 'match[]={job="hostmetrics"}' | jq '.data | length'
Expected output:
{"name":"system_memory_usage_bytes","job":"hostmetrics","state":"used","bytes":"1381797888"}
25
Step 9: Push your own data
Anything that speaks Loki, Prometheus remote write, OTLP, InfluxDB line protocol, Datadog or Elastic can send to this instance. The simplest demonstration pushes one log line through the Loki API and reads it back with LogQL:
QP=$(sudo awk -F= '/^QRYN_PASSWORD=/{print $2}' /root/qryn-credentials.txt)
NOW=$(date +%s%N)
curl -sk -o /dev/null -w 'push -> %{http_code}\n' -u "admin:${QP}" -H 'Content-Type: application/json' \
-d "{\"streams\":[{\"stream\":{\"job\":\"guide-example\",\"app\":\"hello\"},\"values\":[[\"${NOW}\",\"hello from the deployment guide\"]]}]}" \
https://127.0.0.1/loki/api/v1/push
sleep 2
curl -sk -u "admin:${QP}" -G https://127.0.0.1/loki/api/v1/query_range \
--data-urlencode 'query={job="guide-example"}' \
--data-urlencode "start=$(( $(date +%s) - 600 ))000000000" \
--data-urlencode "end=$(( $(date +%s) + 60 ))000000000" \
--data-urlencode 'limit=5' | jq -r '.data.result[].values[][1]'
Expected output:
push -> 204
hello from the deployment guide
Metrics work the same way. This pushes a gauge as OTLP JSON to /v1/metrics and queries it back with PromQL; service.name becomes the job label:
QP=$(sudo awk -F= '/^QRYN_PASSWORD=/{print $2}' /root/qryn-credentials.txt)
NOW=$(date +%s%N)
curl -sk -o /dev/null -w 'push -> %{http_code}\n' -u "admin:${QP}" -H 'Content-Type: application/json' \
-d "{\"resourceMetrics\":[{\"resource\":{\"attributes\":[{\"key\":\"service.name\",\"value\":{\"stringValue\":\"guide-example\"}}]},\"scopeMetrics\":[{\"metrics\":[{\"name\":\"guide_example_gauge\",\"gauge\":{\"dataPoints\":[{\"asDouble\":42,\"timeUnixNano\":\"${NOW}\"}]}}]}]}]}" \
https://127.0.0.1/v1/metrics
sleep 2
curl -sk -u "admin:${QP}" -G https://127.0.0.1/api/v1/query --data-urlencode 'query=guide_example_gauge' \
| jq -c '.data.result[0] | {metric: .metric, value: .value[1]}'
Expected output:
push -> 200
{"metric":{"__name__":"guide_example_gauge","job":"guide-example","service_name":"guide-example"},"value":"42"}
The endpoints your agents and applications should use, all under https://<vm-ip> with the basic authentication credential:
| Data | Send to | Compatible with |
|---|---|---|
| Logs | /loki/api/v1/push |
Promtail, Grafana Alloy, Fluent Bit, Vector and any Loki client |
| Logs, metrics, traces, profiles | /v1/logs, /v1/metrics, /v1/traces, /v1development/profiles |
OpenTelemetry Collector and SDKs (OTLP over HTTP, protobuf or JSON) |
| Metrics | /api/v1/prom/remote/write |
Prometheus remote_write, the OpenTelemetry prometheusremotewrite exporter |
| Metrics | /influx/api/v2/write |
Telegraf and InfluxDB line protocol clients |
| Traces | /tempo/api/push and /api/v2/spans |
Tempo and Zipkin clients |
| Logs and metrics | /api/v2/logs, /api/v2/series |
Datadog agent formats |
| Logs | /_bulk |
Elastic bulk clients |
Point an OpenTelemetry Collector at the instance by adding an otlphttp exporter with basic authentication:
extensions:
basicauth/gigapipe:
client_auth:
username: admin
password: <QRYN_PASSWORD>
exporters:
otlphttp/gigapipe:
endpoint: https://<vm-ip>
auth:
authenticator: basicauth/gigapipe
tls:
insecure_skip_verify: true # until you install a CA issued certificate
service:
extensions: [basicauth/gigapipe]
pipelines:
logs: { receivers: [otlp], exporters: [otlphttp/gigapipe] }
metrics: { receivers: [otlp], exporters: [otlphttp/gigapipe] }
traces: { receivers: [otlp], exporters: [otlphttp/gigapipe] }
For Prometheus, add a remote_write block:
remote_write:
- url: https://<vm-ip>/api/v1/prom/remote/write
basic_auth:
username: admin
password: <QRYN_PASSWORD>
tls_config:
insecure_skip_verify: true # until you install a CA issued certificate
The OTLP over gRPC receiver is multiplexed on Gigapipe's loopback port and is not exposed by this image; use OTLP over HTTP through nginx, which every OpenTelemetry exporter supports. If you need gRPC from other hosts, add a location with grpc_pass http://127.0.0.1:3100; to the nginx site.
Step 10: Use Grafana, if you want to
Grafana is not included in this image. If you run Grafana elsewhere, add this instance as a Loki data source (URL https://<vm-ip>), as a Prometheus data source (the same URL) and as a Tempo data source (the same URL), each with Basic auth enabled and the QRYN_USER / QRYN_PASSWORD credential, and Skip TLS verify until you install a CA issued certificate. No plugin is needed: Gigapipe implements the native Loki, Prometheus and Tempo query APIs, so Explore, dashboards, alerting and log to trace correlation work as they would against the originals.
Step 11: Configuration, retention and key paths
Gigapipe reads its configuration from /etc/gigapipe/gigapipe.env, generated on first boot. Any variable from the upstream configuration reference can be added to it; these are the ones that matter most, shown with the secrets redacted:
sudo sed -E 's/^(CLICKHOUSE_AUTH|QRYN_PASSWORD)=.*/\1=********/' /etc/gigapipe/gigapipe.env | grep -vE '^#|^$'
Expected output:
CLICKHOUSE_SERVER=127.0.0.1
CLICKHOUSE_PORT=9000
CLICKHOUSE_DB=gigapipe
CLICKHOUSE_AUTH=********
HOST=127.0.0.1
PORT=3100
QRYN_LOGIN=admin
QRYN_PASSWORD=********
SAMPLES_DAYS=7
LOG_LEVEL=info
SAMPLES_DAYS— retention in days for logs, metrics and traces (7 as shipped; applied as a ClickHouse TTL). Raise it once you have sized the disk.LOG_LEVEL—debug,info,warnorerror.BULK_MAX_AGE_MSandBULK_MAX_SIZE_BYTES— how long and how much Gigapipe batches before flushing to ClickHouse.QRYN_RULER_ENABLED=true— enable the recording rules engine and its/api/v1/rulesendpoints.LOG_DRILLDOWN=true— enable log pattern detection.
After editing, restart the service:
$ sudo systemctl restart gigapipe
ClickHouse holds everything under /var/lib/clickhouse. Its own settings live in /etc/clickhouse-server/config.d/cloudimg.xml (loopback only, telemetry off, memory capped at 60 percent of RAM) and the two users in /etc/clickhouse-server/users.d/cloudimg-users.xml (SHA-256 password hashes, loopback only). You can see how much space each table uses with the administrator credential:
CP=$(sudo awk -F= '/^CLICKHOUSE_ADMIN_PASSWORD=/{print $2}' /root/qryn-credentials.txt)
clickhouse-client --password "${CP}" -q "SELECT count() AS tables FROM system.tables WHERE database='gigapipe'"
clickhouse-client --password "${CP}" -q "SELECT table, formatReadableSize(sum(bytes_on_disk)) AS size, sum(rows) AS rows FROM system.parts WHERE database='gigapipe' AND active GROUP BY table ORDER BY sum(bytes_on_disk) DESC LIMIT 3 FORMAT PrettyCompactNoEscapes"
Expected output:
29
┌─table───────┬─size──────┬─rows─┐
1. │ metrics_15s │ 41.35 KiB │ 1746 │
2. │ samples_v3 │ 40.42 KiB │ 2606 │
3. │ time_series │ 20.75 KiB │ 194 │
└─────────────┴───────────┴──────┘
The collector's pipeline is /etc/otelcol-contrib/config.yaml. To ship more of this VM, add receivers there (a filelog receiver for application log files, for example); to receive telemetry from other hosts, send it straight to Gigapipe's endpoints above rather than through the local collector.
| Path | Purpose |
|---|---|
/etc/gigapipe/gigapipe.env |
Gigapipe configuration: ClickHouse connection, basic authentication credential, retention |
/usr/local/bin/gigapipe |
The Gigapipe 5.4.4 release binary |
/opt/qryn-view/dist |
The explorer UI bundle served by nginx |
/root/qryn-credentials.txt |
Per VM credentials and URL, root only |
/var/lib/clickhouse |
ClickHouse data (every log, metric, trace and profile) |
/etc/clickhouse-server/config.d/cloudimg.xml |
ClickHouse server settings: loopback only, no telemetry, memory cap |
/etc/clickhouse-server/users.d/cloudimg-users.xml |
The default and gigapipe ClickHouse users |
/etc/apt/preferences.d/clickhouse-pin |
Pins ClickHouse to the verified version; edit it to upgrade deliberately |
/etc/otelcol-contrib/config.yaml |
The collector pipeline (journald and host metrics into Gigapipe) |
/etc/otelcol-contrib/otelcol-contrib.conf |
The collector's environment, including its copy of the credential |
/etc/nginx/sites-available/cloudimg-qryn |
The TLS and basic authentication front door |
/etc/nginx/qryn.htpasswd |
The basic authentication user database |
/etc/nginx/conf.d/cloudimg-qryn-session.conf |
The explorer session token map, root only, re minted by qryn-set-password |
/usr/local/sbin/qryn-set-password |
Rotates the basic authentication credential everywhere at once |
/etc/nginx/tls/qryn.crt and .key |
The per VM TLS certificate and key |
/usr/local/bin/qryn-selftest |
End to end appliance self test |
/var/log/cloudimg-firstboot.log |
First boot log |
Confirm the baked versions at any time. The Gigapipe binary is the official release, unchanged since the image was built:
sha256sum /usr/local/bin/gigapipe
dpkg-query -W -f='${Package} ${Version}\n' clickhouse-server otelcol-contrib
Expected output:
39ec6718d17a3153da593f215e91cf69bb3d5ec07d9887ff1e8118b91f154f69 /usr/local/bin/gigapipe
clickhouse-server 26.8.2.7
otelcol-contrib 0.160.0
Step 12: Rotate the credential and replace the certificate
The basic authentication credential is enforced by nginx and by Gigapipe, used by the collector, recorded in the credentials file, and backed by the explorer session token in nginx. One helper updates all of them together and restarts the services (the password must be at least 12 characters and contain no colon, quotes or spaces):
$ sudo qryn-set-password '<new-password>'
Every client, browser or collector then needs the new password; existing explorer sessions are signed out because the session token is re minted with it.
The per VM certificate is self signed. For a real deployment, point a DNS name at the VM, obtain a CA issued certificate for it, install the certificate and key over /etc/nginx/tls/qryn.crt and /etc/nginx/tls/qryn.key, and reload:
$ sudo systemctl reload nginx
The qryn-tls unit only mints a certificate when none exists, so a certificate you install is never overwritten.
Backups
All state lives in ClickHouse under /var/lib/clickhouse and in the configuration files listed above. The simplest consistent backup is an Azure managed disk snapshot of the OS disk (or of the data disk if you move /var/lib/clickhouse onto one). For logical backups, ClickHouse's own BACKUP DATABASE gigapipe TO ... statement works once you configure a backup destination in /etc/clickhouse-server/config.d/, as the ClickHouse documentation describes. Keep a copy of /etc/gigapipe/gigapipe.env, /etc/clickhouse-server/users.d/cloudimg-users.xml and /root/qryn-credentials.txt off the VM.
Security notes
-
Nothing is reachable without a credential. Gigapipe and ClickHouse bind to loopback and the collector opens no port; nginx on 443 is the only network facing surface and it demands basic authentication on every path except
/healthz. Gigapipe enforces the same credential a second time on loopback. The explorer's session cookie is issued only after a successful basic authentication page load, is HttpOnly, Secure and SameSite strict, lasts for the browser session, and is as secret as the password: rotate the password to invalidate it. -
Every secret is per virtual machine. Both ClickHouse passwords, the basic authentication password and the TLS certificate are generated on first boot; the ClickHouse
defaultuser is never without a password, and Gigapipe is prevented from starting until first boot has produced the secrets. -
The image ships empty. The
gigapipedatabase is created for the first time on your VM, so it holds only telemetry produced there. The collector ships this VM's own journal, which will include the source addresses of SSH connection attempts; restrict port 22 to your management network and keep key based authentication. -
Use TLS end to end. Replace the self signed certificate with a CA issued one before sending production telemetry, and drop
insecure_skip_verifyfrom your exporters once you have. -
The base image ships fully patched with unattended security upgrades enabled. Gigapipe and the collector are installed from pinned release artefacts and ClickHouse is pinned by an apt preference, so none of the three is upgraded automatically; take a newer release deliberately, after reading its release notes, by replacing the binary or package and restarting the service.
Support
cloudimg provides 24/7 support with a guaranteed 24 hour response SLA for this image. Gigapipe and its explorer are open source under the GNU Affero General Public License v3 and are shipped unmodified; ClickHouse and the OpenTelemetry Collector are Apache 2.0. cloudimg is not affiliated with Gigapipe, HEPVEST BV, Grafana Labs, ClickHouse Inc. or The Linux Foundation. For questions about the image, its configuration or its security posture, contact cloudimg support.