Skip to content
HarborMarks
v1.5.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, suggests tags from the page's own keywords, and makes the whole collection searchable in Postgres. New links arrive straight from your browser or phone. 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 the moment you paste a link, tags are suggested from the page's own keywords, and assets are 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:, is:favorite and is:broken 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.

Collection Dashboard for cleanup

A dedicated /dashboard page surfaces bookmark debt, broken links, duplicates, unassigned bookmarks, trends, and rediscovery picks — with direct links to jump into each cleanup view.

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.

Clean up in bulk, not one by one

Tick checkboxes to select bookmarks — shift-click grabs a whole range — then favorite, archive, tag, or delete them all at once from the toolbar. Bulk delete still goes to Trash first.

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.1

The links you meant to read, mailed on your schedule.

Opt in per user from your profile and pick what lands in the envelope: unread from the last seven days, every unread link, everything you saved this week — or just the broken links — plus the weekday and hour it arrives. 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
New in v1.2.0

Save it before the tab closes.

The browser extension saves the current tab in one click — title prefilled, tags and a private note optional, duplicates reported instead of erroring, right-click included. On your phone, the iOS Shortcut opens a quick-save page with the same one-tap flow. Both run on per-device API keys from your profile, revocable any time.

Chrome + Edge extensioniOS Shortcut · /save pagePer-device API keys
New in v1.5.0

Collection Dashboard turns backlog into actions.

The dashboard now lives on its own page at/dashboard. It combines a collection score, bookmark debt, broken-link checks, duplicate and unassigned insights, trend snapshots, and rediscovery picks, with direct links into cleanup views so you can fix what matters first.

New in v1.5.0Dedicated /dashboard pageBookmark debt + scoreDirect cleanup links
New in v1.4.0

Clean up in bulk, not one by one.

Tick checkboxes to select bookmarks — shift-click grabs a whole range — then favorite, archive, tag, or delete them all at once from the toolbar pinned above the cards. Bulk delete still lands in Trash first, and tag changes keep your existing casing instead of duplicating it.

Shift-click rangesFavorite · archive · tag · deleteTrash-first deleteUp to 500 at a time
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.