TriliumNext Notes is a powerful, self-hosted knowledge base and note-taking application built for anyone who needs to organize large amounts of information. It started as Trilium Notes, which was eventually archived by its original developer. The community picked it up and forked it under the TriliumNext project, where active development continues today.

If you have ever struggled with scattered notes across multiple apps, TriliumNext solves that problem. It supports hierarchical note trees, rich text editing, code snippets with syntax highlighting, relation maps between notes, note versioning, and end-to-end encrypted sync between a server and desktop clients. You can run it entirely on your own server – no third-party cloud involved.

This guide walks you through installing TriliumNext Notes on Ubuntu 24.04/22.04 and Debian 13/12 using two methods: a direct .deb package install and a Docker Compose deployment. We will also set up Nginx as a reverse proxy with SSL and cover backups, updates, and troubleshooting.

Prerequisites

Before you begin, make sure you have the following ready:

  • A server running Ubuntu 24.04, Ubuntu 22.04, Debian 13 (Trixie), or Debian 12 (Bookworm)
  • A non-root user with sudo privileges
  • At least 1 GB of RAM and 10 GB of free disk space (more if you plan to store attachments)
  • A registered domain name pointing to your server IP (required for SSL)
  • Ports 80 and 443 open in your firewall for web access

Start by updating your system packages:

sudo apt update && sudo apt upgrade -y

Method 1 – Install TriliumNext Notes from .deb Package

This method installs TriliumNext directly on the host system using the official .deb package from GitHub releases. It is the simplest approach and works well for single-server setups.

Step 1 – Download the .deb Package

Head over to the TriliumNext GitHub releases page and grab the latest .deb file. At the time of writing, the current stable version is 0.90.12. Download it with wget:

TRILIUM_VERSION="v0.90.12"
wget https://github.com/TriliumNext/Notes/releases/download/${TRILIUM_VERSION}/TriliumNextNotes-${TRILIUM_VERSION}-linux-x64.deb

Verify that the file downloaded correctly by checking its size:

ls -lh TriliumNextNotes-*.deb

You should see a file roughly 100-150 MB in size.

Step 2 – Install the Package

Install the downloaded .deb package using apt:

sudo apt install -y ./TriliumNextNotes-${TRILIUM_VERSION}-linux-x64.deb

This handles all dependencies automatically. If any are missing, apt resolves them during installation.

Verify the installation completed without errors:

dpkg -l | grep trilium

You should see the package listed with status ii, confirming it is properly installed.

Step 3 – Create a Systemd Service

For a proper server deployment, you want TriliumNext to start automatically on boot and restart if it crashes. Create a dedicated system user first:

sudo useradd -r -s /usr/sbin/nologin -m -d /opt/trilium-data trilium

Set ownership of the data directory:

sudo mkdir -p /opt/trilium-data
sudo chown -R trilium:trilium /opt/trilium-data

Now create the systemd unit file:

sudo tee /etc/systemd/system/trilium.service > /dev/null <<'EOF'
[Unit]
Description=TriliumNext Notes
After=network.target

[Service]
Type=simple
User=trilium
Group=trilium
Environment=TRILIUM_DATA_DIR=/opt/trilium-data
ExecStart=/opt/trilium/trilium
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

Reload systemd, enable, and start the service:

sudo systemctl daemon-reload
sudo systemctl enable --now trilium.service

Check that the service is running:

sudo systemctl status trilium.service

The output should show active (running). If it is not running, check the logs:

sudo journalctl -u trilium.service --no-pager -n 50

Step 4 – Open the Firewall

If you are using UFW (default on Ubuntu), allow the TriliumNext port:

sudo ufw allow 8080/tcp
sudo ufw status

Confirm port 8080 is listed as ALLOW in the output.

Step 5 – Access the Web Interface

Open your browser and navigate to:

http://your-server-ip:8080

You will see the TriliumNext setup wizard. Set a strong password for your instance – this password protects all your notes and is used for encryption. Store it somewhere safe because there is no recovery mechanism if you lose it.

Method 2 – Deploy TriliumNext Notes with Docker Compose

Docker Compose gives you a cleaner deployment with easier updates and rollbacks. This is the preferred method if you already run other containers on your server.

Step 1 – Install Docker and Docker Compose

If Docker is not already installed, set it up using the official repository:

sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

Add the Docker repository. For Ubuntu:

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

For Debian, replace the repository line:

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Install Docker Engine and the Compose plugin:

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Verify Docker is working:

sudo docker run --rm hello-world

Add your user to the docker group so you do not need sudo for every command:

sudo usermod -aG docker $USER
newgrp docker

Step 2 – Create the Docker Compose File

Create a directory for your TriliumNext deployment:

mkdir -p ~/trilium-docker && cd ~/trilium-docker

Create the Docker Compose configuration file:

cat > docker-compose.yml <<'EOF'
services:
  trilium:
    image: triliumnext/notes:v0.90.12
    container_name: trilium
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    volumes:
      - trilium-data:/home/node/trilium-data
    environment:
      - TRILIUM_DATA_DIR=/home/node/trilium-data

volumes:
  trilium-data:
    driver: local
EOF

A few things to note about this configuration:

  • The port binding uses 127.0.0.1:8080:8080 so TriliumNext only listens on localhost. We will put Nginx in front of it.
  • A named Docker volume trilium-data stores the database and configuration persistently.
  • The unless-stopped restart policy keeps the container running through reboots.

Step 3 – Start the Container

Pull the image and start TriliumNext:

docker compose up -d

Verify the container is running:

docker compose ps

You should see the trilium container with status Up. Check the logs to confirm it started properly:

docker compose logs -f trilium

Look for a line indicating the server is listening on port 8080. Press Ctrl+C to stop following the logs.

Configure Nginx Reverse Proxy with SSL

Running TriliumNext behind Nginx with SSL is the right way to handle production deployments. It gives you proper HTTPS encryption and lets you use a clean domain name instead of an IP address with a port number.

Step 1 – Install Nginx and Certbot

sudo apt install -y nginx certbot python3-certbot-nginx

Verify Nginx is running:

sudo systemctl status nginx

Step 2 – Create the Nginx Server Block

Replace notes.example.com with your actual domain in the configuration below:

sudo tee /etc/nginx/sites-available/trilium.conf > /dev/null <<'EOF'
server {
    listen 80;
    server_name notes.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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;

        client_max_body_size 50M;
    }
}
EOF

The Upgrade and Connection headers are required because TriliumNext uses WebSocket connections for real-time sync. The client_max_body_size setting allows uploading larger file attachments to your notes.

Enable the site and test the configuration:

sudo ln -s /etc/nginx/sites-available/trilium.conf /etc/nginx/sites-enabled/
sudo nginx -t

If the test passes, reload Nginx:

sudo systemctl reload nginx

Step 3 – Obtain an SSL Certificate

Run Certbot to get a free Let’s Encrypt certificate. Replace the domain and email with your own:

sudo certbot --nginx -d notes.example.com --non-interactive --agree-tos -m [email protected]

Certbot automatically modifies the Nginx configuration to add SSL directives and sets up a cron job for automatic certificate renewal.

Verify the renewal process works:

sudo certbot renew --dry-run

If you see “Congratulations, all simulated renewals succeeded”, your SSL setup is complete.

Step 4 – Allow HTTP/HTTPS Through the Firewall

sudo ufw allow 'Nginx Full'
sudo ufw delete allow 8080/tcp
sudo ufw status

We remove the direct port 8080 rule since all traffic now goes through Nginx.

Open your browser and navigate to https://notes.example.com. You should see the TriliumNext login page with a valid SSL certificate.

Basic Usage

After completing the initial setup wizard, here is what to know about working with TriliumNext:

  • Note tree – The left panel shows a hierarchical tree of your notes. Right-click any note to create child notes, clone notes to multiple locations, or export them.
  • Note types – TriliumNext supports text notes, code notes (with syntax highlighting for dozens of languages), relation maps, book notes, and file notes for attachments.
  • Search – Press Ctrl+S to open full-text search across all your notes. The search is fast even with thousands of notes.
  • Attributes – You can tag notes with labels and define relations between notes. This turns your note collection into a personal wiki with cross-references.
  • Note versioning – Every change is tracked. You can view and restore previous versions of any note from the note detail panel.
  • Desktop sync – Download the TriliumNext desktop client and point it at your server URL to sync notes between your desktop and the server instance.

Backup Strategy

Your notes live in a SQLite database, so backups are straightforward. TriliumNext has a built-in automatic backup feature, but you should also maintain external backups.

Built-in Backups

TriliumNext automatically creates daily backups of the database in the backup subdirectory of the data folder. You can configure the number of retained backups in the Options menu inside the web UI.

External Backup Script

For the .deb installation, create a cron job that copies the database to an offsite location:

sudo tee /opt/trilium-data/backup.sh > /dev/null <<'SCRIPT'
#!/bin/bash
BACKUP_DIR="/opt/trilium-backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"

# Use sqlite3 .backup command for a safe copy while the database is in use
sqlite3 /opt/trilium-data/document.db ".backup '${BACKUP_DIR}/trilium_${TIMESTAMP}.db'"

# Keep only the last 7 daily backups
find "$BACKUP_DIR" -name "trilium_*.db" -mtime +7 -delete

echo "Backup completed: trilium_${TIMESTAMP}.db"
SCRIPT

sudo chmod +x /opt/trilium-data/backup.sh

Install sqlite3 if it is not already present:

sudo apt install -y sqlite3

Schedule the backup to run daily at 2 AM:

(sudo crontab -l 2>/dev/null; echo "0 2 * * * /opt/trilium-data/backup.sh >> /var/log/trilium-backup.log 2>&1") | sudo crontab -

For the Docker installation, back up the named volume:

docker run --rm \
  -v trilium-docker_trilium-data:/data \
  -v /opt/trilium-backups:/backup \
  alpine tar czf /backup/trilium_$(date +%Y%m%d_%H%M%S).tar.gz -C /data .

Verify your backup by checking the file size is non-zero:

ls -lh /opt/trilium-backups/

Update Procedure

Updating the .deb Installation

Always take a backup before updating. Then download the new version and install it over the existing one:

# Back up first
sudo /opt/trilium-data/backup.sh

# Download the new version
NEW_VERSION="v0.90.13"
wget https://github.com/TriliumNext/Notes/releases/download/${NEW_VERSION}/TriliumNextNotes-${NEW_VERSION}-linux-x64.deb

# Stop the service, install, and restart
sudo systemctl stop trilium.service
sudo apt install -y ./TriliumNextNotes-${NEW_VERSION}-linux-x64.deb
sudo systemctl start trilium.service

Verify the service started correctly after the update:

sudo systemctl status trilium.service

Updating the Docker Installation

Update the image tag in your docker-compose.yml file, then pull and recreate the container:

cd ~/trilium-docker

# Edit docker-compose.yml and change the image tag to the new version
# Then pull and recreate
docker compose pull
docker compose up -d

Verify the new container is running with the updated image:

docker compose ps
docker compose logs --tail 20 trilium

Your data persists in the named volume, so updates do not affect your notes.

Troubleshooting

TriliumNext fails to start

Check the service logs for specific error messages:

# For systemd installs
sudo journalctl -u trilium.service --no-pager -n 100

# For Docker installs
docker compose logs trilium

Common causes include permission issues on the data directory. Fix them with:

sudo chown -R trilium:trilium /opt/trilium-data

Port 8080 already in use

Find what is occupying the port:

sudo ss -tlnp | grep 8080

Either stop the conflicting service or change the TriliumNext port. For the systemd install, set the TRILIUM_PORT environment variable in the service file. For Docker, change the port mapping in docker-compose.yml (for example, 127.0.0.1:8081:8080) and update the Nginx proxy_pass accordingly.

Nginx returns 502 Bad Gateway

This means Nginx cannot reach TriliumNext on the backend. Verify the application is actually running and listening:

curl -I http://127.0.0.1:8080

If curl fails, the application is down. Restart it and check the logs. If curl works but Nginx still returns 502, check the Nginx error log:

sudo tail -20 /var/log/nginx/error.log

WebSocket connection failures

If the web interface loads but you see sync errors or real-time updates do not work, the WebSocket connection is likely blocked. Make sure your Nginx configuration includes the Upgrade and Connection headers as shown in the reverse proxy section above. Also check that no upstream proxy or CDN is stripping WebSocket headers.

Database corruption after unclean shutdown

If TriliumNext fails to start after a power loss or hard reboot, the SQLite database may be corrupted. Restore from your most recent backup:

# Stop the service first
sudo systemctl stop trilium.service

# Replace the corrupted database with the backup
sudo cp /opt/trilium-backups/trilium_LATEST.db /opt/trilium-data/document.db
sudo chown trilium:trilium /opt/trilium-data/document.db

# Start the service
sudo systemctl start trilium.service

If no backup is available, try running an integrity check:

sqlite3 /opt/trilium-data/document.db "PRAGMA integrity_check;"

High memory usage

TriliumNext is a Node.js application and can consume significant memory with large databases. Monitor its resource usage with:

# For systemd installs
sudo systemctl status trilium.service | grep Memory

# For Docker installs
docker stats trilium --no-stream

If memory usage is too high, you can set limits. For systemd, add MemoryMax=512M to the [Service] section of the unit file. For Docker, add mem_limit: 512m to the service definition in docker-compose.yml.

Conclusion

You now have TriliumNext Notes running on your Ubuntu or Debian server with a proper reverse proxy, SSL, and backup strategy in place. Whether you went with the .deb package or Docker Compose, TriliumNext provides a solid self-hosted platform for organizing your knowledge base.

Keep an eye on the TriliumNext GitHub releases page for updates and security patches. The project has an active community, so check the issues tracker if you run into problems not covered here.

LEAVE A REPLY

Please enter your comment!
Please enter your name here