Skip to main content
  1. Posts/
  2. Self-Hosting/

Trilium — installing and setting up a note-taking system

··1994 words·10 mins· loading · loading · ·
Stilicho2011
Author
Stilicho2011
Writing about homelab, self-hosting, automation and open-source solutions
Table of Contents
Self-Hosting - This article is part of a series.
Part : This Article

Trilium - a powerful personal knowledge system under your control
#

Introduction: why you need Trilium - and why you need PKM tools at all
#

In an age of information overload, we suffer not so much from a lack of knowledge as from the sheer volume of information that piles up on us every day, and from the chaos that this volume creates: scattered ideas, lost connections, forgotten context, and other horrors of digitalization. Not to mention attempts to manipulate you by telling you that your brain wasn’t made to hold anything in memory - as if you were some kind of computer with a limited amount of RAM. (Spoiler, spoiler - that’s not true.) Tools exist to solve this problem, and the community has affectionately dubbed them Personal Knowledge Management (PKM) systems - personal knowledge bases.

Trilium interface: demo note tree with formatting examples

Such systems let you:

  • collect scattered notes, ideas, links, and drafts in one place;
  • integrate different formats (text, images, diagrams, tables, code) in a single database;
  • find connections between notes via links, graphs, search, and attributes;
  • grow knowledge - not just record facts, but connect, deepen, and reassemble them;
  • export / back up - so you don’t depend on someone else’s cloud.

Classic tools like Obsidian or Notion give you either a “file-based” approach (Markdown + plugins, as with Obsidian) or a cloud ecosystem with limitations. Given everything that’s happened recently, being cloud-based is itself a limitation - arguably even a barrier by now. Obsidian, Notion, and Joplin are all good, but Trilium goes further, offering a hybrid approach: a powerful tree structure, database flexibility, and the privacy of a self-hosted solution. That said, keep in mind that Obsidian and Notion aren’t open-source, and while Joplin is popular, it’s also far from perfect.

The hero of today’s article, Trilium, is an actively community-developed successor to the original project started by developer zadam. For a while the community fork lived under the name TriliumNext, but in 2025 the author handed the original repository and name back to it - so it’s simply Trilium again, not a fork.

Trilium is also not “just notes” - it’s a system in which a note is a data object with fields, templates, relations, attributes, and visual interfaces. When your database grows to hundreds or thousands of notes, that difference becomes especially noticeable.

What Trilium is: a brief overview of version 0.104.1 (the current version as of this article’s update date)
#

Trilium’s main features:
#

For more information about Trilium, you can also read:

Note Map of the Trilium demo database - visualization of connections between notes

Trilium turns notes into data objects - each entry can have attributes, relations, a template, and visualizations. This makes the system feel closer to a knowledge base than a simple set of files.

-–

Installing and configuring Trilium
#

Below is my docker-compose file, assuming I’m using the Traefik reverse proxy

services:
  trilium:                                # Define a service named "trilium"
    container_name: trilium               # Docker container name (for convenience)
    image: triliumnext/trilium:v0.104.1   # Official Trilium image, pinning a specific version. Don't use latest - the official docs explicitly warn that the tag can silently bump the minor version and break sync
    restart: always                       # The container will restart automatically on failure or Docker reboot
    environment:                          # Environment variables passed into the container
      TRILIUM_NETWORK_TRUSTEDREVERSEPROXY: 172.18.0.0/16 # Trusted network for the reverse proxy
      TRILIUM_DATA_DIR: /home/node/trilium-data   # Path to the directory where Trilium stores its data inside the container
      TZ: ${TZ}                                   # Set the timezone from an environment variable (usually defined in .env)
      TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHBASEURL: "https://trilium.domain.ru"  
        # Base URL for OIDC callbacks (Trilium needs to know its public address)
      TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHCLIENTID: ${TRILIUM_CLIENT_ID}  
        # OAuth client ID (taken from .env or a secret)
      TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHCLIENTSECRET: ${TRILIUM_CLIENT_SECRET}  
        # OAuth client secret (also from .env)
      TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERBASEURL: "https://auth.domain.ru/application/o/trilium"  
        # Identity Provider address (Authentik in this case)
      TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERNAME: "Authentik"  
        # Name of the auth provider shown in the Trilium UI
      TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERICON: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/authentik.svg"  
        # Auth provider icon (a nice UI touch)
    volumes:                              # Mount local directories into the container
      - /home/user/docker/trilium:/home/node/trilium-data  
        # Main data volume (replaces Trilium's built-in directory)
      # If you want the container to inherit the system timezone, uncomment:
      # - /etc/localtime:/etc/localtime:ro
        # Mount the system's local time into the container (read-only)
    networks:
      proxy:                              # Attach the container to the external "proxy" network (used by Traefik)
    labels:                               # Labels for Traefik integration (reverse proxy)
      - "traefik.enable=true"                                      # Enable Traefik processing for the container
      - "traefik.http.routers.trilium.entrypoints=web"             # Define the HTTP entrypoint (port 80)
      - "traefik.http.routers.trilium.rule=Host(`trilium.domain.ru`)" # Traffic to this domain is routed to this container
      - "traefik.http.middlewares.trilium-https-redirect.redirectscheme.scheme=https" # Middleware to redirect HTTP to HTTPS
      - "traefik.http.routers.trilium.middlewares=trilium-https-redirect" # Apply the redirect middleware to the HTTP route
      - "traefik.http.routers.trilium-secure.entrypoints=websecure" # Define the HTTPS entrypoint (port 443)
      - "traefik.http.routers.trilium-secure.rule=Host(`trilium.domain.ru`)" # HTTPS route for the same domain
      - "traefik.http.routers.trilium-secure.tls=true" # Enable TLS (HTTPS)
      - "traefik.http.routers.trilium-secure.service=trilium" # Bind the HTTPS route to the Trilium service
      - "traefik.http.services.trilium.loadbalancer.server.port=8080" # Specify the internal port Trilium listens on in the container
      - "traefik.docker.network=proxy" # Tell Traefik to look for the container in the "proxy" network

networks:
  proxy:                                  # Definition of the external network for talking to Traefik
    external: true                        # The network was already created earlier (don't recreate)

and also the variables file

# Timezone
TZ=Europe/Moscow
# OAuth2 (Authentik)
TRILIUM_CLIENT_ID=client-id
TRILIUM_CLIENT_SECRET=client-secret
Note

Trilium is also supported on Kubernetes, via Cloudron, HomelabOS, a NixOS module, and others.

Keep in mind that Traefik versions 3.6.4 and above had some minor breaking changes. If you use Traefik as your reverse proxy, you need to add the following block to your static configuration file

  websecure:                              # Entrypoint for HTTPS (port 443)
    address: ":443"                       # Listen on port 443
    http:                                 # HTTP settings for HTTPS
      encodedCharacters:                  # Allowed encoded characters (important for Trilium)
        allowEncodedSlash: true           # Allow %2F
        allowEncodedPercent: true         # Allow %25
        allowEncodedHash: true            # Allow %23

Configuration location
#

By default, config.ini, the database, and other important Trilium files are stored in the data directory. If you want to use a different location, you can set the TRILIUM_DATA_DIR environment variable, for example:

export TRILIUM_DATA_DIR=/home/myuser/data/my-trilium-data

Disabling / changing the upload limit
#

If you run into the default 250 MB upload limit and want to raise it, you can set the TRILIUM_NO_UPLOAD_LIMIT=true environment variable to disable the limit entirely:

export TRILIUM_NO_UPLOAD_LIMIT=true

Or, if you just want to raise the limit to something bigger than 250 MB, you can use the MAX_ALLOWED_FILE_SIZE_MB variable, for example:

export MAX_ALLOWED_FILE_SIZE_MB=450

Synchronization
#

Trilium is an “offline-first” note-taking app: it stores all data locally on the desktop client, or on the so-called server installation described above. However, Trilium also lets you set up synchronization with a server instance, allowing multiple desktop clients to sync with a central server and vice versa. This creates a “star” topology. More details are in the synchronization documentation

Diagram of Trilium’s “star” sync topology: sync server and multiple clients

In this configuration, a central server (called the sync server) and several client (or desktop) instances synchronize with the sync server. Once configured, synchronization becomes automatic and continuous, requiring no manual intervention.

Note! Obsidian? Never heard of it

Setting up synchronization
#

Security considerations
#

Secure server setup is critically important and may seem complicated at first. To ensure security and prevent potential vulnerabilities, it’s important to use a valid SSL certificate (HTTPS) rather than an unencrypted HTTP connection.

Syncing a desktop instance with the sync server
#

This method is used when you already have a desktop instance of Trilium and want to set up a sync server on your web hosting or simply on a Docker machine.

  1. Deploy the server: make sure the server instance is deployed but not initialized.
  2. Desktop configuration: open the desktop instance, go to “Options” -> the “Sync” tab -> “Sync Configuration,” and enter your sync server’s address in the “Server instance address” field. Click “Save.”
Sync tab in Trilium settings - entering the sync server address

3. Testing the sync: click the “Test Sync” button to check the connection to the sync server. On success, the client will start transferring all data to the server. This may take a while, but you can keep using Trilium in the meantime. Periodically check the server to confirm sync has completed. Once done, you’ll see the server login screen.

Syncing the sync server with a desktop app instance
#

This method is used when you already have a sync server (our instance, set up in our homelab) and want to configure a new desktop instance to sync with it.

  1. Desktop setup: follow the instructions on the desktop installation page.
  2. Initial configuration: when prompted, choose the option to sync with the sync server.
Initial setup screen of desktop Trilium: sync with server
  1. Server details: configure the Trilium server address and enter the correct username and password for authentication.
  2. Finish setup: click “Finish Setup.” On success, you’ll see the following screen:
Sync startup screen after finishing server setup

Mobile frontend
#

Trilium (server version) has a mobile web interface optimized for touch devices - smartphones and tablets. It activates automatically upon login, based on browser detection.

The mobile interface has limited functionality compared to the full-featured desktop interface.

Note that this isn’t an Android/iOS app, just a mobile-friendly web page hosted on the server.

Limitations
#

The mobile interface provides only some of the full desktop interface’s features:

  • you can browse the entire note tree, read and edit all note types, but can only create text notes
  • reading and editing protected notes is possible, but creating them is not supported
  • editing options are not supported
  • note cloning is not supported
  • uploading attachments is not supported

Web clipper
#

Trilium Web Clipper browser extension popup

Trilium Web Clipper is a browser extension that lets you clip text, screenshots, entire pages, and short notes and save them directly into Trilium Notes.

The project is hosted here.

Firefox and Chrome are supported, but the Chrome build should also work in other Chromium-based browsers.

I use this version

Functionality
#

  • select text and clip it via the right-click context menu
  • click an image or link and save it via the context menu
  • save an entire page from the popup or context menu
  • save a screenshot (with a crop tool) from the popup or context menu
  • create a short text note from the popup

Trilium will save these clippings as a new child note under the “Clipper Inbox” note.

By default this is a day note, but you can override this.

If there are multiple clippings from the same page (and on the same day), they’ll be added to the same note.

Configuration
#

The extension needs to connect to a running Trilium instance. By default it scans a port range on the local machine to find a Trilium desktop instance.

You can also configure the server address if you’re not running the desktop app, or want it to work without the desktop app running.

Since this article has already gotten quite long, I’ll probably continue covering the app’s features in a separate article.

Self-Hosting - This article is part of a series.
Part : This Article

Related