Skip to content

Dawarich Helm Chart

Private location history with the official Dawarich image, PostGIS and authenticated Redis. Rails, Sidekiq and the public NGINX proxy run together in a single Recreate Pod so local attachments and watched imports have consistent storage ownership and scheduling.

Installation

Create an administrator password Secret through the cluster’s approved secret management workflow, then configure the stable browser-visible origin:

server:
  publicUrl: https://locations.example.com
bootstrap:
  email: [email protected]
  existingSecret: dawarich-administrator
  passwordKey: password
ingress:
  enabled: true
  ingressClassName: nginx
  annotations:
    nginx.ingress.kubernetes.io/proxy-read-timeout: '3600'
    nginx.ingress.kubernetes.io/proxy-body-size: 100m
  hosts:
    - host: locations.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: locations-tls
      hosts: [locations.example.com]
networkPolicy:
  ingressFrom:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: ingress-nginx
helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm upgrade --install dawarich helmforge/dawarich \
  --namespace locations --create-namespace --values production-values.yaml

The initial password requires at least 16 characters and at most 72 UTF-8 bytes. If an existing Secret or explicit password is omitted, the chart generates and retains an initial credential. It does not reset an existing account when the credential changes.

Administrator and registration policy

Initialization applies native schema and data migrations, creates the first user through the native Rails model and its password/API-key callbacks, and only then runs the upstream seeds. This prevents the known demo account from becoming the initial public administrator. No HTTP server runs during model provisioning. An existing unsafe demo credential blocks startup and requires explicit repair.

The public proxy forwards to a Rails listener bound exclusively to loopback. It denies the unconditional native API registration routes, Apple/Google enrollment, the OAuth web namespace and the public signup page. The chart implements a local-account policy; enabling an OAuth environment variable does not remove these guards.

A chart-owned initializer uses the Rails middleware extension point to reject Devise account creation after Rack::MethodOverride has interpreted HTML form methods. This preserves the distinction between registration and authenticated PUT/PATCH/DELETE profile operations. The bootstrap also disables the native cached registration setting. These are explicit chart adaptations, not an upstream universal registration flag.

Native administrator user management and trusted Rails console access remain operator responsibilities. The policy does not attempt to restrict a cluster administrator with Pod exec access.

Data and identity

The application PVC contains native local storage, the shared public directory, imports and an identity fingerprint. Separate bounded emptyDirs provide temporary files, Rails logs and NGINX scratch space. The application runs as UID/GID 1000 with a read-only image filesystem, dropped capabilities and no Kubernetes API token.

The retained identity Secret holds SECRET_KEY_BASE, OTP_ENCRYPTION_PRIMARY_KEY, OTP_ENCRYPTION_DETERMINISTIC_KEY and OTP_ENCRYPTION_KEY_DERIVATION_SALT. An existing user database must match the fingerprint on its PVC. Preserve all four keys when replacing Pods, upgrading or restoring data. Changing them is an explicit native key-rotation operation.

Quiesce both Rails and Sidekiq before coordinating a PostGIS dump with a complete filesystem snapshot or archive. Retain the matching identity and dependency Secrets. PVC retention alone does not provide an off-cluster backup or prove that a backup can be restored.

PostGIS and Redis

The PostgreSQL subchart uses the official PostGIS 18-3.6 image, pinned by digest and verified with PostgreSQL 18.6, and installs postgis and pgcrypto in the application database. The verified bundled image targets amd64; the database Pod has a matching architecture selector. An ARM application deployment requires a separately operated, compatible PostGIS database.

Disable postgresql.enabled and configure database.* for external PostGIS. The application role needs migration privileges and must own its application objects; the DBA installs the required extensions first. External TLS uses libpq verify-full and requires an explicit CA Secret.

Disable redis.enabled and configure cache.* independently for external Redis. Cache and job queues require distinct logical databases. Redis Cluster is not a drop-in replacement. Credentials are URL-encoded, including reserved characters and IPv6 host formatting. Custom Redis CA trust augments the image’s system bundle for Ruby/OpenSSL clients; it does not disable certificate or hostname verification. That additional trust is process-wide. Rotate trust and credentials through a controlled restart.

Bundled Redis enables authentication, persistence and noeviction. Its NetworkPolicy accepts only this release’s application Pods and denies egress. External connections need explicit networkPolicy.extraEgress rules for their destination addresses and ports. Reverse-geocoding services are not configured by default.

Exposure and health

Use Ingress or canonical gatewayAPI.httpRoutes[] with explicit parent references. Controllers must support the selected HTTPS origin, upload limits and WebSocket upgrades. The internal proxy streams responses without buffering large exports into its temporary volume. proxy.bodySize bounds incoming requests.

Startup and liveness use native HTTP health. Readiness additionally executes a fresh PostGIS query and authenticated Redis PING. Dependency outages remove readiness without making database availability a web liveness restart condition. Actual queued import completion is validated separately from HTTP health.

Worker readiness checks its native Sidekiq heartbeat and rejects stale or quiet processes. runtime.threads sets the native Rails thread/database pool limit and must cover worker.concurrency. The default single Pod deliberately keeps jobs and local files together; this topology does not provide horizontal scaling or zero-downtime maintenance.

Native monitoring and object storage

Optional authenticated web and Sidekiq exporters expose two private targets. The ServiceMonitor reads credentials from a retained or existing Secret; a PrometheusRule detects unavailable targets. Restrict metrics.ingressFrom to the monitoring namespace. Public /metrics remains inaccessible.

Native S3 storage supports existing credential Secrets, HTTPS endpoints and verified custom CA trust. It retains the application PVC for shared files and identity. S3 primary storage is independent of backup retention and recovery.

Operational guides

Validation status

Isolated behavioral scenarios have passed native administrator login, closed registration, browser profile forms, queued GPX imports, two-factor enrollment, TOTP and recovery-code replay rejection, verified external PostGIS/Redis TLS, authenticated Prometheus scraping, S3 storage and Pod replacement. Acceptance checks original attachment bytes and retained identity keys as well as HTTP health.

Coordinated recovery into a fresh PostGIS database and PVC passed, including a custom spatial reference, original attachment bytes, exact coordinates and native 2FA. Production acceptance also verifies tokenless dependency Pods and withdrawn readiness for a quiet worker.

The complete make validate-chart CHART=dawarich gate passed on 2026-09-11: 23 validation layers, 36 Helm unit tests and 13 isolated k3d scenarios, including all CI profiles. It covers real CRD schemas, ESO, dual-stack Services, Ingress, Gateway API, browser interaction, private Prometheus scraping, external TLS, coordinated recovery and original S3 object bytes. Application and dependency Pods had no unexpected restarts or crash terminations in the accepted scenarios.

Security Scan: dawarich

Framework Score
Overall 98.53%
MITRE 98.32%
NSA 97.57%
SOC2 94.29%

Kubescape 4.0.13, default rendered manifests, 2026-09-11. C-0012 flags the literal ALLOW_EMAIL_PASSWORD_REGISTRATION=false policy setting and TLS admission code that reads credential environment variables; neither contains a credential value. No controls were suppressed.

C-0034 identifies a real default limitation in the released Redis subchart: its Pod does not explicitly disable service-account token mounting. The production example configures Redis to reuse the chart-created tokenless ServiceAccount. Rails, Sidekiq and PostgreSQL already disable token mounting. The scan covers manifests; it does not replace image vulnerability management or application review.

Sources

identity details

The chart creates its initial administrator through Dawarich’s native Rails model before running upstream seeds. Password hashing, API-key generation and user callbacks remain native. No HTTP listener runs in that init container. An existing user database is admitted only with its retained identity fingerprint and an active administrator; initialization never silently resets an existing account.

Supply bootstrap.existingSecret with the key named by bootstrap.passwordKey, or let Helm generate a retained password. Use at least 16 characters and no more than 72 UTF-8 bytes, matching the native password hashing boundary. Store the Secret through your normal secret-management workflow and change the initial email before the first installation. Later changes to bootstrap values do not rename users or rotate their passwords.

Registration policy

Rails binds only to loopback on port 3010. The public NGINX listener denies native API registration and Apple/Google enrollment, the signup page and web OAuth routes. A documented Rails middleware initializer rejects Devise account creation after Rack::MethodOverride, so authenticated profile update and deletion retain their native HTTP methods. Native registration is also disabled in the cached setting.

This is a local-account deployment. The upstream environment flag alone does not close every registration route, and a readiness probe is not an enrollment barrier. Create additional accounts through trusted native administrator operations. Do not add a Service or ingress rule for the private Rails listener.

Two-factor authentication

Native TOTP setup is available because the chart supplies all three OTP encryption keys alongside SECRET_KEY_BASE. Users enroll through Dawarich and retain their recovery codes securely. Password authentication for an enrolled user returns a challenge rather than an API key; the challenge is completed with TOTP or a recovery code. These are native Dawarich mechanisms, not a chart-managed authenticator.

The retained identity Secret contains:

  • SECRET_KEY_BASE
  • OTP_ENCRYPTION_PRIMARY_KEY
  • OTP_ENCRYPTION_DETERMINISTIC_KEY
  • OTP_ENCRYPTION_KEY_DERIVATION_SALT

An existing user database must match the fingerprint on the application PVC before migrations start. Back up the matching Secret, database and PVC together. Key rotation requires a reviewed native migration; replacing the Secret with unrelated random values is not a password reset and will fail admission.

Trusted administration

Kubernetes exec, Secret access and namespace policy administration are trusted operator capabilities. The chart creates no Role or RoleBinding for the application and disables its projected API token. Use least-privilege RBAC for human operators.

For a reviewed native Rails maintenance script already placed in the Pod, the runtime wrapper initializes the same connection environment as the application:

kubectl exec -n locations deployment/dawarich-dawarich -c dawarich -- \
  sh -ec 'unset BUNDLE_PATH BUNDLE_BIN; exec bundle exec ruby /helmforge/entrypoint.rb runner /tmp/reviewed-maintenance.rb'

Use the actual Deployment name from helm status. Do not print API keys, passwords, OTP seeds or backup codes into operational logs.

dependencies details

Both dependencies are required. Select each independently: enable the HelmForge subchart or disable it and configure the corresponding external connection. Conflicting bundled and external connection settings fail Helm rendering.

Bundled PostGIS

HelmForge PostgreSQL 2.0.5 runs the official PostGIS image, pinned by manifest digest. The selected 18-3.6 image contains PostgreSQL 18.6 and targets amd64. The database Pod is scheduled accordingly. An ARM-only cluster needs external PostGIS; the chart does not silently substitute an unofficial ARM database image.

The DBA init script installs postgis and pgcrypto in the application database. The application role owns application objects and runs migrations without being a superuser. The image is read-only, with bounded temporary and socket volumes. The subchart sets PGDATA explicitly inside its persistent data mount.

Bundled connections use authenticated plaintext inside the configured namespace network boundary. Bundled TLS overrides are rejected; use the external contract for verified database TLS.

External PostGIS

Disable postgresql.enabled and configure database.host, port, name, username, passwordSecret and passwordKey. Install both extensions as DBA before installing the application. The application role needs privileges to create and migrate its own objects; avoid granting superuser privileges to make an extension error disappear.

External TLS defaults to enabled and uses libpq verify-full. An explicit CA Secret is required through database.tls.caSecret and caKey. The hostname must match the certificate. No insecure hostname or CA bypass is introduced by the chart.

Redis

The bundled HelmForge Redis runs standalone with authentication, persistence and noeviction. Cache and Sidekiq queues use distinct logical databases, configured by cache.database and cache.queueDatabase. Redis Cluster is outside this contract.

External Redis uses cache.host, port, username, passwordSecret and passwordKey. Credentials are encoded into the native URI without changing their meaning; punctuation in passwords does not become URL syntax. Optional TLS verifies the server certificate and hostname. A custom cache.tls.caSecret augments the image CA bundle for Ruby/OpenSSL processes. This additional trust is process-wide; it is not a per-connection certificate pin.

The bundled Redis dependency does not expose Pod token automount in its released values contract. Its dedicated account has no RBAC grants and its NetworkPolicy denies egress. The production example shares the parent ServiceAccount, whose automount is disabled, so Redis also inherits that setting.

Network access and upgrades

Set networkPolicy.extraEgress for external endpoints. Default egress allows DNS and the bundled database/cache peers, and does not enable general Internet access. Reverse-geocoding providers are unset by default; configure credentials and the provider’s required egress explicitly if using them.

Native schema and data migration commands run sequentially, before web and worker start. Existing imports with pending migration 20260125100000 require operator review: that upstream historical backfill compares an integer source column with string names and rescues the resulting error. The chart blocks that affected upgrade instead of treating a successful CLI exit as proof that historical backfill ran. An empty new installation has no historical imports to backfill.

monitoring details

Enable metrics.enabled to expose native metrics through a private Service. The public application endpoint continues to return 404 for /metrics.

The metrics Service has two authenticated ports:

Endpoint Default port Purpose
metrics 9464 Rails, ActiveRecord and Puma metrics, with native Sidekiq aggregation
worker-metrics 9394 Direct native Sidekiq exporter availability and queue/job metrics

The private NGINX listener exposes only /metrics. Basic authentication is enforced by the native application and worker, using the same Secret. The chart generates and retains a random password unless metrics.auth.existingSecret is configured. Secret key names are configurable; the ServiceMonitor reads those keys directly.

Prometheus Operator

Enable metrics.serviceMonitor.enabled after installing Prometheus Operator CRDs. Configure labels to match the operator’s ServiceMonitor selector and set metrics.ingressFrom to its scraper Pods/namespaces. A second direct worker target is intentional: the aggregate web endpoint can return web-only metrics if the worker exporter fails, so its HTTP 200 response alone does not prove worker health.

metrics.prometheusRule.enabled installs an availability rule for either target. Use additionalRules for workload-specific thresholds. Useful native signals include sidekiq_jobs_success_total, sidekiq_jobs_failed_total, sidekiq_jobs_waiting_count, sidekiq_jobs_retry_count, sidekiq_jobs_dead_count, sidekiq_queue_latency and rails_requests_total. Select endpoint="worker-metrics" when alerting on direct worker metrics to avoid counting the aggregate and direct copies together.

Readiness and operational scope

Web startup/liveness use native HTTP health. Web readiness adds a new PostGIS query and authenticated cache PING. Worker readiness checks the current Pod’s native Sidekiq heartbeat and rejects a stale or quiet process. A real queued GPX import is part of behavioral acceptance; neither a running PID nor a TCP port proves job execution.

CPU, memory and PVC alerts remain responsibilities of cluster monitoring. These application metrics do not implement distributed tracing or a backup system.

storage-recovery details

The application PVC retains local ActiveStorage objects, public assets, watched imports and the identity fingerprint. Rails and Sidekiq share those paths in one Recreate Pod. A writable private TMPDIR is created with mode 0700 for Ruby multipart uploads; making the container image writable is unnecessary.

Native S3

Set storage.driver: s3 with storage.s3.bucket, region and existingSecret. The Secret supplies access and secret keys. endpoint is optional for AWS S3 and must use HTTPS when configured. A private CA can be supplied with caSecret/caKey; the native AWS SDK receives it through AWS_CA_BUNDLE without disabling verification.

The pinned upstream storage configuration explicitly accepts credentials; ambient IAM identity and arbitrary SDK options are not chart promises. In particular, upstream does not expose a force-path-style setting. For compatible endpoints, the SDK chooses addressing from endpoint and bucket rules; the acceptance fixture uses a dotted bucket name over HTTPS and confirms native path addressing. Verify your backend’s naming and addressing requirements before migrating existing objects.

S3 changes where ActiveStorage stores objects. It does not remove the application PVC, create a backup policy or make the co-located workload horizontally scalable. Native signed object URLs are bearer links; protect them as access credentials. Apply bucket access, encryption, versioning and retention controls separately.

Recovery sequence

  1. Stop public writes and quiesce both Rails and Sidekiq. Allow in-flight jobs to finish within the maintenance window; inspect queued/retrying work.
  2. Take a checked PostgreSQL dump and a matching full filesystem archive/snapshot. For S3, preserve the corresponding object versions as well.
  3. Retain all four identity keys, connection Secrets and the application origin. Keep backups encrypted and access-controlled outside the cluster.
  4. Restore into a compatible PostGIS database and a fresh application PVC. Install extensions as DBA, restore application objects under the application role, and preserve custom spatial reference rows with the required DBA privileges.
  5. Point the release at the restored database and PVC. Let the serialized native migration/admission sequence finish before restoring traffic.
  6. Verify the actual database name, native login including 2FA, imported coordinates, completed import state and the original attachment bytes. Review queues and external integrations before resuming writers.

The dedicated ci/restore-values.yaml fixture uses pg_dump/pg_restore, a new database and a new PVC. It retains the source until disposable namespace cleanup. PostGIS extension creation entries are handled by the DBA; custom spatial_ref_sys rows are restored separately with checked errors rather than discarded. Native ActiveStorage downloads verify the original GPX bytes after recovery.

This is a coordinated offline recovery strategy. PVC retention is not an off-cluster backup, and the chart does not claim an application-consistent live filesystem copy, automatic downgrade or transparent recovery of every interrupted Sidekiq job.

production-ingress example

# SPDX-License-Identifier: Apache-2.0
server:
  publicUrl: https://locations.example.com
bootstrap:
  email: [email protected]
  existingSecret: dawarich-administrator
  passwordKey: password
identity:
  existingSecret: dawarich-identity
serviceAccount:
  name: dawarich-runtime
redis:
  serviceAccount:
    create: false
    name: dawarich-runtime
ingress:
  enabled: true
  ingressClassName: nginx
  annotations:
    nginx.ingress.kubernetes.io/proxy-read-timeout: '3600'
    nginx.ingress.kubernetes.io/proxy-body-size: 100m
  hosts:
    - host: locations.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: locations-tls
      hosts: [locations.example.com]
networkPolicy:
  ingressFrom:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: ingress-nginx

external-tls example

# SPDX-License-Identifier: Apache-2.0
postgresql:
  enabled: false
redis:
  enabled: false
database:
  host: postgis.database.svc.cluster.local
  name: dawarich
  username: dawarich
  passwordSecret: dawarich-database
  passwordKey: password
  tls:
    enabled: true
    caSecret: database-ca
cache:
  host: redis.database.svc.cluster.local
  passwordSecret: dawarich-redis
  tls:
    enabled: true
    caSecret: redis-ca
networkPolicy:
  extraEgress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: database
      ports:
        - protocol: TCP
          port: 5432
        - protocol: TCP
          port: 6379

monitoring example

# SPDX-License-Identifier: Apache-2.0
metrics:
  enabled: true
  auth:
    existingSecret: dawarich-monitoring
  ingressFrom:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: monitoring
      podSelector:
        matchLabels:
          app.kubernetes.io/name: prometheus
  serviceMonitor:
    enabled: true
    labels:
      release: kube-prometheus-stack
  prometheusRule:
    enabled: true
    labels:
      release: kube-prometheus-stack

s3 example

# SPDX-License-Identifier: Apache-2.0
storage:
  driver: s3
  s3:
    bucket: locations.example.com
    region: us-east-1
    endpoint: https://s3.storage.example.com
    existingSecret: dawarich-object-storage
    caSecret: object-storage-ca
# Replace this documentation address with the actual endpoint CIDR.
networkPolicy:
  extraEgress:
    - to:
        - ipBlock:
            cidr: 192.0.2.10/32
      ports:
        - protocol: TCP
          port: 443

gateway-api example

# SPDX-License-Identifier: Apache-2.0
server:
  publicUrl: https://locations.example.com
gatewayAPI:
  enabled: true
  httpRoutes:
    - parentRefs:
        - name: public
          namespace: gateway-system
          sectionName: https
      hostnames: [locations.example.com]
networkPolicy:
  ingressFrom:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: gateway-system

Complete values

# SPDX-License-Identifier: Apache-2.0
# -- Override the chart name used in labels.
nameOverride: ''
# -- Override generated resource names.
fullnameOverride: ''
# -- Additional labels on chart resources.
commonLabels: {}
# -- One co-located Rails and Sidekiq Pod; other replica counts are rejected.
replicaCount: 1
# -- Registry authentication Secrets.
imagePullSecrets: []
# -- Additional upstream environment variables; managed identity, connections and policy settings are protected.
extraEnv: []
# -- Application ServiceAccount without RBAC grants.
serviceAccount:
  # -- Create this resource.
  create: true
  # -- Resource name.
  name: ''
  # -- Additional resource annotations.
  annotations: {}
  # -- Configure automount service account token.
  automountServiceAccountToken: false
# -- Public application Service.
service:
  # -- Configure type.
  type: ClusterIP
  # -- Listener or Service port.
  port: 3000
  # -- Additional resource annotations.
  annotations: {}
  # -- Configure ip family policy.
  ipFamilyPolicy: ''
  # -- Configure ip families.
  ipFamilies: []
# -- Ingress exposure for the application listener.
ingress:
  # -- Enable this optional configuration.
  enabled: false
  # -- Configure ingress class name.
  ingressClassName: ''
  # -- Additional resource annotations.
  annotations: {}
  # -- Configure hosts.
  hosts: []
  # -- TLS settings.
  tls: []
# -- Canonical Gateway API HTTPRoute configuration.
gatewayAPI:
  # -- Enable this optional configuration.
  enabled: false
  # -- Configure http routes.
  httpRoutes: []
# -- External Secrets Operator items for externally managed credentials.
externalSecrets:
  # -- Enable this optional configuration.
  enabled: false
  # -- Configure refresh interval.
  refreshInterval: 1h
  # -- Configure items.
  items: []
# -- Native web startup, readiness and liveness checks.
probes:
  # -- Configure startup.
  startup:
    # -- Enable this optional configuration.
    enabled: true
    # -- Configure failure threshold.
    failureThreshold: 60
    # -- Configure period seconds.
    periodSeconds: 5
    # -- Configure timeout seconds.
    timeoutSeconds: 5
  # -- Configure readiness.
  readiness:
    # -- Enable this optional configuration.
    enabled: true
    # -- Configure failure threshold.
    failureThreshold: 3
    # -- Configure period seconds.
    periodSeconds: 10
    # -- Configure timeout seconds.
    timeoutSeconds: 5
  # -- Configure liveness.
  liveness:
    # -- Enable this optional configuration.
    enabled: true
    # -- Configure failure threshold.
    failureThreshold: 3
    # -- Configure period seconds.
    periodSeconds: 20
    # -- Configure timeout seconds.
    timeoutSeconds: 5
# -- Rails CPU and memory requests and limits.
resources:
  # -- Reserved CPU and memory.
  requests:
    # -- CPU quantity.
    cpu: 500m
    # -- Memory quantity.
    memory: 768Mi
  # -- Maximum CPU and memory.
  limits:
    # -- CPU quantity.
    cpu: '2'
    # -- Memory quantity.
    memory: 2Gi
# -- UID/GID and filesystem group for the shared application Pod.
podSecurityContext:
  # -- Configure run as non root.
  runAsNonRoot: true
  # -- Configure run as user.
  runAsUser: 1000
  # -- Configure run as group.
  runAsGroup: 1000
  # -- Configure fs group.
  fsGroup: 1000
  # -- Configure fs group change policy.
  fsGroupChangePolicy: OnRootMismatch
  # -- Configure seccomp profile.
  seccompProfile:
    # -- Configure type.
    type: RuntimeDefault
# -- Restricted container security context for Rails, worker and proxy.
securityContext:
  # -- Configure allow privilege escalation.
  allowPrivilegeEscalation: false
  # -- Configure read only root filesystem.
  readOnlyRootFilesystem: true
  # -- Configure capabilities.
  capabilities:
    # -- Configure drop.
    drop:
      - ALL
# -- Additional Pod labels; chart selectors cannot be overwritten.
podLabels: {}
# -- Additional Pod annotations.
podAnnotations: {}
# -- Application scheduling selectors; bundled PostGIS independently requires amd64.
nodeSelector: {}
# -- Application tolerations.
tolerations: []
# -- Application affinity rules.
affinity: {}
# -- Application topology constraints.
topologySpreadConstraints: []
# -- Existing workload priority class.
priorityClassName: ''
# -- Grace period for Rails and Sidekiq to stop before container termination.
terminationGracePeriodSeconds: 60
# -- Durable local objects, public assets, watched imports and identity fingerprint.
persistence:
  # -- Enable this optional configuration.
  enabled: true
  # -- Configure existing claim.
  existingClaim: ''
  # -- Configure storage class.
  storageClass: ''
  # -- Requested storage capacity.
  size: 20Gi
  # -- Configure access modes.
  accessModes:
    - ReadWriteOnce
  # -- Configure retain.
  retain: true
  # -- Additional resource annotations.
  annotations: {}
# -- Bounded temporary storage and native Rails concurrency.
runtime:
  # -- Capacity of each application temporary emptyDir.
  temporarySize: 1Gi
  # -- Native Rails thread and database-pool limit; must be at least worker.concurrency.
  threads: 5
# -- Configure image.
image:
  # -- Configure repository.
  repository: docker.io/freikin/dawarich
  # -- Configure tag.
  tag: 1.14.4
  # -- Configure pull policy.
  pullPolicy: IfNotPresent
# -- Public origin and application listener.
server:
  # -- Public NGINX port; native Rails stays on loopback 3010.
  port: 3000
  # -- Stable browser-visible HTTP(S) origin; use HTTPS behind production ingress.
  publicUrl: ''
  # -- Configure time zone.
  timeZone: Etc/UTC
# -- Private native administrator provisioning before upstream seeds.
bootstrap:
  # -- Initial administrator email; existing users are never renamed.
  email: [email protected]
  # -- Optional initial password; prefer an existing Secret. Use 16 to 72 characters and no more than 72 UTF-8 bytes.
  password: ''
  # -- Existing initial administrator Secret; otherwise generate and retain one.
  existingSecret: ''
  # -- Secret key containing the initial administrator password.
  passwordKey: admin-password
# -- Application, metrics and bundled Redis network isolation.
networkPolicy:
  # -- Enable this optional configuration.
  enabled: true
  # -- Configure ingress from.
  ingressFrom: []
  # -- Configure egress isolation.
  egressIsolation: true
  # -- Configure dns egress.
  dnsEgress:
    # -- Configure namespace selector.
    - namespaceSelector:
        # -- Configure match labels.
        matchLabels:
          # -- Configure kubernetes.io/metadata.name.
          kubernetes.io/metadata.name: kube-system
      # -- Configure pod selector.
      podSelector:
        # -- Configure match labels.
        matchLabels:
          # -- Configure k8s-app.
          k8s-app: kube-dns
  # -- Configure extra egress.
  extraEgress: []
# -- External PostGIS connection; used when postgresql.enabled=false.
database:
  # -- External PostgreSQL hostname matching its TLS certificate.
  host: ''
  # -- External PostgreSQL port.
  port: 5432
  # -- External application database with postgis and pgcrypto installed.
  name: dawarich
  # -- Application role with migration privileges, without superuser access.
  username: dawarich
  # -- Secret containing the external database password.
  passwordSecret: ''
  # -- Key containing the database password.
  passwordKey: password
  # -- libpq verified TLS; requires an explicit CA Secret.
  tls:
    # -- Use sslmode=verify-full for external PostGIS.
    enabled: true
    # -- Secret containing the trusted PostgreSQL CA bundle.
    caSecret: ''
    # -- Secret key containing the PEM CA bundle.
    caKey: ca.crt
# -- Redis credentials, verified TLS and distinct cache/queue logical databases.
cache:
  # -- External Redis hostname.
  host: ''
  # -- External Redis port.
  port: 6379
  # -- Optional Redis ACL username.
  username: ''
  # -- Secret containing the external Redis password.
  passwordSecret: ''
  # -- Key containing the Redis password.
  passwordKey: redis-password
  # -- Native Rails cache logical database.
  database: 0
  # -- Verified external Redis TLS.
  tls:
    # -- Use rediss with certificate and hostname verification.
    enabled: true
    # -- Optional private CA added to the Ruby/OpenSSL process trust bundle.
    caSecret: ''
    # -- Secret key containing the PEM Redis CA bundle.
    caKey: ca.crt
  # -- Native Sidekiq logical database; must differ from cache.database.
  queueDatabase: 1
# -- HelmForge PostgreSQL with official pinned amd64 PostGIS image and DBA extension initialization.
postgresql:
  # -- Configure initdb.
  initdb:
    # -- Configure scripts.
    scripts:
      # -- Configure 20-dawarich-postgis.sh.
      20-dawarich-postgis.sh: |
        #!/bin/bash
        set -euo pipefail
        export PGPASSWORD="${POSTGRES_PASSWORD}"
        psql -v ON_ERROR_STOP=1 --username "${POSTGRES_USER}" --dbname "${APP_DATABASE}" <<'SQL'
        CREATE EXTENSION IF NOT EXISTS postgis;
        CREATE EXTENSION IF NOT EXISTS pgcrypto;
        SQL
  # -- Configure security context.
  securityContext:
    # -- Configure read only root filesystem.
    readOnlyRootFilesystem: true
  # -- Configure extra volumes.
  extraVolumes:
    # -- Resource name.
    - name: postgres-tmp
      # -- Configure empty dir.
      emptyDir:
        # -- Configure size limit.
        sizeLimit: 1Gi
    # -- Resource name.
    - name: postgres-socket
      # -- Configure empty dir.
      emptyDir:
        # -- Configure medium.
        medium: Memory
        # -- Configure size limit.
        sizeLimit: 16Mi
  # -- Configure extra volume mounts.
  extraVolumeMounts:
    # -- Resource name.
    - name: postgres-tmp
      # -- Configure mount path.
      mountPath: /tmp
    # -- Resource name.
    - name: postgres-socket
      # -- Configure mount path.
      mountPath: /var/run/postgresql
  # -- Configure network policy.
  networkPolicy:
    # -- Enable this optional configuration.
    enabled: true
    # -- Configure egress.
    egress:
      # -- Enable this optional configuration.
      enabled: true
      # -- Configure allow dns.
      allowDNS: true
      # -- Configure allow same namespace postgre sql.
      allowSameNamespacePostgreSQL: false
      # -- Configure allow https.
      allowHTTPS: false
  # -- Enable this optional configuration.
  enabled: true
  # -- Configure architecture.
  architecture: standalone
  # -- Configure auth.
  auth:
    # -- Configure database.
    database: dawarich
    # -- Configure username.
    username: dawarich
    # -- Existing externally managed Secret.
    existingSecret: ''
    # -- Configure existing secret user password key.
    existingSecretUserPasswordKey: user-password
  # -- Configure image.
  image:
    # -- Configure repository.
    repository: postgis/postgis
    # -- Configure tag.
    tag: 18-3.6@sha256:7e00e8c3539fdd43f513b98806c8204714dcd09dea683c259e333d7690317119
  # -- Configure node selector.
  nodeSelector:
    # -- Configure kubernetes.io/arch.
    kubernetes.io/arch: amd64
# -- HelmForge authenticated standalone Redis with persistence and noeviction.
redis:
  # -- Configure service account.
  serviceAccount:
    # -- Create this resource.
    create: true
  # -- Configure security context.
  securityContext:
    # -- Configure read only root filesystem.
    readOnlyRootFilesystem: true
    # -- Configure capabilities.
    capabilities:
      # -- Configure drop.
      drop:
        - ALL
    # -- Configure seccomp profile.
    seccompProfile:
      # -- Configure type.
      type: RuntimeDefault
  # -- Enable this optional configuration.
  enabled: true
  # -- Configure architecture.
  architecture: standalone
  # -- Configure auth.
  auth:
    # -- Enable this optional configuration.
    enabled: true
    # -- Configure password.
    password: ''
    # -- Existing externally managed Secret.
    existingSecret: ''
    # -- Configure existing secret password key.
    existingSecretPasswordKey: redis-password
  # -- Configure config.
  config:
    # -- Configure redis.
    redis: |
      maxmemory-policy noeviction
      appendonly yes
  # -- Configure standalone.
  standalone:
    # -- Configure persistence.
    persistence:
      # -- Enable this optional configuration.
      enabled: true
      # -- Requested storage capacity.
      size: 5Gi
    # -- CPU and memory requests and limits.
    resources:
      # -- Reserved CPU and memory.
      requests:
        # -- CPU quantity.
        cpu: 100m
        # -- Memory quantity.
        memory: 128Mi
      # -- Maximum CPU and memory.
      limits:
        # -- CPU quantity.
        cpu: 500m
        # -- Memory quantity.
        memory: 512Mi
# -- Official unprivileged NGINX for public policy and private metrics.
proxy:
  # -- Configure image.
  image:
    # -- Configure repository.
    repository: docker.io/nginxinc/nginx-unprivileged
    # -- Configure tag.
    tag: 1.30.4-alpine
    # -- Configure pull policy.
    pullPolicy: IfNotPresent
  # -- CPU and memory requests and limits.
  resources:
    # -- Reserved CPU and memory.
    requests:
      # -- CPU quantity.
      cpu: 50m
      # -- Memory quantity.
      memory: 32Mi
    # -- Maximum CPU and memory.
    limits:
      # -- CPU quantity.
      cpu: 500m
      # -- Memory quantity.
      memory: 128Mi
  # -- Maximum incoming request body accepted by NGINX.
  bodySize: 100m
# -- Retained Rails and OTP identity keys.
identity:
  # -- Existing Secret containing all four documented native identity keys.
  existingSecret: ''
# -- Co-located native Sidekiq process.
worker:
  # -- Maximum concurrent jobs; must not exceed runtime.threads.
  concurrency: 3
  # -- Worker CPU and memory budget.
  resources:
    # -- Reserved CPU and memory.
    requests:
      # -- CPU quantity.
      cpu: 250m
      # -- Memory quantity.
      memory: 512Mi
    # -- Maximum CPU and memory.
    limits:
      # -- CPU quantity.
      cpu: '2'
      # -- Memory quantity.
      memory: 2Gi
# -- Authenticated native web and Sidekiq metrics.
metrics:
  # -- Enable both native exporters and their private Service.
  enabled: false
  # -- Private web metrics proxy port; worker uses 9394.
  port: 9464
  # -- NetworkPolicy peers allowed to reach both metrics ports.
  ingressFrom:
    # -- Configure namespace selector.
    - namespaceSelector:
        # -- Configure match labels.
        matchLabels:
          # -- Configure kubernetes.io/metadata.name.
          kubernetes.io/metadata.name: monitoring
  # -- Two-target Prometheus Operator ServiceMonitor.
  serviceMonitor:
    # -- Enable this optional configuration.
    enabled: false
    # -- Additional selector-compatible labels.
    labels: {}
    # -- Configure interval.
    interval: 30s
    # -- Configure scrape timeout.
    scrapeTimeout: 10s
  # -- Target availability rule and optional workload-specific alerts.
  prometheusRule:
    # -- Enable this optional configuration.
    enabled: false
    # -- Additional selector-compatible labels.
    labels: {}
    # -- Configure additional rules.
    additionalRules: []
  # -- Native Basic authentication shared by web, worker and ServiceMonitor.
  auth:
    # -- Existing metrics credentials; otherwise retain a generated password.
    existingSecret: ''
    # -- Username for chart-generated monitoring credentials.
    username: prometheus
    # -- Secret key containing the metrics username.
    usernameKey: username
    # -- Secret key containing the metrics password.
    passwordKey: password
# -- Native ActiveStorage backend; a local application PVC remains required.
storage:
  # -- Native local or s3 object storage.
  driver: local
  # -- Native AWS SDK object-storage configuration.
  s3:
    # -- Existing private S3 bucket.
    bucket: ''
    # -- AWS signing region.
    region: us-east-1
    # -- Optional HTTPS S3-compatible endpoint; native SDK addressing rules apply.
    endpoint: ''
    # -- Secret containing static object-storage credentials.
    existingSecret: ''
    # -- Secret key containing the S3 access key ID.
    accessKeyIdKey: access-key-id
    # -- Secret key containing the S3 secret access key.
    secretAccessKeyKey: secret-access-key
    # -- Optional custom CA bundle scoped to the native AWS client.
    caSecret: ''
    # -- Secret key containing the S3 CA bundle.
    caKey: ca.crt