Skip to content

Kubernetes deployment

Deploy FluxSend on a Kubernetes cluster.


Prerequisites

  • A Kubernetes cluster (v1.24+)
  • Ingress controller (Nginx, Traefik, or similar)
  • PostgreSQL instance (can be self-hosted via operator or managed like RDS, Cloud SQL)

Helm chart

A community-maintained Helm chart is available at github.com/tscrond/fluxsend-charts.

helm repo add fluxsend https://tscrond.github.io/fluxsend-charts
helm install fluxsend fluxsend/fluxsend-backend \
  --set postgresql.enabled=true \
  --set secrets.storage.type=s3

Default values

images:
  backend: bobaklabs/fluxsend-backend:latest
  frontend: bobaklabs/fluxsend-frontend:latest
  docs: bobaklabs/fluxsend-docs:latest

namespace: "default"

appName: "fluxsend"
replicas: 1
mailFrom: "noreply@fluxsend.com"
labels: {}
# here specify:
# podDisruptionBudget:
#   minAvailable: <your_number>
# or
# podDisruptionBudget:
#   maxUnavailable: <your_number>
podDisruptionBudget:
  maxUnavailable: null
  minAvailable: null

cloudFront:
  enabled: false
  domain: "changeme"
  keyPairId: "changeme"
  secretName: "changeme"

ingress:
  ingressClassName: haproxy
  annotations: {}
  tls:
    secretName: "changeme"
  hosts:
    - hostname: "changeme.changeme"
      servicePort: "3000"
    - hostname: "docs.changeme.changeme"
      servicePort: "4321"

params:
  frontendEndpoint: "__CHANGE_ME__"
  backendEndpoint: "__CHANGE_ME__"
  fluxsendApiPort: "__CHANGE_ME__"
  logLevel: "development"

secrets:
  storage:
    # s3 or gcs
    type: "s3"
    storageSecretName: "changeme"

  dbSecretName: "changeme"
  smtpSecretName: "changeme"
  oauthSecretName: "changeme"
  sessionEncryptionSecretName: "changeme"

migrate:
  enabled: false
  legacyS3PrefixMigration: false
  storageMappingMigration: false

Secrets reference

The chart expects pre-created Kubernetes Secrets referenced by name. Each secret must contain specific keys:

values.yaml path Secret name field Expected keys Maps to env vars
secrets.oauthSecretName oauthSecretName google_client_id, google_client_secret, github_oauth_client_id, github_oauth_client_secret GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GITHUB_OAUTH_CLIENT_ID, GITHUB_OAUTH_CLIENT_SECRET
secrets.dbSecretName dbSecretName postgres_user, postgres_password, postgres_db, db_host POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB, DB_HOST
secrets.smtpSecretName smtpSecretName smtp_host, smtp_port, smtp_username, smtp_password SMTP_HOST, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD
secrets.sessionEncryptionSecretName sessionEncryptionSecretName token_encryption_key TOKEN_ENCRYPTION_KEY
secrets.storage.storageSecretName storageSecretName gcs_bucket_name, google_application_credentials, google_project_id (GCS) or s3_bucket_name, aws_region, aws_access_key_id, aws_secret_access_key (S3) GCS_BUCKET_NAME, GOOGLE_APPLICATION_CREDENTIALS, ... or S3_BUCKET_NAME, AWS_REGION, ...

Secrets management

Never commit raw secret values to git. Use Sealed Secrets (kubeseal) to encrypt secrets and store them safely in your repository:

# Install the Sealed Secrets controller in your cluster
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/.../controller.yaml

# Create a sealed secret from a local manifest
kubeseal --format=yaml < secret.yaml > sealed-secret.yaml

# Commit sealed-secret.yaml — it is safe to store in git

Alternatively, use external secrets operators (e.g. External Secrets Operator with AWS Secrets Manager, GCP Secret Manager) to pull secrets from your cloud provider.

Resources (manual)

Resource Purpose
Deployment Runs the backend container (port 3000 API, 8091 CLI)
Service Exposes the deployment internally
Ingress Routes external traffic to the service with TLS
ConfigMap / Secret Environment variables and sensitive config
PersistentVolumeClaim Only if running PostgreSQL in-cluster

Environment

Configure the backend via environment variables on the Deployment:

env:
  - name: DB_HOST
    value: "postgres-service.namespace.svc.cluster.local"
  - name: POSTGRES_USER
    valueFrom:
      secretKeyRef:
        name: fluxsend-db
        key: user
  - name: POSTGRES_PASSWORD
    valueFrom:
      secretKeyRef:
        name: fluxsend-db
        key: password
  - name: POSTGRES_DB
    value: fluxsend
  - name: STORAGE_PROVIDER
    value: s3
  # ... additional vars from config reference

For GCS, mount the service account JSON as a volume:

volumes:
  - name: gcs-creds
    secret:
      secretName: fluxsend-gcs
volumeMounts:
  - name: gcs-creds
    mountPath: /config
    readOnly: true

Images

Backend

image: bobaklabs/fluxsend-backend:latest

Frontend

image: bobaklabs/fluxsend-frontend:latest

See the Docker guide for available registries.


Frontend

The frontend is a React SPA served by Nginx. It requires the NGINX_BACKEND_HOST, NGINX_BACKEND_PORT, and NGINX_BACKEND_API_PORT environment variables to proxy API requests to the backend service.

env:
  - name: NGINX_BACKEND_HOST
    value: "fluxsend-backend.svc.cluster.local"
  - name: NGINX_BACKEND_PORT
    value: "3000"
  - name: NGINX_BACKEND_API_PORT
    value: "8091"

In the Helm chart, the frontend is deployed as part of the release alongside the backend.


Database migration

Migrations run automatically on pod startup. Ensure the database is reachable before the pod starts (use initContainers or a startup probe to wait for PostgreSQL).