Documentation
Short and to the point: what you need to know to use websidian effectively.
What websidian is (and is not)
websidian is an independent open-source project. It is not the original Obsidian (obsidian.md), not affiliated with it, and not a competing product. The name only describes the idea: an Obsidian-style markdown vault you reach from a web browser.
The original Obsidian is a desktop/mobile app that stores notes locally on each device and uses a separate sync service to keep devices in step. websidian works the other way around: your vault lives on the server and you simply log in.
Why does that matter? In many organisations — companies, agencies, enterprise laptops — you are not allowed to install private sync clients or arbitrary apps. A local-vault-plus-sync setup is then impossible. A web browser, however, is almost always available, so your knowledge vault stays reachable. On top of that:
- Nothing to install — no app, no sync client.
- No local storage used on your phone or PC.
- End-to-end encrypted — your browser encrypts everything, so only you can read it.
- Deliberately simple: just what you need day to day, not a feature maze.
The human brain is made for having ideas, not for holding them. websidian is your second brain.
Changes are not real-time
If you edit on device A, then look at device B, you must reload the browser on device B to see the change. Updates are not pushed live.
This is a direct consequence of end-to-end encryption: content is stored as ciphertext and only decrypted in your browser when you request it, so each device sees the latest version the next time it loads a note — not the instant it changes elsewhere.
Backing up your vault
Click Export in the sidebar. Your entire vault is downloaded as a
single .zip file with the original folder structure.
The export is decrypted in your browser on the way out, so the zip is a portable, platform-independent backup you can open anywhere or re-import later.
Deleting files (trash & recovery window)
When you delete a file or folder it is not erased right away. It is moved to a hidden, per-account trash so an accidental deletion can be recovered. While an item sits in the trash it is hidden from your file tree, but it still counts toward your storage quota until it is permanently removed.
A daily clean-up job permanently removes items that have been in the trash longer than a fixed retention window — 7 days by default. The job runs once a day, so the retention setting controls how long an item stays recoverable, not how often the clean-up runs. After the window passes the item is gone for good and cannot be restored.
Self-hosting? The window is configurable with the
TRASH_RETENTION_DAYS environment variable (set it to 0 to
disable the trash entirely so deletions are immediate).
Two-factor authentication (2FA / TOTP)
TOTP (Time-based One-Time Password) is the 6-digit code that rotates every 30 seconds in an authenticator app. On sign-in you provide your password and the current code, so a stolen password alone is not enough to reach your vault.
2FA is required, not optional, because your notes are sensitive and a single secret is too weak to protect them. Set it up once during registration by scanning the QR code.
Got a new phone or switched authenticator app? You can change (reset) your authenticator any time from the dashboard under Account → Security → Reset authenticator (2FA). For your safety the reset requires your current password and a code from your existing authenticator; you then scan a fresh QR code and confirm a code from the new device to switch over. The old code stops working as soon as the new one is confirmed.
End-to-end encryption (zero-knowledge)
Every file — notes, drawings, attachments, documents — is encrypted in your browser with AES-256-GCM before it is uploaded. The server only ever stores ciphertext it cannot read, so nobody — not even the operator — can see your content.
When you sign up, your browser generates a random vault key and locks it with a key derived from your password (PBKDF2, 600,000 iterations). Your password and the vault key never leave your device. Because the server is blind to your content, things that would normally happen server-side — markdown rendering, full-text content search and the export — all run locally in your browser instead.
Filenames and folder names stay readable on the server so your file tree keeps working; only the contents of files are encrypted.
Recovery key — and why there is no password reset
Because only you can decrypt your vault, we cannot reset your password for you — there is no “forgot password” e-mail that could ever give someone access. Instead, when you register you are shown a one-time recovery key. It unlocks your vault independently of your password, so it is your way back in if you ever forget it.
You must confirm you have saved the recovery key before you can finish signing up, and you can download it as a text file. Store it somewhere safe and separate from your password (a password manager is ideal).
You can change your password any time from the dashboard (current password + a 2FA code are required); this simply re-locks the same vault key under your new password. But if you lose both your password and your recovery key, your data is permanently unrecoverable — by design, no one can decrypt it for you.
We strongly recommend a password manager — for example Bitwarden — to store your password, your recovery key, and your 2FA secret (Bitwarden can generate the TOTP codes for you).
Web links (save a link once, open it safely forever)
The Web links manager lets you keep your important links inside your vault — with a name, category and description — instead of scattering them across browser bookmarks. Open the manager from the toolbar, add a link or import a CSV (the Linky export format is supported), and search across everything you saved.
The idea. Your bookmarks normally live inside one browser on one device. Reinstall the browser, switch machines, or log in from a locked-down work computer and they are gone. Web links live in your encrypted vault, so they travel with your account: save a link once and reach it from anywhere you can open websidian.
Why it is safer. The risky moment with any link is the first time — that is when you judge whether a URL really points where it claims. Vet a link once, store the exact address, and from then on you always open that verified URL. You are no longer re-reading a link someone pasted into an email or chat, where the visible text can hide a different, manipulated destination. The stored URL is end-to-end encrypted like the rest of your vault.
Independent of the browser. Because the links are kept server-side in your vault rather than in a browser profile, they are not tied to any one browser, extension or sync account. Nothing to install, nothing to export when you move devices — just log in and your trusted links are there.
Open tabs & the tab limit
Files you open are kept as tabs, like in a code editor, so you can switch
between several notes, drawings, the calendar, the graph and web links without anything
reloading. A small counter at the left of the tab bar shows how many tabs are open and the
maximum, for example 3/8.
Why there is a limit. Each open file holds a live connection to your storage. If too many files were open at once, your storage backend — especially a WebDAV server — could be overloaded by the many simultaneous connections and become slow or unreliable. The limit keeps that connection healthy.
What happens when it is full. When the counter turns red you have reached the maximum. Opening another file does nothing until you close a tab first — your open files are never closed automatically and nothing is lost. Close a tab with its × button or a middle-click, then open the next file.
Supported files
Beyond markdown and Excalidraw, you can browse a wide range of files like in a code
editor — .py, .ts, .js, .json,
.yaml, .toml, .sh, .html,
.css, .conf and many more — with syntax highlighting.
Word (.docx), Excel (.xlsx/.xls) and
OpenDocument (.odt/.ods) files render read-only in the
browser. All of them are end-to-end encrypted in your browser just like your notes.
Where your vault is stored
websidian does not host your files. You connect your own storage when you sign up (and can change it any time in the dashboard), so your encrypted vault lives on a backend you control. Whatever you pick is a blind blob store: only end-to-end encrypted ciphertext is ever written, so the host cannot read your notes. Because everything is already encrypted in your browser, you do not need a provider with its own “client-side encryption”.
Two kinds of storage are supported, and the provider choice is not critical (it only ever sees ciphertext) — pick one you trust:
- Managed storage — if this instance offers it, store on websidian's own storage with nothing to set up. It is free up to the included allowance; you can raise the limit under Billing. No S3 or Nextcloud account of your own is needed.
- S3-compatible object storage — e.g. Mega S4 (very inexpensive) or Hetzner Object Storage (Germany), also AWS S3, MinIO, …
- WebDAV — e.g. Nextcloud (self-hosting) or Koofr (Europe).
websidian is tested end-to-end with Nextcloud and Koofr (WebDAV) and Mega S4 (S3). See the next section for how to connect.
Connecting your storage
Coming soon: managed storage — just sign in and start, with no need to bring your own storage provider. We host your encrypted vault for you (it only ever sees ciphertext).
Tested compatible providers
These providers are verified end-to-end. Others may work, but these are the recommended, tested choices:
- Nextcloud (WebDAV) — self-hosted (nextcloud.com) or hosted for you, e.g. Hetzner Storage Share
- Koofr (WebDAV) — cloud, Europe (Slovenia) · koofr.eu
- Mega S4 (S3-compatible) — cloud, multiple regions incl. Europe (Amsterdam) · mega.io
Example connection settings
The exact fields to enter for each tested provider:
| Provider | Field | Value / example |
|---|---|---|
| Koofr (WebDAV) | Server URL | https://app.koofr.net/dav/Koofr |
| Username | Your account email | |
| Password / app password | App password (create it in the Koofr dashboard) | |
| Nextcloud (WebDAV) | Server URL | https://your-domain/remote.php/dav/files/your-username |
| Username | Your Nextcloud username (not your email) | |
| Password / app password | App password (Settings → Security) | |
| Mega S4 (S3) | Endpoint | e.g. https://s3.eu-amsterdam.megas4.com (Europe / Amsterdam) |
| Region | e.g. eu-amsterdam (must match your endpoint) | |
| Bucket | e.g. websidian (create it in the Mega dashboard) | |
| Access key ID | Copy both from the Mega dashboard | |
| Secret access key |
WebDAV (Nextcloud)
In Nextcloud open Files, then click Files settings at the bottom-left of the file list. Copy the WebDAV URL shown there and paste it into the “Server URL” field when connecting.
Use an app password
In Nextcloud go to Settings → Security and create a dedicated app password, then use it instead of your normal account password.
Why an app password? When your account has two-factor authentication (2FA) enabled, your normal password does not work over WebDAV — an app password is required. It is also safer in general: you can revoke it at any time without changing your main password.
Koofr (WebDAV)
In the Koofr dashboard create a dedicated app password,
then connect with the WebDAV URL
https://app.koofr.net/dav/Koofr, your account email as the
username, and that app password. The screenshot below shows where to
create the app password.
S3 (Mega S4 & similar)
Create a bucket and an access key pair in your provider. For Mega S4
use the S4 endpoint and its region — for example
https://s3.eu-central-2.s4.mega.io and
eu-central-2 — then enter the bucket, access key ID and
secret access key when connecting.
Stuck? Your credentials are stored encrypted and the connection test shows a precise error if something is wrong. If you cannot resolve it, contact support.
Architecture (for technical users)
- HTTP-only auth token — the session cookie is HTTP-only, so it cannot be read or manipulated by XSS JavaScript attacks.
- NestJS backend with server-side rendered EJS views.
- Cloudflare Zero Trust tunnel into the
fabo011-cloud.deprivate network. - Docker Swarm for container orchestration.
- PostgreSQL database for user data; sensitive columns (TOTP, storage credentials) encrypted at rest.
- Browser WebCrypto for end-to-end encryption — all file contents are encrypted client-side (AES-256-GCM) before upload.
- Bring-your-own storage — each account connects its own S3-compatible or WebDAV backend as a blind blob store for the encrypted vault contents (keyed by a random per-account ID). websidian itself stores no vault files.
Scaling with Docker Swarm
websidian is stateless at the app layer — the encrypted vault lives in each user's own storage and all shared state is in PostgreSQL — so it scales horizontally with Docker Swarm mode. The app service runs as multiple replicas across swarm nodes (load-balanced via the swarm routing mesh / DNS round-robin); to handle more load you simply raise the replica count or add nodes. Cloudflare tunnel replicas front the cluster, and a single PostgreSQL instance (on a manager node) holds accounts and the encrypted storage credentials.
Self-hosting
Three ways to run your own instance. All use the published image
ghcr.io/fabo011/websidian:latest.
Choose your setup
-
Everything, including Nextcloud — websidian, a Cloudflare
tunnel, PostgreSQL and a Nextcloud server (WebDAV storage) all on your
machine, sharing one Postgres server. Use
docker-compose-complete-example.yml. -
websidian + tunnel + PostgreSQL, external storage —
self-host the app, the tunnel and the database, then connect an external
S3/WebDAV provider for the files (
USER_STORAGE_ENABLED=true). Start from the samedocker-compose-complete-example.ymland drop the Nextcloud service. -
websidian + tunnel, no PostgreSQL — the leanest setup:
without Postgres, websidian falls back to a minimal SQLite database and
local storage. Use
docker-compose-min.yaml.
Cloudflare Tunnel is only an example — any reverse proxy or zero-trust tunnel that terminates TLS works just as well (Caddy, nginx, Traefik, …).
HTTPS is required for any access other than
http://localhost. It is not only a security best practice:
end-to-end encryption uses the browser WebCrypto API
(crypto.subtle), which browsers only expose in a
secure context — i.e. HTTPS (or localhost). Over plain HTTP on
a real domain or IP the crypto API is unavailable and the app will not
work — this affects smartphones in particular. Put a
reverse proxy or tunnel with a valid TLS certificate in front (Caddy,
nginx, Traefik, Cloudflare Tunnel, …) and serve the app over
https://, with APP_URL and
CORS_ORIGINS set to your https:// domain.
You do not need Docker secrets to self-host — a plain
.env file works. The app reads each secret from
<NAME>_FILE when that is set, otherwise from the
normal environment variable. Docker secrets are only used in the
production Swarm deployment.
Minimal (SQLite, local storage)
Everything in one container — no database, no external storage to connect. Best for a single user or a small private group. Data is kept in a local volume.
1. Create a file named docker-compose.yaml,
paste this in and save:
services:
websidian:
image: ghcr.io/fabo011/websidian:latest
container_name: websidian
restart: unless-stopped
ports:
- "3065:3065"
environment:
DB_TYPE: sqlite # local SQLite, no external database
DATA_ROOT: /data # database + your vault files
USER_STORAGE_ENABLED: "false"
ALLOW_REGISTRATION: "true" # set false after you register
APP_URL: "http://localhost:3065"
JWT_SECRET: "change-me" # change before exposing publicly
ENCRYPTION_KEY: "change-me" # change before exposing publicly
volumes:
- websidian-data:/data
volumes:
websidian-data:
2. Start it from the same folder:
docker compose up -d
3. Open http://localhost:3065 and register
the first account. Change JWT_SECRET and
ENCRYPTION_KEY before exposing the app publicly —
the defaults are public and insecure. Set
ALLOW_REGISTRATION=false after registering to stop new
sign-ups.
Prefer a single command? Same setup, no compose file needed:
docker run -d --name websidian -p 3065:3065 \
-e DB_TYPE=sqlite -e DATA_ROOT=/data -e USER_STORAGE_ENABLED=false \
-e JWT_SECRET=change-me -e ENCRYPTION_KEY=change-me \
-v websidian-data:/data \
ghcr.io/fabo011/websidian:latest
Complete (PostgreSQL + tunnel)
For a public deployment: PostgreSQL for the database and a Cloudflare
(or any) tunnel in front. Use
docker-compose-complete-example.yml as the starting point,
set your own values in a .env file next to it, then run:
docker compose -f docker-compose-complete-example.yml up -d
At minimum set JWT_SECRET, ENCRYPTION_KEY,
DB_PASSWORD, APP_URL and
CORS_ORIGINS. With USER_STORAGE_ENABLED=true
each account connects its own S3/WebDAV storage; leave it
false to store vaults locally.
Developer area
websidian is open source and community-driven. Help triage issues or join the contributor chat.
Chat with contributors on our DeltaChat channel.
Both links are configurable via the CODETRIAGE_BADGE and
DELTACHAT_CHANNEL environment variables; unset, they fall
back to the upstream project's own badge and channel.