A private, self-hosted bookmark library with background previews and custom covers for your NAS.
515
Pocket is a private, self-hosted bookmark manager built for a home server or NAS. Paste a link, and Pocket fetches the title, description, favicon, and preview image in the background.
Everything is stored locally in a single SQLite database with cached media files beside it. There are no external database dependencies, no separate background workers, and no third-party accounts required.
Run the container with a persistent directory mounted to /data:
mkdir -p data
docker run -d \
--name pocket \
--restart unless-stopped \
-p 8420:8420 \
-v ./data:/data \
pinkpixeldev/pocket:latest
Open http://localhost:8420 (or http://<your-server-ip>:8420) in your browser.
Create a compose.yml file:
services:
pocket:
image: pinkpixeldev/pocket:latest
container_name: pocket
restart: unless-stopped
ports:
- '8420:8420'
volumes:
- ./data:/data
environment:
- TZ=UTC
# Optional: set OpenAI API key from the environment
# - POCKET_OPENAI_API_KEY=your-api-key
Start the service:
docker compose up -d
Pocket stores all data under the /data mount point:
/data
├── pocket.db SQLite database (all bookmarks, tags, collections, settings)
├── pocket.db-wal SQLite write-ahead log
├── pocket.db-shm SQLite shared memory file
├── previews/ Locally cached website preview images
├── favicons/ Locally cached website favicons
└── covers/ User-uploaded custom covers and images
Backing up the data/ folder backs up your entire bookmark library. Note that covers/ holds images you uploaded directly, so ensure it is included in your backup routine.
The container runs by default as the non-root node user (uid: 1000, gid: 1000).
If your host volume or NAS share is owned by a different user account, set the user in your compose file or docker run command:
user: '1026:100'
Ensure the host data directory is writable by that user before starting the container.
Every variable is optional and has a sensible default.
| Variable | Default | Description |
|---|---|---|
PORT | 8420 | Internal port Pocket listens on |
HOST | 0.0.0.0 | Network interface Pocket binds to |
POCKET_DATA_DIR | /data | Directory where database and images are stored |
POCKET_BLOCK_PRIVATE_ADDRESSES | true | Connect-time guard blocking fetches to local and private networks |
POCKET_FETCH_TIMEOUT_MS | 12000 | Whole-request budget for one metadata fetch |
POCKET_ENRICH_TIMEOUT_MS | 45000 | Budget for one whole enrichment job, covering the page and every image it tries |
POCKET_MAX_HTML_BYTES | 2097152 | Maximum bytes read from a website during metadata fetch |
POCKET_MAX_IMAGE_BYTES | 6291456 | Maximum file size for cached preview images |
POCKET_MAX_REDIRECTS | 5 | Maximum redirect hops followed per fetch |
POCKET_MAX_UPLOAD_BYTES | 33554432 | Maximum bookmark file size for browser HTML imports |
POCKET_MAX_COVER_BYTES | 10485760 | Maximum size for an uploaded cover image |
POCKET_USER_AGENT | standard Pocket string | User agent sent when fetching page metadata |
POCKET_PROBE_USER_AGENT | a Chrome string | User agent the link check retries with when a host refuses the Pocket one |
POCKET_OPENAI_API_KEY | unset | A shared OpenAI key every account can use. An account that saves its own key uses that instead |
POCKET_SECURE_COOKIES | follows the request | Force the session cookie's Secure flag on or off. Normally Pocket follows X-Forwarded-Proto |
POCKET_OPENAI_BASE_URL | https://api.openai.com/v1 | Custom endpoint for OpenAI-compatible proxies |
POCKET_OPENAI_TIMEOUT_MS | 60000 | Timeout for AI model responses |
POCKET_AI_EXCERPT_CHARS | 1500 | Characters of page text sent in AI prompt |
Pocket has its own sign-in. The first person to open it creates the owner account, and the owner adds everyone else from Settings. Each account gets its own bookmarks, collections, tags and AI settings, so several people can share one container without sharing a library.
It still serves plain HTTP, so put it on a trusted home network or a private VPN such as Tailscale or WireGuard. To reach it over the public internet, place it behind a reverse proxy that terminates HTTPS, such as Caddy, Traefik or nginx.
Pocket includes connect-time SSRF protection. When fetching metadata for saved links, Pocket inspects DNS answers and literal IP addresses to refuse connections to loopback, RFC 1918 private subnets, carrier-grade NAT, and link-local addresses.
Images are built for both linux/amd64 and linux/arm64.
Content type
Image
Digest
sha256:5bfe54bbf…
Size
87 MB
Last updated
9 days ago
docker pull pinkpixeldev/pocket