Setting up a headless Obsidian instance for syncing

After trying numerous note taking/PKM (Personal Knowledge Management) apps for years, I have finally settled to Obsidian. The tool itself and the reasoning behind this choice deserves its own blog post, but in this blog post I’m going to open up the syncing solution I came up with.

My number one goal with Obsidian was to get it syncing seamlessly without any thinking to it. When I write notes I do not want to think about which clients are open and how long does it take. Coming from the cloud hosted note taking platforms like Simplenote syncing is something that has to “just work” in my books.

Obsidian systemd service via SSH and Obsidian via TigerVNC running side by side on Terminal windows on Linux.

Cross-platform syncing on Obsidian without plugins or client-side syncers

As I use Linux, Mac, Windows and iOS I need my data up to date at all times. There are solutions like Syncthing and Obsidian git, but I don’t like the idea that requires the sync client to be available at all times on the client side. Instead I want to have my own “cloud”, in a sense just by using Obsidian Sync. The paid sync they have is by far the most reliable and consistent, I don’t need to manually do anything or check if the data is in or not. I also don’t need to make sure each of my client apps are in sync.

How to install

Installed on Ubuntu 22.04 VPS.

On remote server via SSH

First we need to install some packages needed for this setup.

sudo apt install openbox xvfb python3-xdg x11vnc -y

Openbox is a really minimal and memory friendly desktop environment which runs beautifully in a “headless” mode. Unlike GDM (Gnome Display Manager) and KDE it doesn’t require a ton of dependencies.

We can test our openbox-session easily by opening a couple of extra terminal windows and running the commands on foreground. So to test, run in three separate terminal windows, in first:

Xvfb :5 -extension GLX -screen 0 800x600x16

In the second one:

export DISPLAY=":5"; /usr/bin/openbox-session

In third, first create a password:

sudo x11vnc -storepasswd

Then run a VNC server:

x11vnc -rfbport 5900 -display :5 -rfbauth ~/.vnc/passwd

Install Obsidian on your headless server (SSH)

Install via deb package:

wget https://github.com/obsidianmd/obsidian-releases/releases/download/v1.6.7/obsidian_1.6.7_amd64.deb
sudo apt-get install xdg-utils
sudo apt --fix-broken install
sudo apt update

On your Linux PC

After this you need to download a VNC viewer. I prefer free TigerVNC which is available for Linux and macOS. You can usually find TigerVNC from your local package manager. Download, install and connect via TigerVNC to your server IP with port 5900. Use your password. You should be able to connect to an empty desktop environment. You’ll see it’s openbox by right clicking the empty space.

Via right click context menu, open headless terminal and simply run:

obsidian

Now that the Obisdian open ups, just log in to your vault, set up Obsidian Sync and you’re good to go.

Systemd services

The final touch is to add these services to run on the background, we don’t want to keep opening up terminals to keep our headless Obsidian up and running. So you want to set up these systemd services.

Xvfb

sudo nano /etc/systemd/system/obsidian-headless-xvfb.service
[Unit]
Description=Headless Xvfb for Obsidian GUI

[Service]
User=rolle
Group=rolle
WorkingDirectory=/home/rolle/
ExecStart=/usr/bin/Xvfb :5 -extension GLX -screen 0 800x600x16
KillSignal=SIGINT
Environment="PATH=/usr/local/bin:/usr/bin:/bin"
Type=exec
Restart=on-failure
RestartSec=30s

[Install]
WantedBy=multi-user.target

Openbox

sudo nano /etc/systemd/system/obsidian-headless-openboxsession.service
[Unit]
Description=Headless openbox-session for Obsidian GUI
After=obsidian-headless-xvfb.service

[Service]
User=rolle
Group=rolle
WorkingDirectory=/home/rolle/
ExecStart=/usr/bin/openbox-session
KillSignal=SIGINT
Environment="DISPLAY=:5"
Environment="PATH=/usr/local/bin:/usr/bin:/bin"
Type=exec
Restart=on-failure
RestartSec=30s

[Install]
WantedBy=multi-user.target

x11vnc

sudo nano /etc/systemd/system/obsidian-headless-x11vnc.service
[Unit]
Description=Headless x11vnc for Obsidian GUI
After=obsidian-headless-openboxsession.service

[Service]
User=rolle
Group=rolle
WorkingDirectory=/home/rolle/
ExecStart=/usr/bin/x11vnc -rfbport 5900 -display :5 -rfbauth ~/.vnc/passwd
KillSignal=SIGINT
Environment="PATH=/usr/local/bin:/usr/bin:/bin"
Type=exec
Restart=on-failure
RestartSec=30s

[Install]
WantedBy=multi-user.target

Obsidian

sudo nano /etc/systemd/system/obsidian-headless.service
[Unit]
Description=Headless Obsidian
After=obsidian-headless-xvfb.service

[Service]
User=rolle
Group=rolle
WorkingDirectory=/home/rolle/
ExecStart=/usr/bin/obsidian
KillSignal=SIGINT
Environment="DISPLAY=:5"
Environment="PATH=/usr/local/bin:/usr/bin:/bin"
Type=exec
Restart=on-failure
RestartSec=30s

[Install]
WantedBy=multi-user.target

Enable and launch services

# Load and enable
sudo systemctl daemon-reload
sudo systemctl enable obsidian-headless-xvfb.service
sudo systemctl enable obsidian-headless-openboxsession.service
sudo systemctl enable obsidian-headless-x11vnc.service
sudo systemctl enable obsidian-headless.service

# Start
sudo systemctl start obsidian-headless-xvfb.service
sudo systemctl start obsidian-headless-openboxsession.service
sudo systemctl start obsidian-headless-x11vnc.service
sudo systemctl start obsidian-headless.service

Debug and logging

sudo systemctl status obsidian-headless-xvfb.service
sudo systemctl status obsidian-headless-openboxsession.service
sudo systemctl status obsidian-headless-x11vnc.service
sudo systemctl status obsidian-headless.service

sudo journalctl -u obsidian-headless.service -f
sudo journalctl -u obsidian-headless-x11vnc.service -f

Cronjob and git backup

On top of that I love to be able to see my changes on my private GitHub repository. For this I use this bash script I programmed:

#!/bin/bash
# IP Address
IPADDR=$(hostname -I | awk '{print $1}')

# Use Helsinki/Europe time
export TZ="Europe/Helsinki"

# Use formatted date
DATE=$(date +"%a %b %d %H:%M:%S %Y")

# Push everything to Git repo
cd "/home/rolle/Documents/Brain dump"
git add --all
git commit -m "Automatic cron sync from $IPADDR on $DATE"
git push

# GitBook
cd "/home/rolle/Documents/Brain dump/Dude/Internal Development Docs"
git pull --rebase
git commit -m "Automatic cron sync from $IPADDR on $DATE"
git push

This bash scripts runs each 10 minutes via cron:

*/10 * * * * bash /home/rolle/obsidian-backup-to-git.sh >/dev/null 2>&1

There we have it, what a perfect Obsidian “cloud”, self-hosted by you!

Comments

With an account on the Fediverse or Mastodon, you can respond to this post. Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one. Known non-private replies are displayed below.