Self-hosting on Kubernetes
Install the data plane with Helm. The chart is published to the GHCR OCI registry — no
helm repo add needed — and by default it is self-contained: NATS, Redis, ClickHouse, and
Postgres run inside the release as StatefulSets, so a bare cluster is enough to start.
For a one-command install, use origamy deploy — it runs this Helm install
for you and prompts for endpoint exposure.
Prerequisites
Section titled “Prerequisites”kubectlconnected to your cluster- Helm 3.12+ (
helm version) - Outbound TCP 443 from the
origamy-dpnamespace togrpc.origamy.io - Your data plane token from the setup wizard (dashboard → Connections)
Install
Section titled “Install”-
Create the namespace.
Terminal window kubectl create namespace origamy-dp -
Store your token as a Secret.
Never pass the token via
--set— it would land in Helm release history (helm history), readable by anyone with cluster access.Terminal window kubectl create secret generic origamy-byod-token \--namespace origamy-dp \--from-literal=auth-token=dpt_<PASTE_YOUR_TOKEN_HERE> -
Install the chart.
Terminal window helm install odp oci://ghcr.io/qubelylabs/charts/origamy-data-plane \--namespace origamy-dp \--version 0.1.12 \--set controlPlane.url=grpc.origamy.io:443 \--set controlPlane.dataPlaneId=<YOUR_DATA_PLANE_ID> \--set portalAgent.existingSecret=origamy-byod-tokenThe secret’s key defaults to
auth-token; override withportalAgent.existingSecretAuthKeyif you named it differently. -
Verify.
Terminal window kubectl get pods -n origamy-dpkubectl logs -n origamy-dp deploy/odp-portal-agent --tail=30Look for
portal-agent connected to control plane. The dashboard’s Connections page updates automatically.
Bring your own datastores (optional)
Section titled “Bring your own datastores (optional)”Each bundled datastore can be swapped for an external one by disabling it and pointing at yours, e.g. an existing ClickHouse cluster:
kubectl create secret generic origamy-clickhouse \ --namespace origamy-dp \ --from-literal=clickhouse-password=<YOUR_CLICKHOUSE_PASSWORD>
helm upgrade odp oci://ghcr.io/qubelylabs/charts/origamy-data-plane \ --namespace origamy-dp --reuse-values \ --set clickhouse.enabled=false \ --set clickhouse.host=<YOUR_CLICKHOUSE_HOST> \ --set clickhouse.port=9000 \ --set clickhouse.existingSecret=origamy-clickhouseThe same pattern applies to nats, redis, and postgres (<name>.enabled=false plus the
connection settings). Store passwords in Secrets for the same reason as the token.
Expose your event endpoint
Section titled “Expose your event endpoint”Your SDKs send events to the ingestion gateway, a ClusterIP service by default —
reachable only inside the cluster. To receive events you must expose it.
Option A — LoadBalancer:
helm upgrade odp oci://ghcr.io/qubelylabs/charts/origamy-data-plane \ --version 0.1.12 --namespace origamy-dp --reuse-values \ --set ingestGateway.service.type=LoadBalancer \ --set-string 'ingestGateway.service.annotations.service\.beta\.kubernetes\.io/aws-load-balancer-scheme=internet-facing'
# then get the public address:kubectl get svc -n origamy-dp odp-ingestion-gatewaySend events to http://<load-balancer-host>:8081/v1/track.
Option B — Ingress (HTTPS on your domain):
helm upgrade odp oci://ghcr.io/qubelylabs/charts/origamy-data-plane \ --version 0.1.12 --namespace origamy-dp --reuse-values \ --set ingestGateway.ingress.enabled=true \ --set ingestGateway.ingress.host=events.yourcompany.com \ --set ingestGateway.ingress.tls.enabled=true \ --set ingestGateway.ingress.tls.secretName=events-tlsSend events to https://events.yourcompany.com/v1/track.
Test it (works before you expose anything):
kubectl port-forward -n origamy-dp svc/odp-ingestion-gateway 8081:8081curl -u <write-key>: http://localhost:8081/v1/track \ -H 'Content-Type: application/json' -d '{"userId":"test","event":"hello"}'Once your endpoint is public, paste it into your source’s Setup tab in the dashboard so the copy-paste SDK snippets use it.
NetworkPolicy (if your cluster enforces one)
Section titled “NetworkPolicy (if your cluster enforces one)”apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: origamy-portal-agent-egress namespace: origamy-dpspec: podSelector: matchLabels: app.kubernetes.io/component: portal-agent policyTypes: [Egress] egress: - ports: - protocol: TCP port: 443Sizing
Section titled “Sizing”| Tier | Nodes | CPU | RAM | Capacity |
|---|---|---|---|---|
| Starter | 3 | 2 vCPU each | 4 GB each | < 100k events/day |
| Production | 5 | 4 vCPU each | 16 GB each | 100k – 2M events/day |
| High volume | 8+ | 8 vCPU each | 32 GB each | 2M+ events/day |
For high-volume production, run ClickHouse on dedicated nodes — a common shape is 3× (8 vCPU, 32 GB RAM, 500 GB NVMe) — or bring an externally managed cluster (see above).
Token rotation
Section titled “Token rotation”Rotate the token from the Connections page, patch the Secret, and restart portal-agent:
kubectl create secret generic origamy-byod-token \ --namespace origamy-dp \ --from-literal=auth-token=dpt_<NEW_TOKEN> \ --dry-run=client -o yaml | kubectl apply -f -
kubectl rollout restart deployment/odp-portal-agent -n origamy-dpkubectl rollout status deployment/odp-portal-agent -n origamy-dpUpgrades
Section titled “Upgrades”helm upgrade odp oci://ghcr.io/qubelylabs/charts/origamy-data-plane \ --namespace origamy-dp \ --reuse-valuesTroubleshooting
Section titled “Troubleshooting”| Symptom | Fix |
|---|---|
| Pod in CrashLoopBackOff | Check the Secret exists with the right key: kubectl describe secret origamy-byod-token -n origamy-dp. The key must be auth-token (not AUTH_TOKEN). |
dial tcp: i/o timeout to grpc.origamy.io:443 |
A NetworkPolicy is blocking egress — apply the example above, or confirm the egress rule includes TCP 443. |
Token rejected (Unauthenticated in logs) |
The Secret may still hold the old token after a rotation. Patch the Secret and rollout-restart portal-agent. |
| Sources missing on the data plane | Check kubectl logs deploy/odp-config-sync -n origamy-dp and verify controlPlane.url is reachable from inside the cluster. |
| ClickHouse connection refused (external CH) | Verify clickhouse.host and clickhouse.port (native protocol 9000, not HTTP 8123), and that the password Secret matches your cluster. |
