Skip to content

Karakeep

AI-powered bookmark manager. Karakeep saves links with full-text content archival, automatic screenshots via a headless Chromium browser, full-text search via Meilisearch, and optional AI-driven automatic tagging. All data is stored in SQLite on a single persistent volume.

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) — headless browser 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

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

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

ParameterTypeDefaultDescription
nameOverridestring""Override the chart name.
fullnameOverridestring""Override the full release name.
commonLabelsobject{}Extra labels added to all resources.

Image

ParameterTypeDefaultDescription
image.repositorystringghcr.io/karakeep-app/karakeepKarakeep container image.
image.tagstring"0.32.0"Image tag.
image.pullPolicystringIfNotPresentImage pull policy.
imagePullSecretsarray[]Pull secrets for private registries.

Karakeep Configuration

ParameterTypeDefaultDescription
karakeep.nextAuthUrlstring""Public URL of the instance. Used as NEXTAUTH_URL for authentication callbacks.
karakeep.browserConnectOnDemandbooltrueConnect to Chromium only when crawling needs it.
karakeep.existingSecretstring""Existing secret with nextauth-secret and meili-master-key.
karakeep.existingSecretNextAuthKeystringnextauth-secretKey for NEXTAUTH_SECRET.
karakeep.existingSecretMeiliMasterKeystringmeili-master-keyKey for MEILI_MASTER_KEY.
karakeep.extraEnvarray[]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

ParameterTypeDefaultDescription
meilisearch.enabledbooleantrueEnable the Meilisearch sidecar for full-text search.
meilisearch.image.repositorystringdocker.io/getmeili/meilisearchMeilisearch container image.
meilisearch.image.tagstring"v1.41.0"Meilisearch image tag.
meilisearch.image.pullPolicystringIfNotPresentMeilisearch image pull policy.
meilisearch.resourcesobject{}CPU and memory requests and limits for Meilisearch.

Chromium Sidecar

ParameterTypeDefaultDescription
chromium.enabledbooleantrueEnable the Chromium sidecar for screenshots and archiving.
chromium.portinteger9222Internal Chromium sidecar HTTP port.
chromium.image.repositorystringghcr.io/browserless/chromiumChromium container image.
chromium.image.tagstring"v2.46.0"Chromium image tag.
chromium.image.pullPolicystringIfNotPresentChromium image pull policy.
chromium.resourcesobject{}CPU and memory requests and limits for Chromium.

Persistence

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

ParameterTypeDefaultDescription
persistence.enabledbooleantrueEnable a PVC for application data, search index, and uploads.
persistence.sizestring10GiPVC size.
persistence.storageClassstring""StorageClass for the PVC.
persistence.accessModesarray["ReadWriteOnce"]PVC access modes.
persistence.existingClaimstring""Use an existing PVC instead of creating one.

Service

ParameterTypeDefaultDescription
service.typestringClusterIPKubernetes service type.
service.portinteger80Service port exposed to the cluster.
service.annotationsobject{}Annotations for the Service.
service.ipFamilyPolicystringnullService IP family policy.
service.ipFamiliesarray[]Ordered Service IP families.

Ingress

ParameterTypeDefaultDescription
ingress.enabledbooleanfalseEnable an Ingress resource.
ingress.ingressClassNamestringtraefikIngress class name.
ingress.annotationsobject{}Annotations for the Ingress (e.g. cert-manager).
ingress.hostsarray[]Ingress host and path rules.
ingress.tlsarray[]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: /
ParameterTypeDefaultDescription
gatewayAPI.enabledbooleanfalseRender an HTTPRoute.
gatewayAPI.parentRefsarray[]Parent Gateway references.
gatewayAPI.hostnamesarray[]HTTPRoute hostnames.
gatewayAPI.pathsarray[{ type: PathPrefix, value: "/" }]HTTPRoute path matches.
gatewayAPI.annotationsobject{}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

ParameterTypeDefaultDescription
probes.startup.enabledbooleantrueEnable startup probe.
probes.startup.initialDelaySecondsinteger5Startup probe initial delay.
probes.startup.periodSecondsinteger5Startup probe period.
probes.startup.timeoutSecondsinteger3Startup probe timeout.
probes.startup.failureThresholdinteger30Startup probe failure threshold.
probes.liveness.enabledbooleantrueEnable liveness probe.
probes.liveness.initialDelaySecondsinteger0Liveness probe initial delay.
probes.liveness.periodSecondsinteger15Liveness probe period.
probes.liveness.timeoutSecondsinteger5Liveness probe timeout.
probes.liveness.failureThresholdinteger3Liveness probe failure threshold.
probes.readiness.enabledbooleantrueEnable readiness probe.
probes.readiness.initialDelaySecondsinteger0Readiness probe initial delay.
probes.readiness.periodSecondsinteger10Readiness probe period.
probes.readiness.timeoutSecondsinteger5Readiness probe timeout.
probes.readiness.failureThresholdinteger3Readiness probe failure threshold.

Resources and Security

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

ParameterTypeDefaultDescription
resourcesobject{}CPU and memory requests and limits for Karakeep.
podSecurityContextobject{}Pod-level security context.
securityContextobject{}Container-level security context.

Service Account

ParameterTypeDefaultDescription
serviceAccount.createbooleanfalseCreate a dedicated ServiceAccount.
serviceAccount.namestring""Override the ServiceAccount name.
serviceAccount.annotationsobject{}Annotations for the ServiceAccount.

Scheduling

ParameterTypeDefaultDescription
nodeSelectorobject{}Node selector for scheduling.
tolerationsarray[]Tolerations for scheduling.
affinityobject{}Affinity rules.
topologySpreadConstraintsarray[]Topology spread constraints.
priorityClassNamestring""PriorityClass for the pod.
terminationGracePeriodSecondsinteger30Termination grace period.
podLabelsobject{}Extra labels for the pod.
podAnnotationsobject{}Extra annotations for the pod.

Extra

ParameterTypeDefaultDescription
extraVolumesarray[]Extra volumes to attach to the pod.
extraVolumeMountsarray[]Extra volume mounts for the container.
extraManifestsarray[]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
ParameterTypeDefaultDescription
externalSecrets.enabledbooleanfalseRender an ExternalSecret.
externalSecrets.secretStoreRef.namestring""SecretStore or ClusterSecretStore.
externalSecrets.secretStoreRef.kindstringSecretStoreSecret store kind.
externalSecrets.refreshIntervalstring"0"ExternalSecret refresh interval.
externalSecrets.dataarray[]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.

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