Skip to content
New storyWe built Skald to count visitors. It caught an AI-key thief.
SkaldEvery visit, truly told.

Self-host · Kubernetes

Self-hosted analytics on Kubernetes, with one replica

Self-hosted analytics on Kubernetes is one Skald pod with a persistent volume claim, behind the Ingress you already run. The repository's example manifest has the volume, the Deployment and the Service.

Self-hosted analytics on Kubernetes means running Skald's Docker image as a Deployment with one replica and a ReadWriteOnce volume at /var/lib/skald, behind your own Ingress controller and certificate manager. One of the ways to self-host Skald free.

30-day free trial · no card · we set it up within one working day · free to self-host

kubectl -n skald get all · sampleone replica
  1. pvc skald-data · 5Gi · ReadWriteOncehistory
  2. deployment skald · 1/1 · Recreateone copy
  3. pod runAsUser 10001 · fsGroup 10001security
  4. readiness GET /traffic-auth/loginprobe
  5. service skald · 80 → 8080inside
  6. ingress https://stats.example.comyours

A sample summary of what the example manifest makes, plus the Ingress you add.

[01] deploy

Deploy Skald on Kubernetes with three commands

Edit deploy/kubernetes.yaml first: the SKALD_* values and the trusted proxy range for your cluster. Then make a namespace, apply the file and make the first owner.

  • Run them from the root of your copy of the repository, so deploy/kubernetes.yaml is found.
  • The last line prints a link that sets the owner's password. Open it once the Ingress below answers over HTTPS.
your terminal · edit the name and email first
kubectl create namespace skald
kubectl -n skald apply -f deploy/kubernetes.yaml
kubectl -n skald exec deploy/skald -- skald accounts init --org "Example Co" --owner-email owner@example.com

Wait for the pod to be ready before the last line: kubectl -n skald get pods.

[02] the manifest

What the Kubernetes example makes

A minimal example: one volume claim, one Deployment, one Service. No Ingress, no certificates: those belong to your cluster.

The Recreate strategy stops the old pod before the new one starts, so two pods never write the same files. An upgrade has a short stop; Skald is built for exactly one copy.

From deploy/kubernetes.yaml
PartWhat it is
Volume claimskald-data, 5Gi, ReadWriteOnce
Deploymentreplicas: 1, strategy Recreate
SecurityrunAsUser, runAsGroup, fsGroup: 10001
ReadinessGET /traffic-auth/login on 8080
Livenessentrypoint.py health inside the pod
Resourcesrequests 100m CPU and 256Mi; limit 1Gi of memory
Serviceskald, port 80 to 8080
Receiving logsSKALD_INGEST=true, SKALD_LOG_DIR=/var/lib/skald/ingest/example.com

[03] ingress

Add an Ingress and trust the controller

Add an Ingress for stats.example.com to the skald Service, with your controller and certificate manager. Sign-in needs HTTPS: the session cookie is Secure.

The controller opens every connection to Skald. Set SKALD_TRUSTED_PROXIES to its pod network, and Skald takes the visitor's address from X-Forwarded-For only on those connections. The example has 10.0.0.0/8. Skald refuses 0.0.0.0/0.

your terminal · prints your cluster's pod ranges
$ kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}'
  • With a cloud load balancer in front of the controller, set the controller's Service to externalTrafficPolicy: Local, or turn on its PROXY protocol. Otherwise the controller sees only node addresses.
  • Check: Internal addresses > Add my current address must show your own public address. Remove the entry after.

[04] your site's log

Send your site's visits to Skald on Kubernetes

When your site does not run in the same cluster with its log on Skald's volume, its requests arrive by HTTPS. SKALD_INGEST=true and SKALD_LOG_DIR turn the receiving end on. Then pick where your site runs.

In the dashboard, Settings > Connections > Send this site's visits to Skald fills in the send address and a sending token for you, and ends with Test connection.

tap one

One command on the web server

On the site's nginx or Apache server, with or without Docker, one command finds the access log and sends its new lines to this Skald. Skald makes the sending token for you.

curl -fsSL https://<your Skald>/traffic-kit/<code> | sudo bash

A template: your Skald shows the real line. Its link works once, for 24 hours.

[05] keeping it

Backups and upgrades on Kubernetes

The volume claim holds everything Skald keeps. Keep a copy of it off the cluster too.

  1. Skald's own backups

    A nightly and a weekly copy of the history, each restored into a scratch file and checked before it counts. kubectl -n skald exec deploy/skald -- skald backup makes one now.

  2. Volume snapshots

    Skald's copies live on the same volume. Take volume snapshots with your storage class's own tools as well.

  3. Upgrades

    Take a backup, then change the image tag in the Deployment and apply. The databases are brought up to date at start. Pin :2 to get every 2.x release and never a breaking one.

What it does not do on Kubernetes

  • It does not scale out: never raise replicas above 1, and never add a HorizontalPodAutoscaler.
  • It does not come with an Ingress, certificates or a backup of the volume: those are your cluster's.
  • It has no log of your website in the cluster unless one is sent. A site with no server or CDN log (the script tag alone) shows no AI crawlers and no bots.
  • It sees node addresses, not visitors', behind a cloud load balancer until the controller keeps the client's address.

questions

Self-hosted analytics on Kubernetes FAQ

Straight answers, including what Skald does not do.

Can I run more than one Skald replica on Kubernetes?

No. Skald keeps its history in SQLite on one ReadWriteOnce volume. The example sets replicas to 1 and the Recreate strategy, so the old pod stops before the new one starts and two pods never write the same files. Never raise replicas above 1.

Why does the Skald pod run as user 10001 on Kubernetes?

The image runs as user 10001. The example's security context sets runAsUser, runAsGroup and fsGroup to 10001, so the volume is writable by that user and the container changes nothing at start.

What should SKALD_TRUSTED_PROXIES be on Kubernetes?

The pod range of your Ingress controller, so Skald takes the visitor's address from X-Forwarded-For only on connections from the controller. The example has 10.0.0.0/8; your cluster's own range is shown by kubectl get nodes with the podCIDR field. Never 0.0.0.0/0: Skald refuses it.

Why does Skald show node addresses behind a cloud load balancer?

Because the controller itself sees only node addresses. Set the controller's Service to externalTrafficPolicy: Local, or turn on its PROXY protocol, so the visitor's own address reaches the controller.

Does the Skald example include an Ingress or certificates?

No. It has a 5 GiB volume claim, a Deployment and a Service on port 80. Add an Ingress with the controller and certificate manager your cluster already uses. Sign-in needs HTTPS, because Skald's session cookie is Secure.

$ tail -f access.log | skald

See what AI does with your site. Free for 30 days.

No card. We set up hosted Skald for you within one working day, or you self-host it free. Every line of your log, sorted and added up.

Start free trial Live demo