Quick Start
Get mdnest running in under 3 minutes — solo first, then add SSO + collaboration when you're ready.
Prerequisites
- Docker and Docker Compose
- Git, only for the guided setup (option B)
1. Solo install
A. One compose file (fastest)
No clone, nothing to build:
mkdir mdnest && cd mdnest
curl -fsSLo docker-compose.yml https://raw.githubusercontent.com/mahsanamin/mdnest/main/deploy/compose/docker-compose.yml
echo "MDNEST_PASSWORD=$(openssl rand -base64 18)" > .env
echo "MDNEST_JWT_SECRET=$(openssl rand -hex 32)" >> .env
docker compose up -d
Open http://localhost:3236 and sign in as admin with
the password in .env. Your notes are plain .md files in ./notes. Every
optional setting, including putting mdnest behind your own reverse proxy, is a
comment in the file. The setup guide
has the common changes and a docker run version.
B. Guided setup
A script writes the compose file from one config file. Use it if you want git sync, multi-user mode or built-in HTTPS set up for you.
git clone https://github.com/mahsanamin/mdnest.git
cd mdnest
./mdnest-server setup
Edit mdnest.conf — set credentials and mount at least one directory:
MDNEST_USER=admin
MDNEST_PASSWORD=your-secure-password
MDNEST_JWT_SECRET=a-long-random-string
MOUNT_notes=/path/to/your/notes
Build and start:
./mdnest-server rebuild
Open http://localhost:3236 and log in. That's it.
2. Go multi-user
Already running mdnest for yourself? Add a few lines to mdnest.conf to enable multi-user mode with a three-tier role hierarchy and per-namespace grants:
AUTH_MODE=multi
POSTGRES_PASSWORD=a-secure-db-password
# Pick an identity provider:
USER_PROVIDER=local # username/password + per-user TOTP (default)
# or USER_PROVIDER=sso # corporate OIDC — see SSO setup
# or USER_PROVIDER=firebase # Firebase Auth + Firestore TOTP
# Optional: turn on real-time presence + cursor sharing + comments
ENABLE_LIVE_COLLAB=true
# Optional: emails auto-promoted to SuperAdmin on every server start
[email protected]
Then rebuild:
./mdnest-server rebuild
A Postgres container is added automatically. On first start the backend runs migrations and seeds your MDNEST_USER as the initial admin. Your existing notes are untouched — Postgres only stores users, grants, and namespace-admin assignments.
From the web UI, click your avatar → Admin Panel to invite teammates. The three roles you can assign:
- SuperAdmin — global. Manages everything. Set via
ADMIN_EMAILSor by another SuperAdmin. - Admin — namespace-scoped. Can invite users and manage grants only for the namespaces they administer. Assigned in the Namespace Admins tab.
- Collaborator — sees only the namespaces / paths they have explicit grants for.
3. Team install with corporate SSO (recommended)
For a small company deploying mdnest as a shared knowledge base:
# Auth
AUTH_MODE=multi
USER_PROVIDER=sso
ENABLE_LIVE_COLLAB=true
GRANT_MAX_DEPTH=3
# OIDC client from your IdP — see [SSO setup](docs.html#sso-setup)
SSO_ISSUER_URL=https://accounts.google.com # or your IdP
SSO_CLIENT_ID=...
SSO_CLIENT_SECRET=...
SSO_ALLOWED_DOMAINS=example.com # optional but recommended
SSO_PROVIDER_LABEL=Google # button label
# Auto-promote your ops folks to SuperAdmin
[email protected],[email protected]
# Built-in HTTPS via Caddy + Let's Encrypt
CADDY_DOMAIN=notes.example.com
FRONTEND_ORIGIN=https://notes.example.com
# Secrets
MDNEST_JWT_SECRET=<long-random-string>
POSTGRES_PASSWORD=<long-random-string>
# Mounts (one per team / topic)
MOUNT_engineering=/srv/notes/engineering
MOUNT_design=/srv/notes/design
MOUNT_ops=/srv/notes/ops
./mdnest-server rebuild. Caddy provisions a TLS certificate, the backend stays loopback-only, and your team signs in at https://notes.example.com with their existing corporate Google / Okta / Entra account. The IdP enforces MFA where it's already configured. mdnest itself owns the per-namespace authorization layer.
The ADMIN_EMAILS users land as SuperAdmin on first login. From there they invite teammates in the admin panel and assign per-team Admins via Namespace Admins.
See SSO Setup for IdP-specific instructions.
Remote access (solo)
For a personal install, Tailscale is the simplest way to reach mdnest from other devices:
tailscale serve --bg --https 3236 http://127.0.0.1:3236
Access from any device on your tailnet at https://your-server.tailnet.ts.net:3236. No firewall ports opened, end-to-end encrypted.
For a team install you typically don't need Tailscale — Caddy + a public domain handles it.
Install the CLI on any machine
Your colleagues don't need the full server — just the CLI to access notes from their terminal:
curl -fsSL https://raw.githubusercontent.com/mahsanamin/mdnest/main/install-cli.sh | bash
Then login with an API token (Settings → API Tokens in the web UI). Each server gets a short alias (@work, @home):
mdnest login @work https://notes.example.com mdnest_abc...
# or let the CLI auto-pick the alias from the server's SERVER_ALIAS
mdnest login https://notes.example.com mdnest_abc...
Use it from anywhere:
mdnest list @work # list namespaces
mdnest list @work/engineering # files in a namespace
mdnest read @work/engineering/architecture.md # read a note
mdnest write @work/engineering/draft.md "..." # overwrite
mdnest append @work/team/log.md "$(date) standup" # append
mdnest search @work/product "roadmap" # search a namespace
echo "from pipe" | mdnest write @work/eng/draft.md -
API tokens inherit the creator's current access at request time (v3.5.0+). If your namespace-admin scope is revoked, your token loses that access immediately on the next request. Works on macOS and Linux. No dependencies beyond bash and curl.
What's next
- Setup & Configuration — every option, env var, mount layout
- User Guide — editor, comments, live collab, roles
- Security — threat model, identity, authorization
- SSO Setup — Google Workspace, Okta, Microsoft Entra, Keycloak, Auth0
- API Reference — REST API with curl examples
- CLI —
mdnestcommand-line tool - Changelog — what's new
Found a bug or have a suggestion? Open an issue on GitHub.