Skip to content

Karakeep

AI-powered bookmark manager. Karakeep saves links with full-text content archival, automatic screenshots via the official Karakeep Chrome image, full-text search via Meilisearch, and optional AI-driven automatic tagging. All data is stored in SQLite on a single persistent volume. The chart currently deploys Karakeep 0.34.1.

Karakeep 0.34.1 is a security release

Version 0.34.1 updates Node.js to fix a Brotli memory-safety vulnerability and three TLS hostname-validation bypasses. Back up the PVC before upgrading. Deployments coming from 0.33.x must also complete the upstream 0.34.0 authentication migration.

Architecture

Karakeep runs as a single pod with optional sidecars sharing the same PVC:

  • karakeep — main application (Next.js)
  • meilisearch (optional) — full-text search engine, indexes archived content
  • chromium (optional) — official Karakeep Chrome image for web page screenshots and archiving
Chromium and Meilisearch require significant resources

With both sidecars enabled (the default), the pod requires at least 1.5–2 GB RAM to operate stably. The Chromium sidecar alone needs ~500 MB on startup. On resource-constrained clusters (e.g. Raspberry Pi), disable one or both sidecars and set explicit resources limits for the remaining containers.

Key Features

  • Meilisearch sidecar — optional full-text search across bookmarks and archived content
  • Chromium sidecar — optional headless browser for automatic web page screenshots
  • AI tagging — automatic categorization via OpenAI or Ollama (configured via extraEnv)
  • SQLite storage — embedded database, no external database required
  • Persistent storage — single PVC shared by all containers
  • Ingress support — TLS via cert-manager with configurable ingress class
  • External Secrets — optional ESO projection for auth and Meilisearch credentials
  • Runtime port contracts — configurable Karakeep and Meilisearch listeners, validated in-cluster
  • Secure defaults — non-root containers, seccomp, dropped capabilities, token-free ServiceAccount, and NetworkPolicy

Operational Patterns

The examples below cover the supported Karakeep operating modes: full sidecar mode, lightweight mode, AI tagging, explicit resource limits, TLS ingress, Gateway API, and External Secrets Operator credentials. The playground exposes the same high-impact settings so operators can generate a focused values file without starting from the complete values contract.

Security Scan

Security Scan: Kubescape on rendered default manifests.

Framework Score
MITRE + NSA + SOC2 87.878784%

The chart enables container hardening, runtime-default seccomp, disabled API token mounting, and an ingress NetworkPolicy by default. Resource requests and limits remain workload-specific and should be set in production.

Installation

HTTPS repository:

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

OCI registry:

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

Deployment Examples

# values.yaml — Karakeep with Meilisearch and Chromium (default)
karakeep:
  nextAuthUrl: 'https://karakeep.example.com'

meilisearch:
  enabled: true
  # Allows the pinned image to migrate an older on-disk database.
  upgradeDb: true

chromium:
  enabled: true

persistence:
  enabled: true
  size: 10Gi

ingress:
  enabled: true
  ingressClassName: traefik
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: karakeep.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: karakeep-tls
      hosts:
        - karakeep.example.com
# values.yaml — Lightweight mode without sidecars
# Suitable for resource-constrained environments (ARM, Raspberry Pi)
# Full-text search and automatic screenshots will be unavailable.
karakeep:
  nextAuthUrl: 'https://karakeep.example.com'

meilisearch:
  enabled: false

chromium:
  enabled: false

persistence:
  enabled: true
  size: 5Gi

resources:
  requests:
    memory: 256Mi
    cpu: 100m
  limits:
    memory: 512Mi
    cpu: 500m

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: karakeep.example.com
      paths:
        - path: /
          pathType: Prefix
# values.yaml — Karakeep with OpenAI automatic tagging
karakeep:
  nextAuthUrl: 'https://karakeep.example.com'
  extraEnv:
    # OpenAI integration for automatic AI tagging
    - name: OPENAI_API_KEY
      valueFrom:
        secretKeyRef:
          name: karakeep-ai-secret
          key: openai-api-key
    - name: OPENAI_BASE_URL
      value: 'https://api.openai.com/v1'

    # Alternative: use Ollama for local AI inference
    # - name: OLLAMA_BASE_URL
    #   value: 'http://ollama.ollama.svc:11434'
    # - name: INFERENCE_TEXT_MODEL
    #   value: 'llama3.2'

meilisearch:
  enabled: true

chromium:
  enabled: true

persistence:
  enabled: true
  size: 10Gi

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: karakeep.example.com
      paths:
        - path: /
          pathType: Prefix
# values.yaml — Production setup with explicit resource limits per container
karakeep:
  nextAuthUrl: 'https://karakeep.example.com'

meilisearch:
  enabled: true
  resources:
    requests:
      memory: 256Mi
      cpu: 100m
    limits:
      memory: 512Mi
      cpu: 500m

chromium:
  enabled: true
  resources:
    requests:
      memory: 512Mi
      cpu: 250m
    limits:
      memory: 1Gi
      cpu: 1000m

resources:
  requests:
    memory: 256Mi
    cpu: 100m
  limits:
    memory: 512Mi
    cpu: 500m

persistence:
  enabled: true
  size: 10Gi

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: karakeep.example.com
      paths:
        - path: /
          pathType: Prefix

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 ghcr.io/karakeep-app/karakeep Karakeep container image.
image.tag string "0.34.1" Image tag.
image.digest string pinned SHA-256 Immutable multi-architecture digest.
image.pullPolicy string IfNotPresent Image pull policy.
imagePullSecrets array [] Pull secrets for private registries.
containerPorts.http integer 3000 Karakeep process listener port.

Karakeep Configuration

Parameter Type Default Description
karakeep.nextAuthUrl string "" Public URL of the instance. Used as NEXTAUTH_URL for authentication callbacks.
karakeep.browserConnectOnDemand bool true Connect to Chromium only when crawling needs it.
karakeep.existingSecret string "" Existing secret with nextauth-secret and meili-master-key.
karakeep.existingSecretNextAuthKey string nextauth-secret Key for NEXTAUTH_SECRET.
karakeep.existingSecretMeiliMasterKey string meili-master-key Key for MEILI_MASTER_KEY.
karakeep.extraEnv array [] Extra environment variables for AI integration and advanced configuration.
nextAuthUrl must match your exact public URL

Karakeep uses Next.js authentication (NextAuth). The NEXTAUTH_URL must exactly match the URL your users use to access the app — including the scheme (https://) and without a trailing slash. A mismatch causes login redirects to fail or sessions to be rejected.

Enable AI tagging via extraEnv

Karakeep supports automatic AI-powered tagging using OpenAI or a local Ollama instance. Configure the integration by setting OPENAI_API_KEY (and optionally OPENAI_BASE_URL) or OLLAMA_BASE_URL and INFERENCE_TEXT_MODEL via karakeep.extraEnv. See the Karakeep AI documentation for the full list of supported variables.

Meilisearch Sidecar

Parameter Type Default Description
meilisearch.enabled boolean true Enable the Meilisearch sidecar for full-text search.
meilisearch.image.repository string docker.io/getmeili/meilisearch Meilisearch container image.
meilisearch.image.tag string "v1.53.0" Meilisearch image tag.
meilisearch.image.digest string pinned SHA-256 Immutable multi-architecture digest.
meilisearch.image.pullPolicy string IfNotPresent Meilisearch image pull policy.
meilisearch.port integer 7700 Meilisearch process listener port.
meilisearch.environment string development Meilisearch runtime environment.
meilisearch.upgradeDb boolean true Upgrade an older on-disk database at startup.
meilisearch.extraEnv array [] Extra non-reserved environment variables.
meilisearch.securityContext object hardened defaults Sidecar container security context.
meilisearch.resources object {} CPU and memory requests and limits for Meilisearch.

Chromium Sidecar

Parameter Type Default Description
chromium.enabled boolean true Enable the Chromium sidecar for screenshots and archiving.
chromium.image.repository string ghcr.io/karakeep-app/karakeep-chrome Official Karakeep Chrome image.
chromium.image.tag string "154.0.8037.57-r1" Immutable Chromium build tag.
chromium.image.digest string pinned SHA-256 Immutable multi-architecture digest.
chromium.image.pullPolicy string IfNotPresent Chromium image pull policy.
chromium.args array upstream-recommended flags Chromium command-line arguments.
chromium.securityContext object hardened defaults Sidecar container security context.
chromium.resources object {} CPU and memory requests and limits for Chromium.
Chromium port 9222 is fixed upstream

The official image entrypoint runs an unauthenticated socat proxy on port 9222 and Chrome’s internal debugging endpoint on port 9223. Chrome binds 9223 to IPv4 loopback, while the proxy binds 9222 to all pod IPv4 interfaces. Karakeep reaches the proxy at 127.0.0.1; using localhost can select IPv6. Keep the NetworkPolicy enabled or provide another access boundary for port 9222. Do not override either port. When Chromium is enabled, remove BROWSER_WEB_URL and BROWSER_CONNECT_ONDEMAND from karakeep.extraEnv; the chart rejects duplicate definitions. containerPorts.http and meilisearch.port are configurable because those values are passed to the actual application processes.

Persistence

All containers in the pod share the same PVC. SQLite database, Meilisearch index, and uploaded files are all stored within this volume.

Parameter Type Default Description
persistence.enabled boolean true Enable a PVC for application data, search index, and uploads.
persistence.size string 10Gi PVC size.
persistence.storageClass string "" StorageClass for the PVC.
persistence.accessModes array ["ReadWriteOnce"] PVC access modes.
persistence.existingClaim string "" Use an existing PVC instead of creating one.

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.
service.ipFamilyPolicy string null Service IP family policy.
service.ipFamilies array [] Ordered Service IP families.

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 (e.g. cert-manager).
ingress.hosts array [] Ingress host and path rules.
ingress.tls array [] TLS configuration (secret name and hosts).

Gateway API

Use gatewayAPI.enabled to render a native Kubernetes Gateway API HTTPRoute for Karakeep. Ingress stays disabled by default and can coexist with the route during migrations.

gatewayAPI:
  enabled: true
  parentRefs:
    - name: shared-gateway
      namespace: gateway-system
      sectionName: https
  hostnames:
    - karakeep.example.com
  paths:
    - type: PathPrefix
      value: /
Parameter Type Default Description
gatewayAPI.enabled boolean false Render an HTTPRoute.
gatewayAPI.parentRefs array [] Parent Gateway references.
gatewayAPI.hostnames array [] HTTPRoute hostnames.
gatewayAPI.paths array [{ type: PathPrefix, value: "/" }] HTTPRoute path matches.
gatewayAPI.annotations object {} HTTPRoute annotations.

Dual-Stack Networking

Karakeep’s Service supports Kubernetes dual-stack networking through optional service.ipFamilyPolicy and service.ipFamilies values. Defaults omit both fields so existing installs inherit cluster defaults.

service:
  ipFamilyPolicy: PreferDualStack

Probes

Parameter Type Default Description
probes.startup.enabled boolean true Enable startup probe.
probes.startup.initialDelaySeconds integer 5 Startup probe initial delay.
probes.startup.periodSeconds integer 5 Startup probe period.
probes.startup.timeoutSeconds integer 3 Startup probe timeout.
probes.startup.failureThreshold integer 30 Startup probe failure threshold.
probes.liveness.enabled boolean true Enable liveness probe.
probes.liveness.initialDelaySeconds integer 0 Liveness probe initial delay.
probes.liveness.periodSeconds integer 15 Liveness probe period.
probes.liveness.timeoutSeconds integer 5 Liveness probe timeout.
probes.liveness.failureThreshold integer 3 Liveness probe failure threshold.
probes.readiness.enabled boolean true Enable readiness probe.
probes.readiness.initialDelaySeconds integer 0 Readiness probe initial delay.
probes.readiness.periodSeconds integer 10 Readiness probe period.
probes.readiness.timeoutSeconds integer 5 Readiness probe timeout.
probes.readiness.failureThreshold integer 3 Readiness probe failure threshold.

Resources and Security

These values apply to the main Karakeep container. Set meilisearch.resources and chromium.resources separately for the sidecars.

Parameter Type Default Description
resources object {} CPU and memory requests and limits for Karakeep.
podSecurityContext object hardened defaults Pod-level security context.
securityContext object hardened defaults Main container security context.

Service Account

Parameter Type Default Description
serviceAccount.create boolean true 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.

Network Policy

The default ingress policy admits the named HTTP port from any namespace, preserving compatibility with ingress controllers while blocking other inbound pod ports. Restrict networkPolicy.ingressFrom for a tighter production boundary. Egress remains open because web archiving and optional AI providers require arbitrary external destinations.

Parameter Type Default Description
networkPolicy.enabled boolean true Create the ingress NetworkPolicy.
networkPolicy.ingressFrom array [] Optional namespace and pod selector peers.

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.

External Secrets

Karakeep can render an External Secrets Operator ExternalSecret that projects NEXTAUTH_SECRET and MEILI_MASTER_KEY into the Kubernetes Secret configured by karakeep.existingSecret.

karakeep:
  existingSecret: karakeep-app-secret

externalSecrets:
  enabled: true
  secretStoreRef:
    name: platform-secrets
    kind: ClusterSecretStore
  data:
    - secretKey: nextauth-secret
      remoteRef:
        key: karakeep/credentials
        property: nextauth-secret
    - secretKey: meili-master-key
      remoteRef:
        key: karakeep/credentials
        property: meili-master-key
Parameter Type Default Description
externalSecrets.enabled boolean false Render an ExternalSecret.
externalSecrets.secretStoreRef.name string "" SecretStore or ClusterSecretStore.
externalSecrets.secretStoreRef.kind string SecretStore Secret store kind.
externalSecrets.refreshInterval string "0" ExternalSecret refresh interval.
externalSecrets.data array [] Remote key mappings for Secret data.

Common Issues

Pod OOMKilled with both sidecars enabled

If the pod is killed shortly after startup with OOMKilled, the Chromium sidecar is most likely the cause. Set explicit chromium.resources.limits.memory (at least 1Gi) and meilisearch.resources.limits.memory (at least 512Mi). Check kubectl describe pod for which container was killed.

A custom service port does not change the process listener

Use containerPorts.http to change Karakeep’s actual listener and meilisearch.port to change Meilisearch’s actual listener. service.port only changes the cluster-facing Service port. Chromium remains fixed on port 9222.

Upgrade Notes

Karakeep 0.34.1 includes the Node.js security fixes described above. The chart also replaces Browserless with the official karakeep-chrome image introduced by the upstream 0.34.0 migration. Before upgrading from 0.33.x, back up /data and resolve accounts whose email addresses differ only by letter case; the automatic migration lowercases addresses and conflicting accounts can lock users out. All web users must sign in again after migration, while mobile sessions and API keys are unaffected. Verify login, search, and a new screenshot after rollout.

Back up Meilisearch before upgrading

The default meilisearch.upgradeDb: true lets the pinned Meilisearch image migrate an older database on the shared PVC, including databases created by the previously pinned 1.41 release. Upstream migrations are not atomic. Take a PVC snapshot before upgrading. Confirm that the Meilisearch UpgradeDatabase task reached succeeded, then verify search after rollout. Only then may you disable the option; keep it enabled when task success is unconfirmed or restored volumes may contain an older database. The development environment remains the default for compatibility with existing short master keys. Rotate keys to at least 16 bytes before opting into production.

Bookmarks saved but no screenshots appearing

Screenshots require the Chromium sidecar to be running. Verify that chromium.enabled: true and check the Chromium container logs: kubectl logs <pod> -c chromium. On ARM64 nodes, ensure the Chromium image has an ARM64 variant available for your tag.

More Information