Nomploy Nomad Packs

← All packs

karakeep v0.1.0

Bookmarks & RSS

Karakeep — a self-hosted bookmark-everything app (links, notes, images) with full-text search, automatic tagging and archival. Bundles Meilisearch and a headless Chrome as sidecars.

nomad-pack run karakeep --registry nomploy
…or one line (add registry + run)
curl -fsSL https://packs.nomploy.com/install.sh | sh -s -- karakeep

Needs nomad-pack on PATH. The script only adds the nomploy registry and runs this pack.

3 tasks http 3000meili 7700chrome 9222 2 volumes image ghcr.io/karakeep-app/karakeep:release pinned :release image bumped today
Variables 18
values.hcl

Save as values.hcl, edit, then run:

nomad-pack run karakeep -f values.hcl --registry nomploy
# The name of the Nomad job.
job_name = "karakeep"

# The Nomad namespace to deploy into.
namespace = "default"

# The datacenters to deploy to.
datacenters = ["*"]

# The Karakeep web image. Pin a tag in production.
image = "ghcr.io/karakeep-app/karakeep:release"

# The Meilisearch image used for full-text search.
meilisearch_image = "getmeili/meilisearch:v1.13.3"

# The headless Chrome image used to fetch and archive pages.
chrome_image = "gcr.io/zenika/alpine-chrome:123"

# Host port for the Karakeep web UI.
port = 3000

# Host port for the bundled Meilisearch (loopback only).
meili_port = 7700

# Host port for the headless Chrome remote-debugging endpoint (loopback only).
chrome_port = 9222

# Session signing secret (NEXTAUTH_SECRET). CHANGE THIS. Generate with: openssl rand -base64 36.
nextauth_secret = "change-me-openssl-rand-base64-36"

# Meilisearch master key (MEILI_MASTER_KEY), shared by the app and the search engine. CHANGE THIS. Generate with: openssl rand -base64 36.
meili_master_key = "change-me-openssl-rand-base64-36"

# Public URL Karakeep is reachable at (NEXTAUTH_URL). Empty = http://localhost:<port>. Set this to your real host/domain.
base_url = ""

# Named volume mounted at /data — the app's SQLite database and assets.
data_volume = "karakeep_data"

# Named volume mounted at /meili_data — the search index.
meili_data_volume = "karakeep_meili"

# Placement constraints. Pin to the node holding the volumes. On a nomploy cluster: attribute = "$${meta.nomploy_control_plane}", operator = "=", value = "true".
constraints = []

# Resources for the Karakeep web task.
resources = {
    cpu    = 500
    memory = 512
  }

# Resources for the Meilisearch task.
meilisearch_resources = {
    cpu    = 300
    memory = 512
  }

# Resources for the headless Chrome task. Rendering pages is memory-hungry.
chrome_resources = {
    cpu    = 500
    memory = 768
  }
NameTypeDefaultDescription
job_name string
"karakeep"
The name of the Nomad job.
namespace string
"default"
The Nomad namespace to deploy into.
datacenters list
["*"]
The datacenters to deploy to.
image string
"ghcr.io/karakeep-app/karakeep:release"
The Karakeep web image. Pin a tag in production.
meilisearch_image string
"getmeili/meilisearch:v1.13.3"
The Meilisearch image used for full-text search.
chrome_image string
"gcr.io/zenika/alpine-chrome:123"
The headless Chrome image used to fetch and archive pages.
port number
3000
Host port for the Karakeep web UI.
meili_port number
7700
Host port for the bundled Meilisearch (loopback only).
chrome_port number
9222
Host port for the headless Chrome remote-debugging endpoint (loopback only).
nextauth_secret set me string
"change-me-openssl-rand-base64-36"
Session signing secret (NEXTAUTH_SECRET). CHANGE THIS. Generate with: openssl rand -base64 36.
meili_master_key set me string
"change-me-openssl-rand-base64-36"
Meilisearch master key (MEILI_MASTER_KEY), shared by the app and the search engine. CHANGE THIS. Generate with: openssl rand -base64 36.
base_url string
""
Public URL Karakeep is reachable at (NEXTAUTH_URL). Empty = http://localhost:<port>. Set this to your real host/domain.
data_volume string
"karakeep_data"
Named volume mounted at /data — the app's SQLite database and assets.
meili_data_volume string
"karakeep_meili"
Named volume mounted at /meili_data — the search index.
constraints list
[]
Placement constraints. Pin to the node holding the volumes. On a nomploy cluster: attribute = "$${meta.nomploy_control_plane}", operator = "=", value = "true".
resources object
{
    cpu    = 500
    memory = 512
  }
Resources for the Karakeep web task.
meilisearch_resources object
{
    cpu    = 300
    memory = 512
  }
Resources for the Meilisearch task.
chrome_resources object
{
    cpu    = 500
    memory = 768
  }
Resources for the headless Chrome task. Rendering pages is memory-hungry.
Back up this pack

This pack stores data in 2 Docker named volumes: karakeep_meilikarakeep_data

restic

# Run on the node hosting this pack. Point restic at your repo first:
#   export RESTIC_REPOSITORY="s3:https://<account>.r2.cloudflarestorage.com/<bucket>"
#   export RESTIC_PASSWORD="<repo-password>"
#   export AWS_ACCESS_KEY_ID=<key>  AWS_SECRET_ACCESS_KEY=<secret>
restic backup \
  /var/lib/docker/volumes/karakeep_meili/_data \
  /var/lib/docker/volumes/karakeep_data/_data

rclone (sync to S3/R2)

rclone sync /var/lib/docker/volumes/karakeep_meili/_data backup:<bucket>/karakeep_meili
rclone sync /var/lib/docker/volumes/karakeep_data/_data backup:<bucket>/karakeep_data

Paths assume the default Docker volume location (/var/lib/docker/volumes). Restore by stopping the job, restoring files into the same volume, and re-running the pack.

Readme

karakeep

Karakeep (formerly Hoarder) — a self-hosted bookmark-everything app. Save links, notes and images; Karakeep fetches a full-page snapshot, extracts the text, and makes everything searchable. It can auto-tag content with an LLM, and offers browser extensions and mobile apps.

This pack is batteries-included: a single host-networked group running three tasks —

Deploy

nomad-pack registry add nomploy https://github.com/Nomploy/nomad-packs
nomad-pack run karakeep --registry=nomploy

Configure

Variable Default Description
port 3000 Web UI port.
nextauth_secret change-me-… Change this. Session signing secret. openssl rand -base64 36.
meili_master_key change-me-… Change this. Shared by the app and Meilisearch. openssl rand -base64 36.
base_url "" Public URL (NEXTAUTH_URL). Empty = http://localhost:<port>. Set to your real host.
image ghcr.io/karakeep-app/karakeep:release Web image. Pin a tag in production.
meilisearch_image getmeili/meilisearch:v1.13.3 Search engine image.
chrome_image gcr.io/zenika/alpine-chrome:123 Headless Chrome image.
meili_port / chrome_port 7700 / 9222 Loopback ports for the sidecars.
data_volume karakeep_data /data — database and assets.
meili_data_volume karakeep_meili /meili_data — the search index.
resources { cpu = 500, memory = 512 } Web task resources.
meilisearch_resources { cpu = 300, memory = 512 } Meilisearch resources.
chrome_resources { cpu = 500, memory = 768 } Chrome resources (rendering is memory-hungry).

AI tagging (optional): to enable automatic tagging, add OPENAI_API_KEY (or point OLLAMA_BASE_URL at a local ollama and set INFERENCE_TEXT_MODEL) to the karakeep task's env. See the Karakeep docs for the full list.

All three tasks share the host network, so they must run together on one node. Pin the job to the node holding the volumes with constraints, and put Karakeep behind an authenticating reverse proxy over TLS before exposing it.