Skip to content

Appwrite

Deploy Appwrite on Kubernetes — a self-hosted Backend-as-a-Service (BaaS) platform providing authentication, databases, storage, functions, messaging, and a real-time API. Ships as a multi-workload chart (~20 Kubernetes Deployments) with bundled MariaDB and Redis.

openSslKeyV1 is the master encryption key — losing it makes encrypted data unrecoverable

appwrite.openSslKeyV1 is a 64-character hex key used to encrypt OAuth provider secrets, API keys, and sensitive credentials stored in the database. If this key changes or is lost, all previously encrypted values become permanently unreadable. Always store it in a Kubernetes Secret via appwrite.existingSecret and never rotate it in production.

Key Features

  • Full Appwrite stack — API, Console v7.5.7, Realtime WebSocket, 12 workers, schedulers, maintenance
  • ~20 Kubernetes workloads — each component runs independently and scales separately
  • MariaDB + Redis — bundled subcharts or external connections
  • Shared PVCs — uploads, cache, certificates, functions, builds, and sites shared across pods
  • Root DB access required — Appwrite needs MariaDB root credentials for schema migrations
  • Ingress routing — Console at /, API at /v1, Realtime WebSocket at /v1/realtime
  • mysqldump backup — scheduled CronJob to S3
Functions execution requires openruntimes-executor

The workers.functions and schedulers.functions workloads are deployed, but serverless function execution requires a separate openruntimes-executor service that is not included in this chart. The functions worker will start but function invocations will fail until the executor is available.

Installation

HTTPS repository:

helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install appwrite helmforge/appwrite -f values.yaml

OCI registry:

helm install appwrite oci://ghcr.io/helmforgedev/helm/appwrite -f values.yaml

Deployment Examples

# values.yaml — Appwrite with bundled MariaDB and Redis
appwrite:
  domain: appwrite.example.com
  # Generate: openssl rand -hex 32
  openSslKeyV1: 'your-64-char-hex-key-here'

mariadb:
  enabled: true
  auth:
    password: 'strong-db-password'
    rootPassword: 'strong-root-password'
  standalone:
    persistence:
      enabled: true
      size: 20Gi

redis:
  enabled: true
  auth:
    enabled: true
    password: 'strong-redis-password'

persistence:
  enabled: true
  uploads:
    size: 20Gi
  functions:
    size: 10Gi
  builds:
    size: 10Gi

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: appwrite.example.com
      paths:
        - path: /
          pathType: Prefix
# values.yaml — Appwrite with external MariaDB and Redis
# IMPORTANT: External MariaDB needs root credentials for Appwrite schema migrations
appwrite:
  domain: appwrite.example.com
  existingSecret: appwrite-master-secrets # contains openssl key + JWT secret
  existingSecretOpenSslKey: appwrite-openssl-key
  existingSecretJwtKey: appwrite-jwt-secret

mariadb:
  enabled: false

database:
  mode: external
  external:
    host: mariadb.database.svc.cluster.local
    port: 3306
    name: appwrite
    rootUser: root
    existingSecret: appwrite-mariadb-root # needs ROOT password for migrations
    existingSecretPasswordKey: mariadb-root-password

redis:
  enabled: false

cache:
  mode: external
  external:
    host: redis.cache.svc.cluster.local
    port: 6379
    existingSecret: appwrite-redis-credentials
    existingSecretPasswordKey: redis-password

persistence:
  enabled: true
  uploads:
    size: 20Gi

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: appwrite.example.com
      paths:
        - path: /
          pathType: Prefix
# values.yaml — Production Appwrite with SMTP, HTTPS, and backup
appwrite:
  domain: appwrite.example.com
  existingSecret: appwrite-master-secrets
  smtp:
    host: smtp.mailgun.org
    port: '587'
    secure: tls
    username: [email protected]
    existingSecret: appwrite-smtp-credentials
    existingSecretPasswordKey: smtp-password

mariadb:
  enabled: true
  auth:
    password: 'strong-db-password'
    rootPassword: 'strong-root-password'
  standalone:
    persistence:
      enabled: true
      size: 50Gi

redis:
  enabled: true
  auth:
    enabled: true
    password: 'strong-redis-password'
  standalone:
    persistence:
      enabled: true
      size: 4Gi

persistence:
  enabled: true
  uploads:
    size: 50Gi
  functions:
    size: 20Gi
  builds:
    size: 20Gi
  sites:
    size: 20Gi

backup:
  enabled: true
  schedule: '0 3 * * *'
  s3:
    endpoint: https://s3.amazonaws.com
    bucket: appwrite-backups
    existingSecret: appwrite-s3-backup-credentials

ingress:
  enabled: true
  ingressClassName: traefik
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: appwrite.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: appwrite-tls
      hosts:
        - appwrite.example.com

Configuration Reference

Core

Parameter Type Default Description
nameOverride string "" Override the chart name.
fullnameOverride string "" Override the full release name.
commonLabels object {} Extra labels added to all resources.

Images

Parameter Type Default Description
image.repository string docker.io/appwrite/appwrite Appwrite server image.
image.tag string "1.8.1" Appwrite image tag.
console.image.repository string docker.io/appwrite/console Console image.
console.image.tag string "7.5.7" Console image tag.

Appwrite Configuration

Parameter Type Default Description
appwrite.domain string "" Public domain. Auto-detected from Ingress if empty.
appwrite.openSslKeyV1 string "" 64-char hex encryption key. Auto-generated if empty. Never rotate.
appwrite.existingSecret string "" Existing secret with the OpenSSL key and JWT secret.
appwrite.existingSecretOpenSslKey string appwrite-openssl-key Key for the OpenSSL encryption key in the existing secret.
appwrite.existingSecretJwtKey string appwrite-jwt-secret Key for the JWT secret in the existing secret.
appwrite.locale string en Appwrite locale (ISO 639-1).
appwrite.usageStats string enabled Usage statistics collection.
appwrite.graphql string enabled GraphQL API.
appwrite.storage.limit integer 30000000 Maximum file upload size in bytes (default 30 MB).
appwrite.functions.timeout integer 900 Maximum function execution timeout in seconds.
appwrite.extraEnv array [] Extra environment variables applied to all Appwrite pods.

SMTP

Parameter Type Default Description
appwrite.smtp.host string "" SMTP server hostname.
appwrite.smtp.port string "" SMTP server port.
appwrite.smtp.secure string "" SMTP security mode (tls, ssl, or empty).
appwrite.smtp.username string "" SMTP username.
appwrite.smtp.existingSecret string "" Existing secret with SMTP password.
appwrite.smtp.existingSecretPasswordKey string smtp-password Key for the SMTP password.

Services

Each service can be scaled independently:

Component Parameter Default Description
API api.replicaCount 1 API server replicas.
Realtime realtime.replicaCount 1 Realtime WebSocket server replicas.

Workers

12 workers, each enabled by default at replicaCount: 1:

Worker Key Description
audits workers.audits Audit log processing.
webhooks workers.webhooks Outbound webhook delivery.
deletes workers.deletes Soft-delete cleanup.
databases workers.databases Database event processing.
builds workers.builds Function build jobs.
certificates workers.certificates SSL certificate management.
functions workers.functions Function invocation worker.
mails workers.mails Email delivery.
messaging workers.messaging SMS/push notification delivery.
migrations workers.migrations Data migration worker.
statsResources workers.statsResources Resource usage statistics.
statsUsage workers.statsUsage API usage statistics.

Each worker accepts enabled, replicaCount, and resources fields.

Database

External MariaDB requires root credentials for schema migrations

Appwrite runs its own schema migrations on startup using MariaDB root access. Unlike typical applications, providing only an app-level user is not sufficient. Supply the root password via database.external.existingSecret.

Parameter Type Default Description
database.mode string auto Database mode: auto or external.
database.external.host string "" External MariaDB hostname.
database.external.rootUser string root Root username for schema migrations.
database.external.existingSecret string "" Existing secret with root password.
database.external.existingSecretPasswordKey string mariadb-root-password Key for the root password in the existing secret.

Persistence

All PVCs are shared across workers and the API. If api.replicaCount > 1, the storage class must support ReadWriteMany.

Parameter Type Default Description
persistence.enabled boolean true Create shared PVCs for all Appwrite data.
persistence.storageClass string "" StorageClass. Use RWX class for multi-replica setups.
persistence.accessModes array [ReadWriteOnce] PVC access modes.
persistence.uploads.size string 10Gi Uploads storage.
persistence.cache.size string 2Gi Cache storage.
persistence.certificates.size string 1Gi SSL certificate storage.
persistence.functions.size string 5Gi Function code storage.
persistence.builds.size string 5Gi Function build storage.
persistence.sites.size string 5Gi Sites/hosting storage.

Backup

Parameter Type Default Description
backup.enabled boolean false Enable scheduled mysqldump S3 backup.
backup.schedule string "0 3 * * *" Cron schedule.
backup.s3.endpoint string "" S3-compatible endpoint URL.
backup.s3.bucket string "" Target bucket name.
backup.s3.existingSecret string "" Existing secret with S3 credentials.
backup.database.mysqldumpArgs string --single-transaction --routines --triggers Extra mysqldump arguments.

Ingress

Parameter Type Default Description
ingress.enabled boolean false Enable an Ingress resource.
ingress.ingressClassName string traefik Ingress class name.
ingress.annotations object {} Annotations for the Ingress.
ingress.hosts array Host and path rules. Console: /, API: /v1.
ingress.tls array [] TLS configuration.

More Information