mirror of
https://github.com/Nystik-gh/ignis.git
synced 2026-06-17 04:35:53 +00:00
update docs
This commit is contained in:
93
README.md
93
README.md
@@ -28,6 +28,15 @@ What started as an experiment turned out to be more viable than expected, and th
|
||||
|
||||
Plugin compatibility depends on what APIs a plugin uses; most plugins built on Obsidian's plugin API work, anything requiring Node native modules or `child_process` doesn't. See [What doesn't work](#what-doesnt-work) for the full list of known limitations.
|
||||
|
||||
## Variants
|
||||
|
||||
Ignis ships in two forms with the same in-browser experience:
|
||||
|
||||
- **Self-hosted server** -- [`apps/ignis-server/`](apps/ignis-server/). Docker container running Express. Stable, in daily use. See its README for setup, env vars, and reverse-proxy examples.
|
||||
- **Desktop plugin** -- `apps/ignis-local/`. Planned.
|
||||
|
||||
The rest of this README describes the shared experience.
|
||||
|
||||
## What works
|
||||
|
||||
- All core editor features: markdown, canvas, bases, and the command palette.
|
||||
@@ -96,90 +105,6 @@ A few design decisions worth knowing about for someone evaluating Ignis against
|
||||
|
||||
Tested in Chrome, Brave, and Firefox, with limited testing in Safari.
|
||||
|
||||
## Authentication
|
||||
|
||||
Ignis has **no built-in authentication** and serves plain HTTP by default. Both authentication and TLS termination are expected to be handled by whatever you put in front of it.
|
||||
|
||||
If you are exposing Ignis to the internet, **you should really** put an authentication layer in front of it. Options include:
|
||||
|
||||
- A reverse proxy with Basic Auth (nginx, Caddy, Traefik)
|
||||
- An SSO proxy like Authelia, Authentik, or OAuth2 Proxy
|
||||
- A VPN (Tailscale, WireGuard)
|
||||
- Cloudflare Application Tunnel
|
||||
|
||||
Example for Basic Auth, and Authelia can be found [here](examples).
|
||||
|
||||
> [!CAUTION]
|
||||
> Do not run Ignis on a public network without auth. Anyone with the url can read and write your vault files.
|
||||
|
||||
|
||||
|
||||
## Setup with Docker Compose
|
||||
|
||||
Example `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
ignis:
|
||||
image: nobbe/ignis:latest
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
- OBSIDIAN_VERSION=1.12.7
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
volumes:
|
||||
- ./vaults:/vaults
|
||||
- ./data:/app/data
|
||||
- obsidian-app:/app/obsidian-app
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
obsidian-app:
|
||||
```
|
||||
|
||||
Then `docker compose up -d`. On first start the container downloads Obsidian from the official source and installs Obsidian Headless CLI. This takes a minute or two.
|
||||
|
||||
To build from source instead of pulling the image, clone the repo and replace `image: nobbe/ignis:latest` with `build: .`.
|
||||
|
||||
### Volumes
|
||||
|
||||
| Mount | Description |
|
||||
| ----- | ----------- |
|
||||
| `/vaults` | Vault storage. Each subdirectory is a vault. |
|
||||
| `/data` | state persistence for various ignis specific functionality, plugin management, headless sync config, etc |
|
||||
| `/app/obsidian-app` | Cached Obsidian assets. Persisting this avoids re-downloading on container recreate. |
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
| -------- | ----------- | ------- |
|
||||
| `PORT` | Server listen port | `8080` |
|
||||
| `VAULT_ROOT` | Path to vault storage inside the container | `/vaults` |
|
||||
| `DATA_ROOT` | Path to persistent data (plugin config, sync state, auth tokens) | `/app/data` |
|
||||
| `OBSIDIAN_VERSION` | Obsidian version to download | `1.12.7` |
|
||||
| `OBSIDIAN_ASSETS_PATH` | Where the extracted Obsidian app files live. Override if you're pointing at a pre-extracted directory instead of letting the entrypoint download. | `/app/obsidian-app` |
|
||||
| `AUTO_CREATE_DEFAULT` | When `true`, creates a "My Vault" vault on startup if no vaults exist. Useful for fresh installs. | `false` |
|
||||
| `PUID` | User ID for file ownership | `1000` |
|
||||
| `PGID` | Group ID for file ownership | `1000` |
|
||||
| `WRITE_COALESCE_MS` | Debounce window (ms) for rapid writes. Useful for slow filesystems (rclone, NFS, SMB). Set to `0` to disable. | `5000` |
|
||||
|
||||
Demo mode adds its own set of env vars (per-session vaults, auto-cleanup, proxy allowlist, login blocking). See [examples/demo/](examples/demo/) if you want to run a public demo deployment.
|
||||
|
||||
### Migrating an existing vault
|
||||
|
||||
Each subdirectory of `/vaults` is treated as a separate vault, so dropping in an existing Obsidian vault directory will make it available in Ignis.
|
||||
|
||||
### Upgrading Obsidian
|
||||
|
||||
Obsidian releases can include changes that break the compatibility shim. Each Ignis release pins a known-working Obsidian version through the `OBSIDIAN_VERSION` env var, so the recommended path is to wait for an Ignis release that bumps the version, pull the new image, and restart.
|
||||
|
||||
If you want to try a newer Obsidian version before Ignis updates, set `OBSIDIAN_VERSION` in your compose file. The entrypoint will download that version on next start, but there's no guarantee it'll work cleanly with the current shim.
|
||||
|
||||
### Backups
|
||||
|
||||
Vault data lives as ordinary files in `/vaults`. Back it up however you back up other server-side data; Ignis doesn't provide a built in backup mechanism.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines, especially on how to report plugin compatibility issues. Check the [open issues](https://github.com/Nystik-gh/ignis/issues) for things to work on.
|
||||
|
||||
95
apps/ignis-server/README.md
Normal file
95
apps/ignis-server/README.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# Ignis Server
|
||||
|
||||
The self-hosted Docker variant of Ignis. For the project overview, feature list, and what works / what doesn't, see the [root README](../../README.md).
|
||||
|
||||
## Contents
|
||||
|
||||
- [Authentication](#authentication)
|
||||
- [Setup with Docker Compose](#setup-with-docker-compose)
|
||||
- [Volumes](#volumes)
|
||||
- [Environment Variables](#environment-variables)
|
||||
- [Migrating an existing vault](#migrating-an-existing-vault)
|
||||
- [Upgrading Obsidian](#upgrading-obsidian)
|
||||
- [Backups](#backups)
|
||||
|
||||
## Authentication
|
||||
|
||||
Ignis has **no built-in authentication** and serves plain HTTP by default. Both authentication and TLS termination are expected to be handled by whatever you put in front of it.
|
||||
|
||||
If you are exposing Ignis to the internet, **you should really** put an authentication layer in front of it. Options include:
|
||||
|
||||
- A reverse proxy with Basic Auth (nginx, Caddy, Traefik)
|
||||
- An SSO proxy like Authelia, Authentik, or OAuth2 Proxy
|
||||
- A VPN (Tailscale, WireGuard)
|
||||
- Cloudflare Application Tunnel
|
||||
|
||||
Example configurations for Basic Auth and Authelia are in [`examples/`](examples).
|
||||
|
||||
> [!CAUTION]
|
||||
> Do not run Ignis on a public network without auth. Anyone with the URL can read and write your vault files.
|
||||
|
||||
## Setup with Docker Compose
|
||||
|
||||
Example `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
ignis:
|
||||
image: nobbe/ignis:latest
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
- OBSIDIAN_VERSION=1.12.7
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
volumes:
|
||||
- ./vaults:/vaults
|
||||
- ./data:/app/data
|
||||
- obsidian-app:/app/obsidian-app
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
obsidian-app:
|
||||
```
|
||||
|
||||
Then `docker compose up -d`. On first start the container downloads Obsidian from the official source and installs the Obsidian Headless CLI. This takes a minute or two.
|
||||
|
||||
To build from source instead of pulling the image, clone the repo and run `docker compose up` against the [`docker-compose.yml`](docker-compose.yml) in this directory -- it is already wired to build from the monorepo root.
|
||||
|
||||
## Volumes
|
||||
|
||||
| Mount | Description |
|
||||
| ----- | ----------- |
|
||||
| `/vaults` | Vault storage. Each subdirectory is a vault. |
|
||||
| `/app/data` | State persistence for various Ignis-specific functionality: plugin management, headless sync config, etc. |
|
||||
| `/app/obsidian-app` | Cached Obsidian assets. Persisting this avoids re-downloading on container recreate. |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
| -------- | ----------- | ------- |
|
||||
| `PORT` | Server listen port | `8080` |
|
||||
| `VAULT_ROOT` | Path to vault storage inside the container | `/vaults` |
|
||||
| `DATA_ROOT` | Path to persistent data (plugin config, sync state, auth tokens) | `/app/data` |
|
||||
| `OBSIDIAN_VERSION` | Obsidian version to download | `1.12.7` |
|
||||
| `OBSIDIAN_ASSETS_PATH` | Where the extracted Obsidian app files live. Override if you're pointing at a pre-extracted directory instead of letting the entrypoint download. | `/app/obsidian-app` |
|
||||
| `AUTO_CREATE_DEFAULT` | When `true`, creates a "My Vault" vault on startup if no vaults exist. Useful for fresh installs. | `false` |
|
||||
| `PUID` | User ID for file ownership | `1000` |
|
||||
| `PGID` | Group ID for file ownership | `1000` |
|
||||
| `WRITE_COALESCE_MS` | Debounce window (ms) for rapid writes. Useful for slow filesystems (rclone, NFS, SMB). Set to `0` to disable. | `5000` |
|
||||
|
||||
Demo mode adds its own set of env vars (per-session vaults, auto-cleanup, proxy allowlist, login blocking). See [`examples/demo/`](examples/demo/) if you want to run a public demo deployment.
|
||||
|
||||
## Migrating an existing vault
|
||||
|
||||
Each subdirectory of `/vaults` is treated as a separate vault, so dropping in an existing Obsidian vault directory will make it available in Ignis.
|
||||
|
||||
## Upgrading Obsidian
|
||||
|
||||
Obsidian releases can include changes that break the compatibility shim. Each Ignis release pins a known-working Obsidian version through the `OBSIDIAN_VERSION` env var, so the recommended path is to wait for an Ignis release that bumps the version, pull the new image, and restart.
|
||||
|
||||
If you want to try a newer Obsidian version before Ignis updates, set `OBSIDIAN_VERSION` in your compose file. The entrypoint will download that version on next start, but there is no guarantee it will work cleanly with the current shim.
|
||||
|
||||
## Backups
|
||||
|
||||
Vault data lives as ordinary files in `/vaults`. Back it up however you back up other server-side data; Ignis does not provide a built-in backup mechanism.
|
||||
@@ -43,7 +43,7 @@ The shim layer makes Obsidian think it's running in Electron. The bridge plugin
|
||||
|
||||
### Loading
|
||||
|
||||
The server serves its own `index.html` (in `server/assets/`) rather than Obsidian's. At startup it reads Obsidian's `index.html` once to discover which scripts Obsidian expects, then embeds that list in our HTML as a JSON array. The client-side HTML loads the shim loader and UI bundle first (non-deferred), then a small inline script dynamically injects Obsidian's scripts in order. Obsidian's files are never modified on disk, or transformed in transit.
|
||||
The server serves its own `index.html` (in `apps/ignis-server/server/assets/`) rather than Obsidian's. At startup it reads Obsidian's `index.html` once to discover which scripts Obsidian expects, then embeds that list in our HTML as a JSON array. The client-side HTML loads the shim loader and UI bundle first (non-deferred), then a small inline script dynamically injects Obsidian's scripts in order. Obsidian's files are never modified on disk, or transformed in transit.
|
||||
|
||||
Before injecting Obsidian's scripts, the shim loader sets `localStorage.EmulateMobile` based on viewport width (< 600px) so Obsidian boots into its mobile UI on phones and narrow windows. The loader replaces the module system, then issues a single blocking bootstrap request that returns the vault info, vault list, metadata tree, and Ignis plugin list in one pre-compressed response. The request has to be blocking because Obsidian makes synchronous filesystem calls during page load, before the event loop is running, so the cache has to already be populated.
|
||||
|
||||
@@ -77,11 +77,11 @@ Two caches on the client side. The **MetadataCache** holds `{ type, size, mtime,
|
||||
|
||||
Reads not satisfied by ContentCache go through the transport layer to `/api/fs/readFile`. Sync calls use synchronous XHR to keep Obsidian's pre-boot module code working. Async calls use fetch. The transport handles vault id injection, base64 encoding for binary files, and mapping HTTP error codes back to Node errno values (`ENOENT`, `EEXIST`, `ENOTDIR`).
|
||||
|
||||
Writes go through a server-side write coalescer (`server/write-coalescer.js`) designed for slow filesystems like rclone FUSE mounts. The first write to a path goes to disk immediately. Subsequent writes within a configurable window (default 5 seconds, `WRITE_COALESCE_MS`) are buffered and flushed when the debounce timer fires; the timer resets on each write. Buffered writes return to the HTTP client immediately with synthetic metadata so connection-pool starvation on rapid-fire writes (e.g. `workspace.json` autosaves) doesn't stall unrelated reads. Reads for pending paths serve the buffered content so clients never see stale data. All pending writes are flushed on graceful shutdown.
|
||||
Writes go through a server-side write coalescer (`packages/server-core/src/write-coalescer.js`) designed for slow filesystems like rclone FUSE mounts. The first write to a path goes to disk immediately. Subsequent writes within a configurable window (default 5 seconds, `WRITE_COALESCE_MS`) are buffered and flushed when the debounce timer fires; the timer resets on each write. Buffered writes return to the HTTP client immediately with synthetic metadata so connection-pool starvation on rapid-fire writes (e.g. `workspace.json` autosaves) doesn't stall unrelated reads. Reads for pending paths serve the buffered content so clients never see stale data. All pending writes are flushed on graceful shutdown.
|
||||
|
||||
### Transforms
|
||||
|
||||
The shim has a transforms registry (`src/shims/fs/transforms.js`) for hooks applied at the public shim surface, before caches or transport see the path. Three hook types:
|
||||
The shim has a transforms registry (`packages/shim/src/fs/transforms.js`) for hooks applied at the public shim surface, before caches or transport see the path. Three hook types:
|
||||
|
||||
- **Path resolvers** map a logical path to a physical path. Used by the workspaces shim to redirect reads and writes of `.obsidian/workspace.json` to `.obsidian/workspace.<name>.json` based on the `?workspace=` URL parameter, so each browser tab can hold a separate layout.
|
||||
- **Read transforms** post-process bytes returned by a read (cache hit or transport miss). Used to mask the Obsidian Sync setting in `core-plugins.json` when headless-sync is active for the vault, and to override the `active` field on reads of `workspaces.json` so each tab sees its own workspace as selected.
|
||||
@@ -143,7 +143,7 @@ Standard community and core Obsidian plugins. Obsidian evals plugin code with it
|
||||
|
||||
### Bridge Plugin (ignis-bridge)
|
||||
|
||||
An Obsidian plugin auto-installed into every vault by the server. Source lives in `plugin/`, built to `plugin/main.js`.
|
||||
An Obsidian plugin auto-installed into every vault by the server. Source lives in `packages/bridge-plugin/`, built to `packages/bridge-plugin/main.js`.
|
||||
|
||||
It contributes:
|
||||
- **File actions**: a ribbon icon for uploading files into the current folder, and right-click menu items: Download (single file), Download as ZIP (folder), and Upload file (folder).
|
||||
@@ -158,11 +158,11 @@ Not user-installable through Obsidian's plugin browser. Managed entirely by the
|
||||
|
||||
A basic plugin system for extending the server. Still early, the core lifecycle works but the API surface is minimal and likely to change.
|
||||
|
||||
An Ignis plugin is a Node.js package under `server/plugins/<name>/` that exports an id, name, and a `register` function. On load it receives a context object with access to config, the WebSocket server, a file watcher, an Express router, a logger, and a persistent data directory. Plugins are enabled and disabled per vault, with state persisted in `data/plugin-config.json`.
|
||||
An Ignis plugin is a Node.js package under `apps/ignis-server/server/plugins/<name>/` that exports an id, name, and a `register` function. On load it receives a context object with access to config, the WebSocket server, a file watcher, an Express router, a logger, and a persistent data directory. Plugins are enabled and disabled per vault, with state persisted in `data/plugin-config.json`.
|
||||
|
||||
When enabled, a plugin's Express router is mounted at `/api/ext/<pluginId>/`. A plugin can also optionally bundle an Obsidian plugin, a directory containing a standard Obsidian plugin (manifest.json, main.js) that gets auto-installed into the vault on enable and removed on disable. This bridges the server and client sides: the Ignis plugin handles server logic and routes, while the bundled Obsidian plugin provides the in-app UI or behavior.
|
||||
|
||||
The one Ignis plugin currently in the repo is **headless-sync** (`server/plugins/headless-sync/`). It wraps the [obsidian-headless](https://github.com/Yuri-Khomyakov/obsidian-headless) CLI (`ob`) and runs `ob sync --continuous` as a per-vault child process, optionally with `--pull-only` or `--mirror-remote`. Process state (running/stopped/error, pid, last activity, recent log lines) is broadcast over the WebSocket via a small per-vault subscription protocol. The bundled Obsidian plugin (`ignis-headless-sync`) adds a status bar item, a settings tab with start/stop/unlink controls, and a core-sync guard that hides Obsidian's own Sync setting from `core-plugins.json` reads while headless sync is active for that vault, so a different device syncing the "Active core plugins list" can't accidentally re-enable it.
|
||||
The one Ignis plugin currently in the repo is **headless-sync** (`apps/ignis-server/server/plugins/headless-sync/`). It wraps the [obsidian-headless](https://github.com/Yuri-Khomyakov/obsidian-headless) CLI (`ob`) and runs `ob sync --continuous` as a per-vault child process, optionally with `--pull-only` or `--mirror-remote`. Process state (running/stopped/error, pid, last activity, recent log lines) is broadcast over the WebSocket via a small per-vault subscription protocol. The bundled Obsidian plugin (`ignis-headless-sync`) adds a status bar item, a settings tab with start/stop/unlink controls, and a core-sync guard that hides Obsidian's own Sync setting from `core-plugins.json` reads while headless sync is active for that vault, so a different device syncing the "Active core plugins list" can't accidentally re-enable it.
|
||||
|
||||
## Demo mode
|
||||
|
||||
@@ -179,4 +179,4 @@ Other demo behaviors:
|
||||
- Server-side plugins (e.g. headless-sync) hidden from the client; enable/disable returns 403.
|
||||
- The bridge plugin disables any `<input type="email">` or `<input type="password">` it sees anywhere in the document, with a placeholder telling users not to enter credentials.
|
||||
|
||||
All server-side demo code lives in `server/demo/`. The client-side hooks live in `src/shims/demo.js`. The deployment example is in `examples/demo/` (tmpfs-mounted vaults, restricted proxy, all the env vars).
|
||||
All server-side demo code lives in `apps/ignis-server/server/demo/`. The client-side hooks live in `packages/shim/src/demo.js`. The deployment example is in `apps/ignis-server/examples/demo/` (tmpfs-mounted vaults, restricted proxy, all the env vars).
|
||||
Reference in New Issue
Block a user