linXivlinXiv

Self-hosting

linXiv runs on hardware you own: a personal laptop, a lab workstation, or a server your group controls. There is no mandatory hosted service: install the app and your library lives entirely on that machine.

Where your data lives

Everything (papers, notes, tags, annotations) lives in one SQLite file, papers.db, plus a PDF directory:

  • Linux: ~/.local/share/com.linxiv.app
  • macOS: ~/Library/Application Support/com.linxiv.app
  • Windows: %APPDATA%\com.linxiv.app

Set LINXIV_DATA_DIR to point linXiv at a different location instead: a synced folder, an external drive, or a path on a shared machine.

Back it up

Because everything is a local SQLite file plus a PDF directory, backup and migration are ordinary file operations: stop the app and copy the data directory. Before upgrading to a new release, copying papers.db out first costs nothing and saves a library if a migration goes wrong. Export projects to Obsidian, BibTeX, or shareable .lxproj bundles whenever you need to move data out entirely.

Sharing a project without a server

Projects can be shared directly with another person over a peer-to-peer connection (via iroh), without running a relay server or account. You're either the Hoster of a share or a Reader of one; a Hoster invites members as Editor or Viewer, and write access is enforced host-side. Sync uses end-to-end encrypted CRDTs, so edits merge instead of overwriting each other. Find it under Shared in the app.

By default, connections go through iroh's public discovery and relay infrastructure to find each other. You don't run that server, and since v0.5.1 you can also point sharing at a relay you control (see below).

Sharing a project with a simple server

Since v0.5.1, linxiv-headless is the whole linXiv backend without a window: the complete /api/* router over HTTP (share routes included), the iroh peer, and background sync. Run it on a box or in a container as an always-on node that keeps a shared project available even when your laptop is closed. It uses the same on-disk layout as the desktop app, CLI, and MCP server, and prebuilt images publish to GHCR on every release: no registry login needed.

Without a relay node

The simplest setup: the node connects through iroh's public discovery and relay infrastructure, so there is nothing to configure beyond the node itself.

# 1. Pull the image (tags are unprefixed: 0.5.1, or latest for the newest stable)
podman pull ghcr.io/linxiv-dev/linxiv-headless:0.5.1

# 2. Start the node with an API token and a persistent data volume
export LINXIV_API_TOKEN="$(openssl rand -hex 32)"
podman run -d --name linxiv \
  -e LINXIV_API_TOKEN \
  -e LINXIV_P2P_PASSPHRASE=change-me \
  -p 127.0.0.1:8000:8000 \
  -v linxiv-data:/data \
  ghcr.io/linxiv-dev/linxiv-headless:0.5.1

# 3. Verify it's up
curl -H "Authorization: Bearer $LINXIV_API_TOKEN" http://127.0.0.1:8000/api/status

The node fails closed: a non-loopback bind without LINXIV_API_TOKEN refuses to start, and authenticated requests use the bearer token. docker works the same as podman, and there is a compose file in docs/headless that wires the token, volume, and healthcheck in one step. From here, invite the node to a shared project (or host one from it) exactly like any other member.

With a relay node

To keep sharing traffic on infrastructure you control, point the node at your own relay. Relay settings are the same on-disk user settings as the app (p2p_relay_url, p2p_relay_auth_token, p2p_relay_only):

# 1. Start the node as above, then set the relay
curl -X PATCH http://127.0.0.1:8000/api/settings \
  -H "Authorization: Bearer $LINXIV_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"p2p_relay_url": "https://relay.example.org", "p2p_relay_only": true}'

# 2. Rebind to the relay without a restart
curl -X POST http://127.0.0.1:8000/api/share/relay/reconnect \
  -H "Authorization: Bearer $LINXIV_API_TOKEN"

Once a relay is configured, the admin page at /admin mints a copyable Node Address, manages the Remote Query Mode member list (members query the node directly, gated by their role), and shows the relay access and PDF transfer logs.

One rule either way: the library is single-writer. Never point two running nodes, or a node and the desktop app, at the same data directory; one node per data dir.