Linkwarden: Self-Hosted Bookmarking for the Tab Hoarder
Save the page, not just the link — before it 404s forever

I have a confession that will surprise nobody who has ever borrowed my laptop: my browser at any given moment is holding somewhere north of two hundred open tabs. Each one is a promise to myself — “I’ll read this later” — and each one is a lie. Worse, the tabs I do eventually bookmark have a nasty habit of rotting. I click through six months later and find a 404, a parked domain, or a “this article has been removed” notice. The thing I wanted to keep is gone, and all my bookmark preserved was the gravestone.
Link rot is the quiet tax on a life lived online. The fix I landed on is Linkwarden, and it has done more for my digital hoarding than any number of New Year’s resolutions to “tab less”.
1 What Linkwarden actually does
Most bookmark managers store a URL and a title. That is the bit that rots. Linkwarden stores the URL and a copy of the page — it archives whatever you save as a screenshot, a PDF, a full HTML capture, and a stripped-down readable version. So when the original inevitably vanishes, you still have the content. The link points at a tombstone; Linkwarden hands you the body.
On top of the archiving it does all the sensible organisational things you’d expect: collections (nested folders, basically), tags, and full-text search across the archived content — not just titles, but the actual words inside the saved pages. There’s a browser extension for one-click saving, and you can share collections or individual links publicly if you want to.
It’s open source, written by a small team, and — crucially for me — runs perfectly well on a modest home server.
2 Getting it running
Linkwarden ships as a Docker image and wants a PostgreSQL database alongside it. A docker-compose.yml is the path of least resistance. Here’s a trimmed-down version of what I run:
services:
postgres:
image: postgres:16-alpine
restart: always
environment:
POSTGRES_USER: linkwarden
POSTGRES_PASSWORD: change-me-to-something-long
POSTGRES_DB: linkwarden
volumes:
- ./pgdata:/var/lib/postgresql/data
linkwarden:
image: ghcr.io/linkwarden/linkwarden:latest
restart: always
depends_on:
- postgres
environment:
# Generate with: openssl rand -base64 32
NEXTAUTH_SECRET: paste-a-real-random-secret-here
NEXTAUTH_URL: https://links.example.com/api/v1/auth
DATABASE_URL: postgresql://linkwarden:change-me-to-something-long@postgres:5432/linkwarden
ports:
- "3000:3000"
volumes:
- ./data:/data/dataA few things worth saying out loud, because the docs assume you already know them. NEXTAUTH_SECRET is not optional and not cosmetic — generate a real random value with openssl rand -base64 32 and never reuse it elsewhere. NEXTAUTH_URL must match the address you actually reach the app on; if you put it behind a reverse proxy with TLS (which you should), use the https:// hostname, not localhost. And the ./data volume is where the archives live, so put it somewhere with room to grow.
Bring it up with docker compose up -d, wait for Postgres to settle, hit the port, and create your admin account on first load.
3 The workflow, in practice
Once it’s up the loop is genuinely pleasant. You paste a URL (or hit the browser extension), optionally drop it into a collection and slap a tag or two on it, and save. In the background Linkwarden goes off and renders the page, grabbing the screenshot, PDF, and readable copy. After a few seconds the entry shows little icons telling you which formats are ready.
I organise by collection — “Homelab”, “Recipes”, “Things to read on a train”, “Articles I’ll cite in an argument later” — and lean hard on tags for the cross-cutting stuff. The search is the part I underrated at first. Because it indexes the archived text, I can find a half-remembered article by a phrase from its third paragraph, even if I gave it a useless title at save time. That alone has retired about forty browser tabs.
4 The honest trade-offs
This is not magic, and I’d be doing you a disservice to pretend otherwise.
The biggest one is storage. Every archived page is a screenshot plus a PDF plus HTML, and that adds up faster than you’d think — a few hundred saves and you’re into gigabytes. If you’re the kind of person Linkwarden is for, you will fill a disk. Plan for it, and consider whether you really need full PDF archiving on every single link.
Second, some sites resist archiving. Pages hidden behind logins, aggressive paywalls, or heavy anti-bot measures will save as a screenshot of a cookie banner or a “please verify you are human” wall. The readable copy is your friend here, but it isn’t infallible. Sites that render everything client-side can also produce patchy captures.
And as ever with self-hosting: this is now a thing you own. Backups of the Postgres database and the data volume are your responsibility. An archive you forgot to back up is just link rot with extra steps.
5 The verdict
Linkwarden is for the chronic tab-hoarder, the researcher, the person who has been burned one too many times by a dead bookmark. If your bookmarking needs end at “save this URL”, a browser already does that for free and you should stop reading. But if you actually want to keep the things you save — to outlive the websites they came from — this is the tool. It’s been the rare piece of self-hosted software that made me change a bad habit rather than just enabling it. My tab count is down, my archive is up, and the next time a site 404s on me, I’ll be the one who still has the page.




