Skip to content
Fluxer API

Kubernetes

The Helm chart in deploy/helm/fluxer runs the same Fluxer services that rexctl runs on one machine. You install and upgrade it with Helm, because rexctl doesn't manage a Kubernetes install.

RequirementDetails
KubernetesVersion 1.29 or newer
HelmHelm 3 or Helm 4
ResourcesThe pods request about 1 CPU and 4.5 GB of memory, and their limits add up to about 19 GB
StorageA default StorageClass with ReadWriteOnce volumes
Web trafficAn ingress controller and cert-manager, or a Gateway API gateway
Visitor addressesThe ingress controller sees each visitor's address, through externalTrafficPolicy: Local or the PROXY protocol
DNSAn A record for your domain that points to the ingress controller or the load balancer
VoiceTCP port 7881 and UDP port 7882 open to LiveKit

With edge.expose: loadBalancer you need neither an ingress controller nor cert-manager, and Fluxer gets its own certificate.

If the ingress controller doesn't see each visitor's address, every visitor shares one address and hits the same sign-in limits.

The install stops with a message when the cluster is missing something it needs.

Get the chart and write a values file with your domain.

Terminal window
git clone --depth 1 https://github.com/fluxerapp/fluxer.git
printf 'domain: chat.example.com\n' > fluxer-values.yaml

Install it into its own namespace.

Terminal window
helm install fluxer ./fluxer/deploy/helm/fluxer \
--namespace fluxer --create-namespace \
-f fluxer-values.yaml --wait --timeout 15m

Keep fluxer-values.yaml for upgrades. When the install is done, helm test fluxer -n fluxer checks that the instance answers for your domain.

Open your domain in a browser to create your admin account. The setup page asks for the setup token in the fluxer-env Secret.

Terminal window
kubectl -n fluxer get secret fluxer-env -o jsonpath='{.data.FLUXER_SETUP_TOKEN}' | base64 -d

If the Secret has no setup token, the API wrote one to its log when it first started.

Terminal window
kubectl -n fluxer logs deployment/api | grep -i 'setup token'

The chart's values.yaml explains every value. These are the ones most installs change.

ValueWhat it sets
domainThe address people use for your instance
emailThe contact address for Let's Encrypt and web push
edge.exposeingress, gateway, loadBalancer or none for a proxy of your own
livekit.exposehostNetwork (the default, needs a privileged namespace), loadBalancer or nodePort
envFluxer settings as NAME: value, listed on Environment variables
secrets.extraSettings that have a password or a key

To relay calls through a TURN server when people can't connect to LiveKit directly, add it to livekit.extraConfig, as Voice behind a tunnel shows.

Under Argo CD or helm template, set secrets.generate: false and give every key in secrets.values, or put a Secret you manage in secrets.existingSecret.

To use a service you already run, turn off the bundled one and say where yours is.

ServiceValues to set
Postgrespostgres.enabled: false and postgres.external.host, or a URL in secrets.extra.FLUXER_POSTGRES_URL
Valkeyvalkey.enabled: false and valkey.external.url, or a URL with a password in secrets.extra.FLUXER_KV_URL
NATSnats.enabled: false and nats.external.url
Meilisearchmeilisearch.enabled: false and meilisearch.external.url
S3 storageseaweedfs.enabled: false and s3.endpoint
LiveKitlivekit.enabled: false, livekit.external.url and livekit.external.publicUrl

The Postgres database and role, and the S3 buckets in s3.buckets, must exist before you install. Put passwords and keys in secrets.values under the key values.yaml gives for each service.

Point your LiveKit server's webhook at https://<your domain>/api/webhooks/livekit, signed with the key in FLUXER_LIVEKIT_API_KEY.

Give every LiveKit server of an instance its own API key. Fluxer finds the server that sent a webhook by its key. To add more voice servers, create a join token in the admin panel and run rexctl voice join on another machine, or follow Run a voice server with Docker Compose. Joining talks only to your instance's public API, and it works with the Helm chart too.

Joined servers work next to the chart's LiveKit and next to a LiveKit of your own in livekit.external.url. To run with only joined servers and no LiveKit of the chart's, set livekit.enabled: false and livekit.joined: true. Voice stays on, the default region starts with no server in it and calls go to the servers you join. livekit.enabled: false without livekit.external.url or livekit.joined turns voice off.

When your email server or another service the api calls has a certificate from your own CA, mount that CA's PEM file into the api and worker and set NODE_EXTRA_CA_CERTS to its path. This example reads ca.pem from a ConfigMap called smtp-ca.

api:
env:
NODE_EXTRA_CA_CERTS: /etc/fluxer/ca/ca.pem
extraVolumes:
- name: smtp-ca
configMap:
name: smtp-ca
extraVolumeMounts:
- name: smtp-ca
mountPath: /etc/fluxer/ca
readOnly: true
worker:
env:
NODE_EXTRA_CA_CERTS: /etc/fluxer/ca/ca.pem
extraVolumes:
- name: smtp-ca
configMap:
name: smtp-ca
extraVolumeMounts:
- name: smtp-ca
mountPath: /etc/fluxer/ca
readOnly: true

Pull the chart and upgrade with the same values file. A new image.revision restarts every Fluxer pod, which pulls the newest Fluxer images.

Terminal window
git -C fluxer pull
helm upgrade fluxer ./fluxer/deploy/helm/fluxer -n fluxer -f fluxer-values.yaml \
--set-string image.revision=$(date +%s) --wait --timeout 15m

helm rollback goes back to the previous values and images, but it doesn't undo changes to the database.

Back up the Secrets and the database.

Terminal window
kubectl -n fluxer get secret fluxer-env fluxer-unfurl-env -o yaml \
| grep -v -E '^ (resourceVersion|uid|creationTimestamp):' > fluxer-env.yaml
kubectl -n fluxer exec postgres-0 -- sh -c 'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" --format=custom' > fluxer.dump

A restored database only works with the same Secrets. Keep fluxer-env.yaml as safe as the dump.

Uploads are on the volume data-seaweedfs-0. Back it up with a snapshot from your storage provider.

To restore, put the Secrets back before you install, and the new release uses the same secrets.

Terminal window
kubectl create namespace fluxer
kubectl apply -f fluxer-env.yaml
helm install fluxer ./fluxer/deploy/helm/fluxer -n fluxer -f fluxer-values.yaml --wait --timeout 15m

Stop everything except Postgres and restore the database.

Terminal window
kubectl -n fluxer scale deployment,statefulset --replicas=0 \
-l 'app.kubernetes.io/part-of=fluxer,app.kubernetes.io/name notin (postgres)'
kubectl -n fluxer exec -i postgres-0 -- sh -c 'pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" --clean --if-exists' < fluxer.dump

Restore the data-seaweedfs-0 volume from its snapshot with your storage provider. Then start everything again.

Terminal window
helm upgrade fluxer ./fluxer/deploy/helm/fluxer -n fluxer -f fluxer-values.yaml --wait --timeout 15m
Terminal window
helm uninstall fluxer -n fluxer

The Secrets and the volumes stay, and a new install with the same release name and namespace uses them again. To delete everything, delete them too.

Terminal window
kubectl -n fluxer delete secret fluxer-env fluxer-unfurl-env
kubectl -n fluxer delete pvc -l app.kubernetes.io/instance=fluxer
kubectl delete namespace fluxer