
Deploy KaraKeep | (Just Updated) Bookmark Manager and Read-Later App, Pocket Alternative, Admin Preset
KaraKeep self-hosted bookmark manager and read-later app with REST API
Just deployed
/meili_data
Just deployed
karakeep
Just deployed
/data
Deploy and Host KaraKeep on Railway
Built for an LLM agent to deploy and use. The deploy form has no fields to fill: the admin login, the session signing key, the search key and the browser token are generated at deploy time, Meilisearch and a headless Chrome run beside the app, and public sign-up is closed once the admin exists. KaraKeep is an open-source, self-hosted bookmark manager and read-later app, a Pocket alternative: save links, notes and images, search them in full text, archive pages and read them later.
About Hosting KaraKeep
This template runs three services: karakeep (the web app and its REST API on one public domain, with a volume at /data for the database, archived pages and assets), search (Meilisearch with a volume at /meili_data for the full-text index) and chrome (a headless Chrome the app drives over the private network to crawl pages and take screenshots). Bookmarks and settings live in the /data volume, so they survive redeploys of any service.
Ready from boot. Stock KaraKeep leaves sign-up open, so the first stranger to reach a fresh public URL becomes the owner. This template creates the administrator named by the generated ADMIN_EMAIL and ADMIN_PASSWORD on first boot, on a loopback-only server before the public port opens, and from then on runs with sign-up disabled. The account exists once and a redeploy does not repeat it.
Using it. Sign in to the web interface at the public URL with the same email and password. For the API, exchange the email and password for an API key with the apiKeys.exchange call and send the key as a Bearer header; then POST /api/v1/bookmarks saves a link. Uploading assets, AI tagging and summaries need an inference provider key such as OPENAI_API_KEY, added as a variable on the karakeep service; everything else works without one.
Agent contract
- Public URL:
https://RAILWAY_PUBLIC_DOMAIN(the generated domain of thekarakeepservice) - Private URL:
http://karakeep.railway.internal:8080 - Credentials: the variables
ADMIN_EMAILandADMIN_PASSWORDon thekarakeepservice - Auth:
POST /api/trpc/apiKeys.exchangewith a JSON body{"json":{"keyName","email","password"}}returns an API key underresult.data.json.key; send it asAuthorization: Bearer $KEY. A write without a key or with a wrong key answers401, and sign-up answers403. - Health:
GET /api/healthreturns 200
#!/bin/sh
# needs: RAILWAY_PUBLIC_DOMAIN, ADMIN_EMAIL, ADMIN_PASSWORD (variables of the karakeep service); also curl
B="https://$RAILWAY_PUBLIC_DOMAIN"
J="Content-Type: application/json"
curl -s -o /dev/null -w "health: %{http_code}\n" "$B/api/health"
KEY=$(curl -s -X POST -H "$J" -d "{\"json\":{\"keyName\":\"agent\",\"email\":\"$ADMIN_EMAIL\",\"password\":\"$ADMIN_PASSWORD\"}}" "$B/api/trpc/apiKeys.exchange" | sed -n 's/.*"key":"\([^"]*\)".*/\1/p')
if [ -n "$KEY" ]; then echo "exchange: ok"; else echo "exchange: FAILED"; fi
D='{"type":"link","url":"https://example.com"}'
curl -s -o /dev/null -w "write with key: %{http_code}\n" -X POST -H "$J" -H "Authorization: Bearer $KEY" -d "$D" "$B/api/v1/bookmarks"
curl -s -o /dev/null -w "write without key: %{http_code}\n" -X POST -H "$J" -d "$D" "$B/api/v1/bookmarks"
curl -s -o /dev/null -w "write with wrong key: %{http_code}\n" -X POST -H "$J" -H "Authorization: Bearer ${KEY}x" -d "$D" "$B/api/v1/bookmarks"
curl -s -o /dev/null -w "read without key: %{http_code}\n" "$B/api/v1/bookmarks"
curl -s -o /dev/null -w "read with key: %{http_code}\n" -H "Authorization: Bearer $KEY" "$B/api/v1/bookmarks"
curl -s -o /dev/null -w "wrong password exchange: %{http_code}\n" -X POST -H "$J" -d "{\"json\":{\"keyName\":\"agent\",\"email\":\"$ADMIN_EMAIL\",\"password\":\"wrong-password-0\"}}" "$B/api/trpc/apiKeys.exchange"
curl -s -o /dev/null -w "open sign-up: %{http_code}\n" -X POST -H "$J" -d '{"name":"intruder","email":"intruder@example.com","password":"intruder-pass-1"}' "$B/api/auth/sign-up/email"
A fresh deploy prints health: 200, exchange: ok, write with key: 201, write without key: 401, write with wrong key: 401, read without key: 401, read with key: 200, wrong password exchange: 401 and open sign-up: 403.
Why Deploy KaraKeep on Railway?
Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.
By deploying KaraKeep on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.
- Agent-ready - no deployer fields, a contract block and one script that proves the key exchange, a bookmark write, the refusal of a write without a key and the closed sign-up.
- No open sign-up - the admin exists before the public port opens, so nobody can claim a fresh URL.
- Data survives redeploys - the app data and the search index each sit on a volume.
- Pinned - the upstream, Meilisearch and Chrome images are pinned by digest or exact tag.
- No per-seat pricing - unlimited bookmarks and API keys on your own domain.
Common Use Cases
- Read-later and link archive - save pages with a full-text copy that survives link rot.
- Pocket alternative - bookmarks, tags, lists and highlights on infrastructure you own.
- Research collection for a team or an agent - save sources over the REST API and search them later.
- Agent memory for web pages - an LLM agent saves and retrieves links with an API key.
Dependencies for KaraKeep Hosting
- The karakeep, search and chrome services with their volumes, all created by the template. A custom domain and an inference provider key are optional.
Deployment Dependencies
Template Content
