> ## Content Index
> Fetch the complete content index at: https://blog.uptime.bet/llms.txt
> Use this file to discover other available public pages before exploring further.

# Linkwarden: Self-Host a Bookmark Manager That Saves a Copy of Every Page (Docker Compose Guide)
- URL: https://blog.uptime.bet/linkwarden-self-hosted-bookmark-manager-docker/
- Published: 2026-11-08T08:00:00.000Z
- Updated: 2026-11-08T08:00:00.000Z
- Description: Linkwarden is an AGPL-licensed, self-hosted bookmark manager that stores a screenshot, PDF, HTML snapshot and readable copy of every link you save, so link rot can't take it away. Here is how to run v2.16.3 with Docker Compose, plus tips for keeping it light.
- Author: Alexandre Nebeling
- Tags: Trending, Self-Hosted, Open Source, Docker, Homelab, Productivity

You find a great write-up, bookmark it, and two years later the link returns a 404, a cookie wall, or a domain parked by someone selling crypto. Link rot is real, and a plain list of URLs in your browser does nothing against it.

**Linkwarden** tackles exactly that. It is a self-hosted, collaborative bookmark manager that doesn't just store the address: it saves a **screenshot, a PDF, a single-file HTML snapshot and a readable text version** of every page you add. With roughly **20,000 GitHub stars**, an **AGPL-3.0** license and a steady release pace (the latest release is **v2.16.3** from September 2026, with commits as recently as late October), it is one of the most popular tools in its category.

In this guide I'll cover what Linkwarden does, how to run it with Docker Compose, which settings are worth changing, and where its limits are.

## What is Linkwarden?

[Linkwarden](https://github.com/linkwarden/linkwarden?ref=blog.uptime.bet) describes itself as a tool to "collect, read, annotate, and fully preserve" web content. In practice it sits somewhere between three kinds of apps:

- a **bookmark manager** with collections, sub-collections and tags,
- a **read-it-later app** with a reader view, highlights and annotations,
- a lightweight **web archive** that keeps local copies of each page.

It is built with Next.js, uses **PostgreSQL** as its database and **Meilisearch** for full-text search. A background worker drives a headless browser to capture pages, and uses the Rust tool Monolith for single-file HTML snapshots. There is also a paid cloud offering from the developers, but every core feature is available when you self-host.

## Key features

According to the project README and docs, Linkwarden offers:

- **Automatic preservation**: screenshot, PDF and single-file HTML of each saved page, plus a readable version.
- **Reader view with highlights and annotations.**
- **Optional Wayback Machine submission**, so archive.org gets a snapshot too.
- **Collections, sub-collections and tags**, with custom icons.
- **Collaboration**: share collections with other users and set per-member permissions, or share links publicly.
- **Full-text search**, filtering and sorting.
- **AI tagging (optional)** with a local Ollama model or any OpenAI-compatible API.
- **RSS subscriptions** that drop new items into a collection.
- **Browser extension**, browser bookmark sync via [Floccus](https://floccus.org/?ref=blog.uptime.bet), and uploads from the SingleFile extension.
- **Official iOS and Android apps**, plus an iOS Shortcut.
- **SSO** with a long list of providers (including Authelia, Authentik, Keycloak and Zitadel), **API keys**, bulk actions, user administration and i18n.
- **Image and PDF uploads**, and optional **S3-compatible storage** instead of local disk.

![Linkwarden mobile app screens on a tablet and two phones](https://blog.uptime.bet/content/images/2026/11/linkwarden-mobile.webp)

Linkwarden's official mobile apps on iPad, Pixel and iPhone. [Source: linkwarden/linkwarden on GitHub](https://github.com/linkwarden/linkwarden?ref=blog.uptime.bet) (AGPL-3.0)

## Why self-host it?

Bookmarks are a surprisingly personal dataset: they show what you read, research and care about. Running Linkwarden yourself keeps that data on your hardware, lets you share collections with family or a small team without per-seat pricing, and, most importantly, keeps the **preserved copies** under your control. If a site disappears, your snapshot doesn't.

## Hardware requirements

The official setup docs call **4 GB of RAM** a comfortable starting point, and any **2-core CPU** is enough. Images are published for **x86-64 and ARM64**, and the Docker image needs about **1.5 GB** of disk plus your data. The docs also note that since **v2.15** idle memory dropped to roughly 350 MB, down from around 700 MB in older versions.

Keep in mind that preserved pages add up: PDFs and full HTML snapshots of image-heavy sites can be several megabytes each.

## Installing Linkwarden with Docker Compose

### 1\. Create a folder and get the official files

```bash
mkdir linkwarden && cd linkwarden
curl -O https://raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml
curl -L https://raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env"

```

### 2\. Review the Compose file

The official `docker-compose.yml` starts three services: PostgreSQL 16, Linkwarden itself and Meilisearch. Below is the same file with two small changes I recommend for a server: the Linkwarden image is **pinned to a release tag** instead of `latest` (so updates happen when you decide), and port 3000 is **bound to localhost only**, because you'll put a reverse proxy in front anyway.

```yaml
services:
  postgres:
    image: postgres:16-alpine
    env_file: .env
    restart: always
    volumes:
      - ./pgdata:/var/lib/postgresql/data

  linkwarden:
    image: ghcr.io/linkwarden/linkwarden:v2.16.3
    env_file: .env
    environment:
      - DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres
    restart: always
    ports:
      - 127.0.0.1:3000:3000
    volumes:
      - ./data:/data/data
    depends_on:
      - postgres
      - meilisearch

  meilisearch:
    image: getmeili/meilisearch:v1.13.3
    restart: always
    env_file: .env
    volumes:
      - ./meili_data:/meili_data

```

If you don't use a reverse proxy and want to reach it from your LAN directly, keep the original `3000:3000` mapping.

### 3\. Set the required environment variables

Open `.env`. The docs list four required values; the three secrets must be different from each other:

```bash
NEXTAUTH_URL=http://localhost:3000/api/v1/auth
NEXTAUTH_SECRET=change-me-long-random-value
MEILI_MASTER_KEY=change-me-another-long-random-value
POSTGRES_PASSWORD=change-me-a-third-random-value

```

You can generate random values with:

```bash
openssl rand -base64 32

```

Wrap a value in quotes if it contains special characters. `MEILI_HOST` defaults to `http://meilisearch:7700`, which matches the Compose service name, so you don't need to set it.

### 4\. Start the stack

```bash
docker compose up -d
docker compose logs -f linkwarden

```

On first start the container runs its database migrations and then launches the web app and the worker. After a few minutes, open `http://localhost:3000` and create your account. The first user (ID 1) is treated as the server administrator by default (`NEXT_PUBLIC_ADMIN=1`).

## Putting it behind a reverse proxy

Once you publish Linkwarden on a real hostname such as `links.example.com`, update two variables in `.env` and restart:

```bash
NEXTAUTH_URL=https://links.example.com/api/v1/auth
BASE_URL=https://links.example.com

```

`NEXTAUTH_URL` must keep the `/api/v1/auth` suffix, otherwise sign-in and OAuth callbacks break. The official reverse-proxy guide uses NGINX and Certbot; Traefik, Caddy or Nginx Proxy Manager work the same way as long as they forward to port 3000 and pass WebSocket upgrade headers.

```bash
docker compose down
docker compose up -d

```

## Configuration tips

**Close registration after creating your accounts.** On an internet-facing instance you probably don't want strangers signing up:

```bash
NEXT_PUBLIC_DISABLE_REGISTRATION=true

```

**Use SSO if you already run an identity provider.** The `.env.sample` contains blocks for many providers, for example `NEXT_PUBLIC_AUTHENTIK_ENABLED`, `NEXT_PUBLIC_AUTHELIA_ENABLED` and `NEXT_PUBLIC_KEYCLOAK_ENABLED`. With `DISABLE_NEW_SSO_USERS=true` you can block first-time SSO logins while letting already linked accounts in, and `NEXT_PUBLIC_CREDENTIALS_ENABLED=false` turns off password login entirely.

**Add AI tagging with a local model.** Point Linkwarden at an Ollama instance; the docs say a small model like `phi3:mini-4k` is enough:

```bash
NEXT_PUBLIC_OLLAMA_ENDPOINT_URL=http://ollama:11434
OLLAMA_MODEL=phi3:mini-4k

```

(Use the hostname under which Ollama is reachable from the Linkwarden container.) OpenAI-compatible APIs work too via `OPENAI_API_KEY`, `OPENAI_MODEL` and optionally `CUSTOM_OPENAI_BASE_URL`.

**Run the containers as a non-root user.** Support for this arrived in v2.16.1, and the docs have a dedicated guide. For a new install, create the folders yourself *before* the first start and add a `user:` line to every service:

```bash
mkdir -p data pgdata meili_data

```

```yaml
services:
  linkwarden:
    user: "1000:1000"
  postgres:
    user: "1000:1000"
  meilisearch:
    user: "1000:1000"

```

Use the output of `id -u` and `id -g` if your user isn't 1000\. For an existing install, stop the stack and `chown -R` the three folders once.

**Make it lighter on small hardware.** The "Running a Lighter Setup" page explains the trade-offs:

- Disable preserved formats you don't need under **Settings, Preferences, Archive Settings**. Monolith and PDF are the most expensive, readable text is the cheapest (and is what search and highlights rely on).
- `DISABLE_BROWSER=true` skips every browser-based task. You keep bookmarks, tags, collections, sharing and search over titles, URLs and descriptions, but lose screenshots, PDFs, snapshots, reader view and previews.
- Let your own browser do the work: the browser extension can upload a screenshot it captured locally, and SingleFile can upload a complete HTML snapshot. That also covers pages behind a login.

## Backups and updates

Everything lives in three folders next to your Compose file: `data` (preserved files and uploads), `pgdata` (PostgreSQL) and `meili_data` (search index, which can be rebuilt). For consistent database backups, dump PostgreSQL instead of copying the live folder:

```bash
docker compose exec -T postgres pg_dump -U postgres postgres > linkwarden-$(date +%F).sql

```

Back up `data` alongside the dump. If you want to know when a nightly backup job silently stops, pair it with [Healthchecks](https://blog.uptime.bet/healthchecks-self-hosted-cron-job-monitoring-docker/).

To update, read the [release notes](https://github.com/linkwarden/linkwarden/releases?ref=blog.uptime.bet), change the image tag, then:

```bash
docker compose pull
docker compose up -d

```

Migrations run automatically on start.

## Limitations and honest notes

- **Preservation costs resources.** A headless browser, a Rust archiver, a search engine and a database are more than a simple bookmark list needs. If you only want links and tags, `DISABLE_BROWSER=true` or a lighter tool may suit you better.
- **Some sites resist automated capture.** Login walls, bot protection and heavy cookie banners can produce poor snapshots. Uploading from your own browser is the documented workaround.
- **The Meilisearch version is pinned** in the official Compose file. Don't bump it on your own without checking Linkwarden's file first, since Meilisearch indexes aren't always compatible across versions.
- **Releases have slowed a bit**: v2.16.3 from 9 September 2026 is still the latest release, although the main branch received fixes in October.
- **AGPL-3.0** means that if you modify Linkwarden and offer it to others over a network, you have to share your changes. For personal and homelab use that doesn't change anything.

## Linkwarden vs. Karakeep vs. ArchiveBox

All three are open source and self-hostable, but they focus on different things:

|               | Linkwarden                                     | Karakeep                                                         | ArchiveBox         |
| ------------- | ---------------------------------------------- | ---------------------------------------------------------------- | ------------------ |
| Main focus    | Collaborative bookmarks with preservation      | "Bookmark everything" app (links, notes, images) with AI tagging | Full web archiving |
| Collaboration | Shared collections with per-member permissions | Collaborative lists                                              | Not the focus      |
| Mobile apps   | Official iOS and Android                       | iOS and Android                                                  | No official app    |
| License       | AGPL-3.0                                       | AGPL-3.0                                                         | MIT                |

If you mainly want to archive pages in many formats for the long term, [ArchiveBox](https://blog.uptime.bet/archivebox-self-hosted-web-archive-docker/) is the specialist. If you want a personal "save everything" inbox with notes and images, take a look at our [Karakeep guide](https://blog.uptime.bet/karakeep-self-hosted-bookmark-manager-docker/). Linkwarden sits in the middle and is the strongest choice when you want to **share and organize** collections with others while still keeping a copy of every page.

Since Linkwarden can subscribe to RSS feeds, it also pairs nicely with a feed reader like [CommaFeed](https://blog.uptime.bet/commafeed-self-hosted-rss-reader-docker/): read in the reader, keep the good stuff in Linkwarden.

## Conclusion

Linkwarden turns bookmarks from a fragile list of URLs into a searchable, shareable library that survives link rot. The Docker Compose setup takes a few minutes, the docs are thorough (including non-root and low-resource guides), and features like the mobile apps, SSO and local AI tagging make it feel complete. Just plan for the storage and memory that preservation needs, and switch off the formats you don't use.

Do you already archive your bookmarks, or do you still trust the Wayback Machine to have a copy when you need it? If you've never tried preserving pages yourself, Linkwarden is an easy place to start.

## Sources

- [Linkwarden on GitHub](https://github.com/linkwarden/linkwarden?ref=blog.uptime.bet) (README, license, Compose file, `.env.sample`)
- [Linkwarden releases](https://github.com/linkwarden/linkwarden/releases?ref=blog.uptime.bet)
- [Docs: Setup](https://docs.linkwarden.app/self-hosting/setup?ref=blog.uptime.bet)
- [Docs: Environment Variables](https://docs.linkwarden.app/self-hosting/environment-variables?ref=blog.uptime.bet)
- [Docs: AI Tagging](https://docs.linkwarden.app/self-hosting/ai-worker?ref=blog.uptime.bet)
- [Docs: Reverse Proxy](https://docs.linkwarden.app/self-hosting/reverse-proxy?ref=blog.uptime.bet)
- [Docs: Running as a Non-Root User](https://docs.linkwarden.app/self-hosting/non-root?ref=blog.uptime.bet)
- [Docs: Running a Lighter Setup](https://docs.linkwarden.app/self-hosting/lighter-setup?ref=blog.uptime.bet)