How to Install Trilium Notes on Ubuntu 24.04 — Self-Hosted Personal Knowledge Base
Your personal notes, research, and half-finished ideas are some of the most valuable data you own. Handing them to Notion, Evernote, or Google Keep means trusting a third party with your thinking — and betting that they stay in business, honor their privacy promises, and do not quietly change terms next quarter. Trilium Notes flips the relationship. You host it on your own VPS, the database sits on your disk, and the desktop client syncs back to a server you control. This guide walks through a production-ready Trilium deployment on Ubuntu 24.04 with Docker, a Nginx reverse proxy, Let's Encrypt TLS, and desktop client sync.
Need a reliable VPS first? Our Starter VPS plan comes with 2 vCPU, 4 GB RAM, and NVMe storage — more than enough for Trilium plus a few other self-hosted tools.
Table of Contents
What is Trilium Notes?
Trilium Notes is an open-source hierarchical note-taking application built for serious knowledge workers, researchers, and anyone who has outgrown flat-file markdown editors. Rather than a folder of .md files, Trilium stores everything in a single SQLite database and organizes notes as a tree — with the twist that any note can appear in multiple places (clones), and notes can link to each other both as children and as semantic relations.
Under the hood Trilium is a Node.js server that exposes a web UI on port 8080 and a sync API that desktop clients connect to. The server persists notes, attachments, revisions, and backup snapshots under a single data directory controlled by the TRILIUM_DATA_DIR environment variable. This single-directory design makes backup, restore, and migration trivial — you copy one folder and the whole knowledge base travels with you.
Trilium's feature set is unusually deep for a self-hosted notes app. You get a rich WYSIWYG editor with math support (KaTeX), code blocks with syntax highlighting, Excalidraw-style drawings, mermaid diagrams, file attachments, and a full-text search that indexes every note instantly. More advanced capabilities include relation maps (visualize links between notes), scripting (write JavaScript inside a note to query the database, build dashboards, or automate workflows), promoted attributes (turn notes into typed database rows), per-note encryption with client-side keys, and note revisions (automatic versioning of every edit). It is, effectively, a personal Notion that you own outright.
The project by Zadam has been widely adopted for personal wikis, research vaults, journaling, project management, and second-brain systems. In 2024 the community forked active development into TriliumNext (still published under the original Docker image family), which continues shipping improvements while preserving compatibility with existing databases.
Why Self-Host Your Knowledge Base Instead of Using Notion or Evernote?
Handing your notes to a SaaS provider is convenient until it is not. Here is the honest case for self-hosting:
- Your data is actually yours — With Notion, Evernote, or Google Keep, your notes live on servers you cannot audit, encrypted with keys you do not hold, under terms that can change at any time. With Trilium on your VPS, the SQLite file sits on your disk. You can inspect it, copy it, encrypt it, or delete it. No one else has a copy.
- No subscription creep — Notion's Plus plan is USD 10/user/month. Evernote Personal is USD 14.99/month. Multiply by years. A Starter VPS at roughly EUR 7.99/month hosts Trilium plus a dozen other self-hosted tools, with no per-user fees and no quota meter.
- No vendor lock-in — Trilium exports to HTML, Markdown, or a portable
.zipof the entire tree. Your notes are not trapped in a proprietary cloud format. Migration away is a single command. - Works offline and on slow links — The desktop client holds a full local database. You can write 500 notes on a plane and sync them later. SaaS web apps degrade badly on poor connectivity.
- Genuine privacy, not marketing privacy — Cloud providers regularly update privacy policies, train AI on user content, or respond to government requests. A Trilium instance on your VPS has none of that exposure. Per-note encryption adds a second layer even against a server compromise.
- Performance that scales with your hardware — Notion becomes noticeably sluggish past a few thousand notes. Trilium's SQLite backend handles tens of thousands of notes on modest hardware without pagination or loading spinners.
- Extensible by default — Scripting, custom CSS, import/export, REST API, and a stable data format mean you can bend Trilium to your workflow instead of waiting for a product team to ship a feature.
Cost Comparison Over 3 Years
| Service | Monthly Cost | 3-Year Cost | Data Ownership | Export Quality |
|---|---|---|---|---|
| Notion Plus | USD 10 | USD 360 | Cloud-only | Markdown (imperfect) |
| Evernote Personal | USD 14.99 | USD 539 | Cloud-only | ENEX (proprietary) |
| Obsidian Sync | USD 10 | USD 360 | Local files + cloud sync | Native Markdown |
| Trilium on Starter VPS | EUR 7.99 | EUR 180 | Full — your disk | HTML / Markdown / ZIP |
Prerequisites
Before you begin, make sure you have:
- A VPS running Ubuntu 24.04 LTS with root or sudo access
- SSH access to your server
- A registered domain name pointed at your VPS IP (for TLS)
- At least 1 GB of RAM (2 GB recommended for comfortable multi-device sync)
- 10 GB of free disk space (Trilium itself is tiny; attachments grow with use)
Recommended Plan: Starter VPS>
Trilium is lightweight, but a good foundation matters for reliability. Our Starter VPS is ideal:>
- 2 vCPU cores
- 4 GB RAM
- 50 GB NVMe SSD
- Unmetered bandwidth
- From EUR 7.99/month>
Plenty of headroom for Trilium plus Nginx, backups, and a handful of other small services.
Connect to your server via SSH:
ssh root@your-server-ipPoint an A record for notes.yourdomain.com at your server's IP before proceeding. TLS issuance in Step 7 depends on DNS resolving correctly.
Step 1: Update System Packages
Refresh the package index and upgrade installed packages:
sudo apt update && sudo apt upgrade -yIf a new kernel was installed, reboot before continuing:
sudo rebootReconnect via SSH once the server is back up.
Step 2: Install Docker
Trilium ships an official Docker image, which is the cleanest way to run it on Ubuntu 24.04. Install Docker Engine from Docker's official apt repository.
Install prerequisites:
sudo apt install -y ca-certificates curl gnupgAdd Docker's official GPG key and repository:
sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc
echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Install Docker Engine:
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-pluginVerify Docker is running:
sudo systemctl status dockerExpected output includes Active: active (running).
Step 3: Create the Persistent Data Volume
Trilium stores its notes database, attachments, backups, and configuration in a single directory. We mount that directory from the host so container restarts and image upgrades never lose data.
Create the host directory:
sudo mkdir -p /var/lib/trilium-data
sudo chown -R 1000:1000 /var/lib/trilium-dataThe 1000:1000 ownership matches the node user inside the official Trilium image. Getting this right prevents the permission errors that are the number one cause of failed first-time starts.
Step 4: Run the Trilium Server Container
Launch the trilium-server container with the data directory mounted and the TRILIUM_DATA_DIR environment variable pointed at it:
sudo docker run -d \
--name trilium \
--restart unless-stopped \
-p 127.0.0.1:8080:8080 \
-v /var/lib/trilium-data:/home/node/trilium-data \
-e TRILIUM_DATA_DIR=/home/node/trilium-data \
-e TZ=UTC \
zadam/trilium:latestWhat each flag does:
--name trilium— friendly name for futuredocker logs triliumanddocker restart trilium.--restart unless-stopped— container auto-starts on reboot and restarts on crash.-p 127.0.0.1:8080:8080— binds port 8080 to the loopback interface only. Nginx will front it; the world never talks to Trilium directly.-v /var/lib/trilium-data:/home/node/trilium-data— persists the notes database on the host.-e TRILIUM_DATA_DIR=/home/node/trilium-data— tells the Trilium process where to read and write data inside the container.-e TZ=UTC— timestamps in note revisions and backups use UTC. Change if you prefer local time.
sudo docker logs -f triliumExpected output (abbreviated):
Starting Trilium...
App data path: /home/node/trilium-data
DB not initialized, initializing...
Schema version 228
Listening on port 8080Press Ctrl+C to stop tailing the logs. The container keeps running.
Step 5: Verify the Installation
Confirm the container is healthy:
sudo docker ps --filter name=triliumExpected output:
CONTAINER ID IMAGE STATUS PORTS NAMES
a1b2c3d4e5f6 zadam/trilium:latest Up 2 minutes 127.0.0.1:8080->8080/tcp triliumTest the local endpoint responds:
curl -I http://127.0.0.1:8080Expected output:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8Inspect the data directory to confirm Trilium is writing to it:
sudo ls -la /var/lib/trilium-dataYou should see document.db, log/, backup/, and a config.ini file.
Step 6: Configure Nginx as a Reverse Proxy
Exposing a Node.js app directly on port 80 is fine in dev; in production Nginx handles TLS, compression, WebSocket upgrades, rate limiting, and graceful restarts. Trilium's sync protocol also uses WebSockets for live updates, so the proxy must pass the upgrade headers correctly.
Install Nginx:
sudo apt install -y nginxCreate the site config:
sudo tee /etc/nginx/sites-available/trilium > /dev/null <<'EOF' server { listen 80; server_name notes.yourdomain.com;# Trilium supports large attachments; lift the upload cap. client_max_body_size 250m;
location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support for live sync. proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";
proxy_read_timeout 600s; proxy_send_timeout 600s; } } EOF
Replace notes.yourdomain.com with your actual hostname.
Enable the site and reload:
sudo ln -s /etc/nginx/sites-available/trilium /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginxOpen ports 80 and 443 on the firewall if UFW is active:
sudo ufw allow 'Nginx Full'Visit http://notes.yourdomain.com in a browser. You should see the Trilium setup screen. Do not complete setup yet — finish TLS first.
Step 7: Enable TLS with Let's Encrypt
Install Certbot:
sudo apt install -y certbot python3-certbot-nginxIssue a certificate and let Certbot rewrite the Nginx config for HTTPS:
sudo certbot --nginx -d notes.yourdomain.comWhen prompted:
- Enter an email address for expiry notifications.
- Agree to the terms.
- Choose option
2to redirect all HTTP traffic to HTTPS.
sudo certbot renew --dry-runExpected output ends with Congratulations, all simulated renewals succeeded.
Reload Nginx to be safe:
sudo systemctl reload nginxYour Trilium instance is now reachable at https://notes.yourdomain.com with a valid TLS certificate.
Step 8: Complete First-Time Setup in the Browser
Open https://notes.yourdomain.com and choose "New document" if this is a fresh install (choose "Sync from server" only if you are migrating an existing database).
Set:
- Username — for the web UI login
- Password — strong, unique, stored in your password manager
- Sync password — a separate credential used by desktop clients to authenticate their sync connection. Can be the same as the login password but does not have to be.
Create your first real note to confirm everything persists:
+ in the tree to add a child note.Hello Trilium.Step 9: Install and Sync the Desktop Client
The web UI is excellent, but the desktop client is faster, works offline, and gives you a system tray icon for quick capture.
Download the client for your OS from the Trilium releases page. Builds are provided for Windows, macOS, and Linux (AppImage, deb, rpm).
Install and launch it. On first start you will see two choices:
Choose sync instance and fill in:
- Server address —
https://notes.yourdomain.com - Username — your web UI username
- Password — your sync password (not the web login password, if you chose different ones)
Repeat on each device. You can connect as many desktops as you like to the same server — macbook, desktop, work laptop — and all of them stay in sync.
Step 10: Configure Automatic Backups
Trilium writes automatic nightly backups into /var/lib/trilium-data/backup/ inside the container (which maps to the same path on the host). These are full SQLite snapshots — restoring is a matter of stopping the container and replacing document.db.
For off-server protection, sync the data directory to a remote location. A simple cron-based rsync works well:
sudo tee /etc/cron.daily/trilium-backup > /dev/null <<'EOF'
#!/bin/bash
rsync -az --delete /var/lib/trilium-data/ backup-user@backup-host:/backups/trilium/
EOF
sudo chmod +x /etc/cron.daily/trilium-backupFor encrypted, deduplicated backups, restic or borg are better choices and integrate cleanly with S3-compatible object storage.
Test your backup workflow by restoring to a second VPS at least once. An untested backup is not a backup.
Hardening and Maintenance
Keep Trilium Updated
Pull the latest image and recreate the container periodically:
sudo docker pull zadam/trilium:latest sudo docker stop trilium sudo docker rm trilium
Re-run the docker run command from Step 4.
Because the data lives in a host volume, image upgrades never touch your notes.
Restrict Access with Fail2Ban
Install Fail2Ban to block brute-force attempts against the login form:
sudo apt install -y fail2banDefault Nginx filters cover most attack shapes. For custom rules, add a jail referencing Trilium's Nginx access log.
Per-Note Encryption
In the web UI, right-click any note and choose Protect subtree. You will be prompted for a protection password (separate from login). Encrypted notes are ciphered inside the SQLite file and decrypted only in-memory in the client. Even a full server compromise cannot reveal their contents without the protection password.
Resource Limits
Trilium is frugal, but set a memory ceiling to be safe:
sudo docker update --memory 1g --memory-swap 1g triliumTroubleshooting
| Problem | Cause | Solution |
|---|---|---|
| Container exits immediately | Data directory permissions wrong | sudo chown -R 1000:1000 /var/lib/trilium-data && sudo docker restart trilium |
502 Bad Gateway from Nginx | Trilium container not running, or wrong port | sudo docker ps; check logs with sudo docker logs trilium |
| Desktop client cannot sync | Sync password wrong, or TLS certificate invalid | Re-enter sync password; verify certificate in browser first |
| Changes in browser do not appear in desktop client | WebSocket upgrade not proxied | Confirm proxy_set_header Upgrade and Connection "upgrade" lines in Nginx config |
| Disk filling up | Backup directory growing without bound | Rotate backups: find /var/lib/trilium-data/backup -name 'backup-*.db' -mtime +30 -delete |
| Upload fails on large attachment | Nginx client_max_body_size too low | Raise to 500m in the site config and reload Nginx |
| Sync conflicts after restoring backup | Two instances diverged | Pick one as source of truth, run "Sync from server" on the other to overwrite local |
Viewing Logs
Container logs:
sudo docker logs -f triliumNginx access and error logs:
sudo tail -f /var/log/nginx/access.log /var/log/nginx/error.logFAQ
What are the minimum server requirements for Trilium Notes?
Trilium is very lightweight. It runs comfortably on a VPS with 1 vCPU and 1 GB of RAM for a single user with a few thousand notes. For multi-device sync with large attachments (PDFs, images, videos) and frequent writes, 2 vCPU and 2 GB of RAM provide a noticeably smoother experience. Disk usage is dominated by attachments and revision history — plan for 10 GB to start and monitor growth. CPU is rarely the bottleneck; Trilium is I/O bound on the SQLite file, so NVMe storage matters more than clock speed.
Is Trilium Notes still maintained?
The original project by Zadam entered maintenance mode in 2024 after years of active development. The community forked the code as TriliumNext, which continues shipping features, security patches, and UI improvements. The Docker image used in this guide remains the canonical path and TriliumNext preserves full compatibility with existing databases. If you want the newest features, switch the image tag to triliumnext/notes:latest in the docker run command — the rest of the setup is unchanged.
How does the desktop client sync with the server?
The desktop client holds a local SQLite copy of your notes and syncs bidirectionally with the server over HTTPS. On first setup you enter the server URL, username, and sync password; the client pulls the full database. After that, each edit is queued locally and pushed to the server, while changes from other clients are pulled on a short polling interval plus WebSocket notifications for near-real-time updates. Offline edits are queued and synced the next time the client reaches the server. Conflicts (same note edited in two places simultaneously) are resolved by last-write-wins with the losing version kept in note revisions.
Can I encrypt my notes end-to-end?
Yes. Trilium supports per-note encryption with a user-supplied protection password. Encrypted notes (marked with a shield icon) are stored ciphered in the SQLite database and decrypted only in the client with your password — the server never sees plaintext. Combined with TLS on the sync channel, this gives genuinely end-to-end protection for sensitive notes like credentials, journal entries, or legal material. Unprotected notes are still stored on the server in readable form, so protect anything truly sensitive.
How do I back up my Trilium database?
Trilium writes automatic backups every day, week, and month into the backup/ subdirectory of the data folder. Full restoration is a matter of stopping the container, copying a backup-*.db file over document.db, and restarting. For off-server protection, sync the entire /var/lib/trilium-data directory to remote storage with rsync, restic, or borg on a daily cron schedule. You can also use the built-in Export function to produce a portable .zip archive of all notes in HTML or Markdown. Always test restores on a second VPS at least once before relying on them.
Can multiple users share one Trilium instance?
Trilium is designed as a single-user personal knowledge base — there is no multi-user permission model. For shared team wikis, look at BookStack or Outline, both of which are purpose-built for teams. You can, however, run multiple Trilium containers on the same VPS on different ports and domains, each with its own data volume — a reasonable setup for a family or small group where each person wants their own private notes base on shared infrastructure.
How does Trilium compare to Obsidian, Logseq, or a wiki?
Obsidian and Logseq are local-first markdown editors — your notes are .md files in a folder, and sync requires a third-party service (Obsidian Sync, iCloud, Syncthing) or paid plugin. Trilium is server-first with a SQLite backend, a hierarchical tree structure, relation maps, scripting, and a built-in web client. It trades the pure-markdown portability for a richer database-backed model. Compared to a traditional wiki like Wiki.js, Trilium is faster to capture into (no page-creation ceremony) and better for personal research, while Wiki.js shines for publishing structured documentation to a wider audience. Pick based on workflow: Obsidian for portable markdown, Wiki.js for team docs, Trilium for a deep personal second brain.
Next Steps
With Trilium running, here are useful directions to take your self-hosted knowledge stack further:
- Install a team wiki alongside personal notes — BookStack is the companion piece when you need shared documentation that non-technical teammates can edit. Run it on the same VPS behind a second Nginx vhost.
- Publish docs with Wiki.js — If some of your notes are destined for a public-facing documentation site, deploy Wiki.js and use Trilium's export to seed the initial content.
- Add a team document editor with Outline — For collaborative real-time editing closer to the Notion experience, Outline pairs well with Trilium: personal thinking stays in Trilium, published team knowledge lives in Outline.
- Connect an AI assistant — Point a local LLM at your Trilium export for natural-language search across your notes. Our Ollama install guide covers the model side.
- Monitor the stack — Drop Uptime Kuma onto the same VPS and configure HTTPS checks against
https://notes.yourdomain.comso you know the moment anything breaks.
- Explore Trilium scripting — Open the user manual in the Trilium tree and read the scripting section. You can query the note database, build dashboards, and automate workflows using plain JavaScript inside a note. It is genuinely magical once you internalize it.
Start with the right foundation.>
A self-hosted knowledge base is only as reliable as the VPS under it. Our Starter plan gives you NVMe storage, DDoS protection, and 99.9% uptime — the things you want backing years of accumulated notes.>
- 2 vCPU cores
- 4 GB RAM
- 50 GB NVMe SSD
- Ubuntu 24.04 LTS ready
- From EUR 7.99/month>
Deploy Your Starter VPS Now