Skip to content
HarborMarks
v1.1.0MIT licensed · no accounts, no telemetry, no cloud

A bookmark manager that lives on your NAS.

HarborMarks saves a link, pulls in its title, description, favicon and preview image, and makes the whole collection searchable in Postgres. One docker compose up -d and it runs on hardware you own — your NAS, a mini PC, or the laptop already on your desk.

  • Astro + React 19
  • PostgreSQL 17
  • Drizzle ORM
  • Docker Compose
harbormarks.home.lan
Self-hosted by design

Two containers. Your hardware. Done.

The published image ships the app; the compose file brings its Postgres alongside it. Schema migrations run before the server accepts its first request, so upgrading is a drop-in image swap.

Versioned SQL migrations at startup. Tracked in schema_migrations; a failed migration stops the container instead of serving a half-migrated database.

Healthchecks for your reverse proxy. An unauthenticated GET /api/healthz liveness probe that never touches the database.

Behind a tunnel or proxy? Supported. List your public hostname in HARBOR_ALLOWED_DOMAINS rather than turning the CSRF origin check off.

Your data stays in your volumes. db_data for Postgres, uploads_data for avatars and cached previews. Back them up and you have backed up everything.

ghcr.io/aperezm85/harbormarks:latest
linux/amd64
What it does

Built for collections that outgrew the browser bar.

Every link you save gets enriched, indexed and organised — and everything you can do to one bookmark, you can undo.

Paste a URL, get a record

Title, description, favicon and preview image are extracted on save, then proxied and cached locally so your library never hotlinks someone else's server.

Search that ranks, not just filters

Postgres full-text search over a generated search_vector with a GIN index and relevance ranking — plus tag:, site: and is:favorite operators.

Tags you can reorganise later

Autocomplete while you save, live counts in the sidebar, and a tag screen that renames a tag everywhere, merges one into another, or deletes it across the whole collection.

Views for how you actually browse

Recent, Unread, Unorganised, Favorites, Trash — and Most visited, weighted by recency so a page you hammered two years ago stops crowding out this month's reading.

Nothing is lost by accident

Delete is soft: an undo toast appears immediately, a Trash view keeps the rest, and permanent deletion is a separate, deliberate action.

No accidental duplicates

URLs are canonicalised on write — host, trailing slash, tracking parameters — and saving one you already have offers open, merge tags, or save anyway.

Three densities

Skim the previews, or scan a hundred rows.

The view selector switches between preview cards, a compact row with the thumbnail, and a single-line list. Your choice sticks across sessions.

Cards
Compact
List
New in v1.1.0

The links you meant to read, mailed to you on Sunday.

Opt in per user from your profile and pick what lands in the envelope: unread from the last seven days, every unread link, or everything you saved this week. Clicking a title marks it as reading and records the visit — the same as opening the card — then takes you straight to the page, no login needed.

SMTP, your serverSend now · 10/hourPOST /api/digest/run
Household-ready

More than one person, properly separated.

Isolation
Every list, tag, favourite and visit count is scoped to the user who made it.
Roles
An admin screen to create users, assign roles and switch accounts off.
Signup
Closed by default on the deploy compose; open it with HARBOR_ALLOW_SIGNUP for a private instance.
Accounts
Password reset and email verification over your own SMTP, with a server-log fallback.
Exposed to the internet?

The boring parts are already done.

CSRF
Origin checking on by default, evaluated per request, with proxy-aware Secure cookies.
SSRF
Outbound fetches for metadata, previews and favicons are guarded before they leave the container.
Rate limits
Login, registration and recovery endpoints are throttled; expired sessions and tokens clean themselves up.
Sessions
Database-backed session tokens with role-based guards on every admin route.

Bring your links home.

Clone the repo or pull the image, set a bootstrap admin password, and you have a bookmark manager that answers only to you.