Skip to content

Heimdall

Application dashboard for organizing and launching self-hosted services. Heimdall provides a clean, customizable homepage where you can pin any web application as a tile, complete with icons, colors, and live status indicators. All configuration is stored in a SQLite database on a persistent volume — no external database required.

The chart uses Heimdall 2.8.3 and rejects empty image repository or tag values before creating a workload.

Key Features

  • Application tiles — pin any URL as an app tile with custom icons and colors
  • Enhanced apps — native integrations for popular self-hosted apps (stats, health)
  • LinuxServer.io image — PUID/PGID file ownership control for PVC compatibility
  • Persistent storage — SQLite database and all configuration in /config
  • S3 backup — scheduled archive of the full /config directory to S3-compatible storage
  • Ingress support — configurable TLS via cert-manager
  • End-to-end listener configuration — custom application and Service ports remain independent
  • Hardened defaults — restricted capabilities, seccomp, no API token, and an ingress NetworkPolicy

Chart Documentation

Installation

HTTPS repository:

helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install heimdall helmforge/heimdall

OCI registry:

helm install heimdall oci://ghcr.io/helmforgedev/helm/heimdall

Deployment Examples

# values.yaml — Heimdall with Traefik ingress
heimdall:
  containerPort: 8080
  timezone: 'America/Sao_Paulo'
  puid: 1000
  pgid: 1000

persistence:
  enabled: true
  size: 1Gi

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: dashboard.example.com
      paths:
        - path: /
          pathType: Prefix
# values.yaml — Heimdall with daily S3 backup
# Backup covers the full /config directory including SQLite database and all tiles
heimdall:
  timezone: 'America/Sao_Paulo'

persistence:
  enabled: true
  size: 1Gi

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

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: dashboard.example.com
      paths:
        - path: /
          pathType: Prefix
# values.yaml — Production Heimdall with TLS and backup
heimdall:
  timezone: 'America/Sao_Paulo'
  puid: 1000
  pgid: 1000

persistence:
  enabled: true
  size: 1Gi

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

resources:
  requests:
    cpu: 50m
    memory: 128Mi
  limits:
    memory: 256Mi

service:
  port: 80

networkPolicy:
  enabled: true

ingress:
  enabled: true
  ingressClassName: traefik
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: dashboard.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: heimdall-tls
      hosts:
        - dashboard.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.

Image

Parameter Type Default Description
image.repository string docker.io/linuxserver/heimdall Heimdall container image.
image.tag string "2.8.3" Image tag.
image.pullPolicy string IfNotPresent Image pull policy.
imagePullSecrets array [] Pull secrets for private registries.

Heimdall Configuration

Parameter Type Default Description
heimdall.puid integer 1000 User ID used by the container process for file ownership in /config.
heimdall.pgid integer 1000 Group ID used by the container process for file ownership in /config.
heimdall.timezone string UTC Container timezone for display purposes.
heimdall.containerPort integer 80 HTTP port used by the real NGINX listener.
heimdall.extraEnv array [] Extra environment variables for advanced configuration.
PUID/PGID must match the PVC file ownership

The LinuxServer.io image runs as the user and group defined by heimdall.puid and heimdall.pgid. If the PVC is created with a different owner (e.g. root, UID 0), the container will fail to write to /config and the application will not start correctly. The default 1000:1000 works with most dynamic provisioners. If you encounter permission errors in logs, verify the PVC ownership and adjust puid/pgid accordingly.

Persistence

Heimdall stores all configuration, application tiles, and the SQLite database in the /config directory.

Parameter Type Default Description
persistence.enabled boolean true Enable a PVC for /config (SQLite database and all tile config).
persistence.size string 1Gi PVC size.
persistence.storageClass string "" StorageClass for the PVC.
persistence.accessMode string ReadWriteOnce PVC access mode.
persistence.existingClaim string "" Use an existing PVC instead of creating one.
persistence.annotations object {} Annotations for the PVC.

Backup

The S3 backup CronJob archives the full /config directory, which includes the SQLite database, all configured application tiles, custom icons, and settings. This is a complete backup of the Heimdall instance.

Parameter Type Default Description
backup.enabled boolean false Enable scheduled S3 backup CronJob.
backup.schedule string "0 3 * * *" Cron schedule for backups.
backup.suspend boolean false Suspend the CronJob without deleting it.
backup.concurrencyPolicy string Forbid CronJob concurrency policy.
backup.successfulJobsHistoryLimit integer 3 Number of successful Job records to keep.
backup.failedJobsHistoryLimit integer 3 Number of failed Job records to keep.
backup.backoffLimit integer 1 Job retry limit.
backup.archivePrefix string heimdall Prefix for backup archive filenames.
backup.images.archiver string docker.io/library/alpine:3.22 Image used for tar archive.
backup.images.uploader string docker.io/helmforge/mc:1.0.0 Image used for S3 upload.
backup.resources object {} Resources for backup containers.
backup.s3.endpoint string "" S3-compatible endpoint URL.
backup.s3.bucket string "" Target bucket name.
backup.s3.prefix string heimdall Key prefix within the bucket.
backup.s3.createBucketIfNotExists boolean true Create the bucket automatically if it does not exist.
backup.s3.existingSecret string "" Existing secret containing S3 access and secret keys.
backup.s3.existingSecretAccessKeyKey string access-key Key in the existing secret for the S3 access key.
backup.s3.existingSecretSecretKeyKey string secret-key Key in the existing secret for the S3 secret key.
backup.s3.accessKey string "" Inline S3 access key (ignored when existingSecret is set).
backup.s3.secretKey string "" Inline S3 secret key (ignored when existingSecret is set).

Service

Parameter Type Default Description
service.type string ClusterIP Kubernetes service type.
service.port integer 80 Service port exposed to the cluster.
service.annotations object {} Annotations for the Service.

Ingress

ingressClassName must be set explicitly

Unlike most HelmForge charts, ingress.ingressClassName defaults to an empty string. You must set it explicitly to your cluster’s ingress controller (e.g. traefik, nginx) for the Ingress resource to be picked up.

Parameter Type Default Description
ingress.enabled boolean false Enable an Ingress resource.
ingress.ingressClassName string "" Ingress class name. Must be set explicitly.
ingress.annotations object {} Annotations for the Ingress (e.g. cert-manager).
ingress.hosts array [] Ingress host and path rules.
ingress.tls array [] TLS configuration (secret name and hosts).

Probes

Probes use the / root path.

Parameter Type Default Description
startupProbe.enabled boolean true Enable startup probe.
startupProbe.initialDelaySeconds integer 5 Startup probe initial delay.
startupProbe.periodSeconds integer 5 Startup probe period.
startupProbe.timeoutSeconds integer 3 Startup probe timeout.
startupProbe.failureThreshold integer 12 Startup probe failure threshold.
livenessProbe.enabled boolean true Enable liveness probe.
livenessProbe.initialDelaySeconds integer 0 Liveness probe initial delay.
livenessProbe.periodSeconds integer 20 Liveness probe period.
livenessProbe.timeoutSeconds integer 5 Liveness probe timeout.
livenessProbe.failureThreshold integer 3 Liveness probe failure threshold.
readinessProbe.enabled boolean true Enable readiness probe.
readinessProbe.initialDelaySeconds integer 0 Readiness probe initial delay.
readinessProbe.periodSeconds integer 10 Readiness probe period.
readinessProbe.timeoutSeconds integer 5 Readiness probe timeout.
readinessProbe.failureThreshold integer 3 Readiness probe failure threshold.

Resources and Security

The LinuxServer /init process starts as root to prepare /config and apply PUID/PGID. The chart documents that upstream requirement while disabling privilege escalation, minimizing capabilities, applying RuntimeDefault seccomp, and preventing ServiceAccount token automount. The main root filesystem remains writable because s6-overlay writes outside /config during startup.

Parameter Type Default Description
resources object {} CPU and memory requests and limits.
podSecurityContext.seccompProfile.type string RuntimeDefault Pod seccomp profile.
securityContext.allowPrivilegeEscalation boolean false Permit privilege escalation.
securityContext.readOnlyRootFilesystem boolean false Read-only root; disabled for LinuxServer initialization.
securityContext.capabilities.drop array [ALL] Capabilities removed before the required allowlist is added.

Service Account

Parameter Type Default Description
serviceAccount.create boolean false Create a dedicated ServiceAccount.
serviceAccount.name string "" Override the ServiceAccount name.
serviceAccount.annotations object {} Annotations for the ServiceAccount.
serviceAccount.automountServiceAccountToken boolean false Mount a Kubernetes API token in the pod.

Network Policy

The default policy restricts inbound traffic to the named HTTP port. Egress is left unrestricted because Heimdall enhanced tiles contact operator-selected services. Add a separate egress policy when every destination is known.

Parameter Type Default Description
networkPolicy.enabled boolean true Create the server ingress NetworkPolicy.
networkPolicy.extraIngress array [] Additional complete ingress rules.

Scheduling

Parameter Type Default Description
nodeSelector object {} Node selector for scheduling.
tolerations array [] Tolerations for scheduling.
affinity object {} Affinity rules.
topologySpreadConstraints array [] Topology spread constraints.
priorityClassName string "" PriorityClass for the pod.
terminationGracePeriodSeconds integer 30 Termination grace period.
podLabels object {} Extra labels for the pod.
podAnnotations object {} Extra annotations for the pod.

Extra

Parameter Type Default Description
extraVolumes array [] Extra volumes to attach to the pod.
extraVolumeMounts array [] Extra volume mounts for the container.
extraManifests array [] Extra Kubernetes manifests deployed alongside the chart.

Common Issues

All dashboard tiles lost after pod restart without persistence

All configured application tiles, icons, and settings are stored in the SQLite database inside /config. If persistence.enabled is false or the PVC is not correctly bound, the entire dashboard configuration is lost when the pod restarts. Always verify persistence.enabled: true and that the PVC is in Bound state before configuring your dashboard.

Enhanced app integrations require API tokens

Heimdall supports enhanced tiles for apps like Sonarr, Radarr, Pi-hole, and others that display live statistics. These require an API token or key configured in the tile settings within the Heimdall UI. Check the Heimdall supported apps list for available integrations.

Application and Service ports are independent

Set heimdall.containerPort to change the NGINX listener. Set service.port to change only the cluster-facing Service port. Probes, policy, and routing follow the named application port automatically.

More Information