Bookmarking tools built into browsers are basically digital junk drawers – links pile up, organization falls apart, and when a page goes offline, the content is gone for good. Linkwarden fixes all three problems at once by archiving full snapshots of saved pages and giving you a clean, self-hosted interface to organize everything with collections and tags.

What Linkwarden Actually Does
Linkwarden is an open-source bookmark manager designed specifically for self-hosting. Unlike a simple link list, it captures a screenshot and a readable text snapshot of every page you save, so even if the original URL disappears, your archived version stays intact on your own server. It supports multiple users, shared collections, and browser extensions for Chrome and Firefox, making it practical for both personal use and small teams.
The stack runs on Next.js with a PostgreSQL database. You get a web interface that loads fast and handles search well, including full-text search across archived content – not just titles and URLs. That detail matters more than it sounds. A year from now, when you vaguely remember saving something about kernel parameters or CSS grid tricks, you can search the actual page text rather than guessing what you titled the bookmark.
Linkwarden also integrates with Monolith, a command-line tool that saves a single-file HTML version of web pages, stripping trackers and external dependencies so the archive is genuinely portable. The combination gives you something closer to a personal Wayback Machine than a standard bookmarking app. If you already run a self-hosted stack and want a note-sync layer alongside it, the approach used to set up Obsidian Sync as a self-hosted note server pairs well with what Linkwarden handles on the bookmarking side.
Before starting, you will need a Linux server or VPS running Docker and Docker Compose. The recommended minimum is 1 GB of RAM, though 2 GB is more comfortable once archiving tasks start running in the background. A domain name pointed at your server is optional but strongly recommended if you want HTTPS and browser extension support to work without friction.

Installing Linkwarden With Docker Compose
Create a working directory and pull the official compose file. The project maintains a docker-compose.yml on its GitHub repository, and using it directly saves you from configuration drift when upstream changes. Inside your directory, create a .env file – this is where all the sensitive configuration lives.
Your .env file needs a few required values. Set NEXTAUTH_SECRET to a long random string, which you can generate with openssl rand -base64 32. Set NEXTAUTH_URL to the full URL where Linkwarden will be accessible, for example https://links.yourdomain.com. Set POSTGRES_PASSWORD to another strong random string. The database name and user default to linkwarden in the compose file, so you only need to supply the password. Finally, add PAGINATION_TAKE_COUNT=20 if you want to control how many links load per page – the default is fine for most setups but worth knowing it is adjustable.
The compose file defines two services: the Linkwarden app container and a PostgreSQL container. The app exposes port 3000 by default. If you are running Nginx or Caddy as a reverse proxy, map port 3000 internally and do not expose it directly to the internet. The data directory for PostgreSQL should be mounted as a named volume so your bookmarks and archives survive container restarts and image updates. Linkwarden stores screenshot and HTML archive files in a separate data folder, which you should also mount as a bind mount to a path on your host system – this makes backups straightforward and keeps archive files out of the container layer.
Run docker compose up -d from your working directory. On first launch, Linkwarden will run database migrations automatically. Give it about 30 seconds, then check the logs with docker compose logs -f linkwarden to confirm the app is running without errors. When you see the Next.js ready message with the port number, the instance is up. Navigate to your URL or http://localhost:3000 to create your first account.
Account creation on first launch works through the registration page. After the first admin account is created, you can control whether additional registrations are open or invite-only by setting DISABLE_REGISTRATION=true in your .env file and restarting the container. For a private personal instance, disabling open registration immediately after your first account is a straightforward security step. Once logged in, install the browser extension from the Chrome Web Store or Firefox Add-ons, point it at your instance URL, and authenticate with your credentials – at that point, saving a link from any tab takes a single click.
Configuring Archiving and Staying Current
By default, Linkwarden archives every link you save, capturing a screenshot via Playwright (which runs headless Chromium inside the container) and a Monolith HTML snapshot. This runs as a background job, so the link appears in your collection immediately while the archive processes asynchronously. You can monitor archive status from the link detail view – each entry shows whether the screenshot and HTML archive succeeded or is still pending. If archiving fails repeatedly for a specific domain, it is usually a JavaScript-heavy site that times out; Linkwarden logs these errors and marks the link accordingly rather than silently dropping it.

Keeping the instance updated is a matter of pulling the latest image and restarting the stack. Run docker compose pull followed by docker compose up -d, and the migration system handles any database schema changes automatically. Your .env file and mounted volumes carry over untouched. The Linkwarden project moves quickly – new features and bug fixes ship on a regular basis – so checking the GitHub releases page every few weeks is worth the habit, particularly before any major version jump.





