Skip to content

AdamsGH/obsidian-headless

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

obsidian-headless

Headless Obsidian container with a working CLI and interactive TUI accessible via docker exec. No GUI required. No Catalyst license required at runtime — only the obsidian-1.12.6.asar file must be supplied at build time (see below).

How it works

  • Xvfb provides a virtual framebuffer so Electron starts without a real display.
  • dbus (system + session bus) is started inside the container — Electron requires it.
  • Obsidian 1.12.4 is installed from the official .deb release.
  • obsidian-1.12.6.asar (insider build) is placed in the config directory and auto-discovered by the launcher. Version 1.12.6 introduced a fixed Unix socket protocol (~/.obsidian-cli.sock) that makes CLI reliable in a container.
  • obsidian (/usr/local/bin/obsidian) — Python script that serialises argv via json.dumps, sends it to the socket, and reads the response until EOF. No second Electron process, no lock contention.
  • obsidian-tui (/usr/local/bin/obsidian-tui) — Python script that opens the socket in interactive mode (argv=[], tty=true), switches stdin to raw mode, and proxies bytes in both directions so Tab, arrow keys, and Ctrl+C all work correctly.

Repository structure

.
├── Dockerfile
├── docker-compose.yaml
├── justfile
├── CLI.md                        # Full command reference
├── scripts/
│   ├── entrypoint.sh             # Starts dbus, Xvfb, seeds config dir, launches Obsidian
│   ├── obsidian-cli              # One-shot CLI wrapper (Python)
│   └── obsidian-tui              # Interactive TUI wrapper (Python, raw TTY)
└── src/
    ├── obsidian-1.12.6.asar      # Insider renderer (not included in repo — see below)
    └── obsidian.json             # Vault registration, cli: true, frame: hidden

Requirements

  • Docker + Compose

  • just (optional, for justfile shortcuts)

  • src/obsidian-1.12.6.asarmust be copied from another machine running Obsidian with an active Insider Catalyst license. The file is not distributed in this repo.

    Typical locations:

    • Linux: ~/.config/obsidian/obsidian-1.12.6.asar
    • Windows: %APPDATA%\obsidian\obsidian-1.12.6.asar
    • macOS: ~/Library/Application Support/obsidian/obsidian-1.12.6.asar

    Place it at src/obsidian-1.12.6.asar before building.

Quick start

# 1. Copy obsidian-1.12.6.asar from an Insider-licensed instance (see Requirements)
#    cp /path/to/obsidian-1.12.6.asar src/

# 2. Set your vault path in docker-compose.yaml:
#    volumes:
#      - /your/vault/path:/vault

# 3. Build and start
docker compose up -d --build
# or: just up

# 4. Wait ~10 seconds for Obsidian to fully load
docker compose logs -f
# or: just logs

# 5. Run CLI commands
docker exec obsidian-headless obsidian version
docker exec obsidian-headless obsidian vault list
docker exec obsidian-headless obsidian files total

# 6. Open the interactive TUI
just tui

CLI

docker exec obsidian-headless obsidian version
docker exec obsidian-headless obsidian vault list
docker exec obsidian-headless obsidian files total
docker exec obsidian-headless obsidian files list
docker exec obsidian-headless obsidian read file="Daily Note"
docker exec obsidian-headless obsidian search query="TODO"
docker exec obsidian-headless obsidian tags counts sort=count
docker exec obsidian-headless obsidian tasks todo

Full command reference: see CLI.md.

Convenience alias

# Add to ~/.zshrc or ~/.bashrc
alias ob='docker exec obsidian-headless obsidian'

ob version
ob files list
ob tags counts sort=count
ob search query="TODO" format=json | jq '.[].file'

justfile shortcuts

just up             # build and start
just down           # stop
just restart        # restart container
just logs           # follow logs
just shell          # bash shell inside container
just tui            # interactive TUI
just version        # obsidian version
just vault          # vault summary
just files          # total file count
just ls             # list all files
just recents        # recently opened files
just search "q"     # full-text search
just grep "q"       # search with line context
just tags           # tags with counts
just tasks          # pending tasks
just tasks-done     # completed tasks
just dead-links     # unresolved links
just dead-ends      # notes with no outgoing links
just aliases        # all aliases
just properties     # all properties with counts
just read "Note"    # read a note by name
just read-path "p"  # read a note by path
just backlinks "n"  # backlinks for a note
just note-tags "n"  # tags for a note
just wc "n"         # word count for a note
just create "n"     # create a new note
just append "n" "t" # append to a note
just prepend "n" "t"# prepend to a note
just delete "n"     # delete a note
just rename "o" "n" # rename a note
just reload         # reload the vault
just tabs           # show open tabs
just screenshot     # take a screenshot

Run just with no arguments to see the full list.

Interactive TUI

just tui
# or directly:
docker exec -it obsidian-headless /usr/local/bin/obsidian-tui

The TUI requires a real TTY. It opens Obsidian's built-in interactive REPL with:

  • Tab — autocomplete commands and flags
  • ↑/↓ — command history
  • Ctrl+C — quit

just tui passes the current terminal dimensions ($COLUMNS/$LINES) so the autocomplete dropdown renders correctly.

Configuration files

File Purpose
src/obsidian.json Vault registration, cli: true, frame: hidden, updateDisabled: true
src/obsidian-1.12.6.asar Insider renderer — fixed Unix socket CLI protocol (not in repo)
scripts/obsidian-cli One-shot CLI wrapper (Python)
scripts/obsidian-tui Interactive TUI wrapper (Python, raw TTY)
scripts/entrypoint.sh Starts dbus, Xvfb, seeds config dir, launches Obsidian
docs/CLI.md Full command reference
justfile Convenience recipes

obsidian.json structure

{
  "vaults": {
    "<16-char hex id>": {
      "path": "/vault",
      "ts": 1773743087717,
      "open": true
    }
  },
  "cli": true,
  "frame": "hidden",
  "updateDisabled": true
}

The vault id is an arbitrary 16-character hex string. ts is any valid millisecond timestamp. open: true tells Obsidian to open the vault on startup.

Named volume

obsidian-config is a named volume mounted at /root/.config/obsidian/. It persists:

  • The Unix socket (~/.obsidian-cli.sock) used for CLI/TUI communication.
  • Chromium profile data (cache, IndexedDB, session storage).
  • The obsidian-1.12.6.asar file (copied from the image on first start).

On a fresh volume the entrypoint seeds obsidian.json and copies the .asar file from /opt/ before starting Obsidian.

Technical notes

  • --no-sandbox is required — Electron cannot use user namespaces inside a container.
  • SYS_ADMIN + seccomp=unconfined are needed for Chromium's internal sandboxing.
  • --disable-gpu and --disable-software-rasterizer prevent GPU process crashes.
  • tty: true + stdin_open: true in docker-compose.yaml are required for docker exec -it.
  • The CLI wrapper prepends vault=<id> automatically by reading obsidian.json, so commands resolve the correct vault without manual configuration.
  • The TUI wrapper translates bare \n to \r\n in raw mode — Node.js emits \n only, but a raw-mode terminal requires CRLF for correct line rendering.
  • Obsidian closes the socket after writing the full response; the CLI wrapper reads until EOF with a 30-second timeout.

Updating

Public release (installer)

Change OBSIDIAN_VERSION in docker-compose.yaml and rebuild:

just up   # or: docker compose up -d --build

Latest releases: https://github.com/obsidianmd/obsidian-releases/releases

Insider .asar

The .asar file is only available on machines with an active Insider Catalyst license. Copy the new obsidian-X.Y.Z.asar from another instance that has Insider access, place it at src/obsidian-X.Y.Z.asar, update the COPY line in Dockerfile, and rebuild. The launcher picks the highest version automatically.

About

Obsidian vault API on remote server

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors