Skip to content
KamiNekoPublic

About

Your Markdown notes, self-hosted, in any browser. Private by design.

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Notes

Your Markdown notes, self-hosted, in any browser. Private by design.

A fast, modern notes app for your home server: notebooks, tags, search, attachments, to-dos and version history.
One Docker Compose stack, your own PostgreSQL, no cloud, no tracking, no third-party services.

CI CodeQL OpenSSF Scorecard License: MIT Security policy EU CRA aligned
.NET 10 PostgreSQL React Vite Tested with Playwright

Notes showing a note with a table and task list in dark mode

Get started Β· Features Β· Security Β· Documentation

Why Notes?

Your notes are some of the most personal data you have: plans, journals, passwords you shouldn't have written down, the things you think about at 2 a.m. They don't belong on someone else's server. Notes keeps them on yours, and makes them as pleasant to use as any cloud app, from any browser, on any device, with nothing to install.

  • 🏠 Self-hosted, all the way. The app and its database run in one Docker Compose stack, for example in a Proxmox LXC. Notes never calls home: no telemetry, no analytics, no external fonts or scripts.
  • πŸ” Security as a feature, not an afterthought. Hardened defaults, a strict Content Security Policy, a locked-down container, signed releases with SBOMs, and a public security policy. Built along the EU Cyber Resilience Act. More below.
  • πŸ“ Plain Markdown. Notes are GitHub-flavored Markdown with a few well-known extensions (math, Mermaid diagrams, highlights), so notes pasted in from other apps keep their formatting, and one click exports everything as Markdown files again. No lock-in.
  • πŸ‘₯ Accounts for the household. An administrator adds users; there is no public sign-up. Every user sees only their own notes, and not even administrators can read them in the app.
  • πŸ•°οΈ Nothing gets lost. Version history for every note, a trash, conflict detection between devices, and unsaved typing that survives a lost connection.
  • ⚑ Fast and small. A .NET backend and a React app in one container. A household runs comfortably on one CPU core and 1 GB of RAM.

Not included, on purpose: offline mode, sharing notes with others, and end-to-end encryption.

Features

πŸ“š Notebooks Nested notebooks; create, rename, move (into another notebook or to the top level) and delete them.
πŸ“ Markdown editor CodeMirror editor with Edit, Split and Preview modes, autosave and Ctrl+S. Formatting toolbar (also on phones) and shortcuts: Ctrl+B bold, Ctrl+I italic, Ctrl+E code, Ctrl+K link. Links to other notes via a search picker or Copy Markdown link.
✨ Rich rendering GitHub-flavored Markdown: tables, task lists, syntax-highlighted code blocks, plus math (KaTeX), Mermaid diagrams, ==highlight==, ++insert++, ~sub~ and ^sup^. HTML notes are shown as sanitized HTML.
πŸ–ΌοΈ Images & attachments Drop, paste or attach files; images are shown inline. The account menu shows how much space your attachments take, and attachments no note links to any more can be cleaned up automatically.
βœ… To-dos Create to-dos and tick them off, right from the note list. Set, change or clear due dates; overdue to-dos are highlighted.
🏷️ Tags Tag notes, browse by tag, rename and delete tags.
πŸ”Ž Search Instant search across titles and content (Ctrl+K): all words must match, "exact phrases", -word to exclude, and filters tag:, notebook:, type:todo, iscompleted:0.
πŸ•°οΈ Version history Before an editing session changes a note, its previous state is kept as a version. Preview any version, see what changed since (line by line), and restore it; the replaced text becomes a version too, so a restore can be undone. Optional retention period.
πŸ“¦ Export & import Download all your notes as a ZIP of Markdown files with front matter, in notebook folders, with attachments and working links. Import such a ZIP (or an Obsidian vault) into a new notebook, with tags, to-dos and links restored. Your notes are never locked in.
πŸ—‘οΈ Trash Deleted notes and notebooks go to the trash, where you can restore them or delete them permanently. Optionally emptied automatically after a number of days.
βš”οΈ Conflict detection If a note was changed in another tab or on another device while you edited it, you choose which version to keep.
πŸ‘₯ Users Administrators add accounts, reset passwords, grant the administrator role, set storage limits and delete users (account menu > Manage users). Everyone can change their own password.
πŸ” Two-factor sign-in Optional second step with any authenticator app (Aegis, Google Authenticator, 1Password, Bitwarden …): scan a QR code, keep 10 recovery codes. Administrators can turn it off for someone who lost their phone.
πŸ›Ÿ No lost typing Unsaved text is kept on the device while offline or after the session expires, saves retry when the connection returns, and you can restore a draft later.
πŸŒ— Light & dark mode Switch themes with one click.
πŸ“± Responsive Works on phones and tablets as well as on the desktop.

Security first

Notes is meant to be reachable from the internet, so it is built like it will be attacked.

πŸ”‘ Accounts Passwords hashed with PBKDF2-HMAC-SHA512 (210,000 iterations), 12 characters minimum (NIST SP 800-63B). Rate limits per address and an account lock after 10 failed sign-ins. Unknown accounts look exactly like wrong passwords. Optional two-factor sign-in with an authenticator app (TOTP) and one-time recovery codes.
πŸͺ Sessions Server-side sessions, stored only as hashes. HttpOnly, SameSite=Strict, Secure __Host- cookie over HTTPS. 30 days idle, 90 days at most. See where you are signed in and sign out a lost device (account menu > Signed-in devices); a password change signs out your other devices too.
πŸ›‘οΈ Browser Strict Content Security Policy without inline scripts, sanitized Markdown and HTML, CSRF protection by Origin check, HSTS, frame-ancestors 'none', no caching of API answers. Risky attachments are always downloads.
🧱 Isolation Every query is scoped to the signed-in user, covered by tests. The container runs as non-root with a read-only filesystem, no Linux capabilities and no-new-privileges; the database is never published.
πŸ“œ Audit trail Sign-ins, failures, locks, password and account changes and refused requests go to a security log with stable event ids, without passwords or tokens.
πŸ“¦ Supply chain Lock files for every dependency, base images pinned by digest, GitHub Actions pinned by commit. CodeQL, dependency review, NuGet and npm audit and an image scan on every change; Dependabot for updates. Releases come with SBOMs and signed build provenance you can verify with gh attestation verify.
πŸ‡ͺπŸ‡Ί CRA Every essential requirement of the EU Cyber Resilience Act is mapped to how Notes meets it, gaps included: CRA compliance. As a free, non-commercial project Notes is outside the CRA's scope and follows it voluntarily.

Found a vulnerability? Please report it privately, as described in the security policy. Running Notes on the internet? Read the security guide and its hardening checklist first.

Screenshots

Light mode with an embedded image
Light mode, with an image attachment
Version history of a note
Version history: see what changed since an earlier state, preview it and restore it
Split-view Markdown editor
Split-view editor with live preview
Note list on a phone Note on a phone
On a phone

Getting started

You need a Linux host with Docker and the Docker Compose plugin. In a Proxmox LXC, enable nesting (and keyctl) under Options > Features and install Docker inside it.

git clone https://github.com/KamiNeko/notes.git
cd notes
cp .env.example .env && chmod 600 .env
# Edit .env: POSTGRES_PASSWORD (openssl rand -hex 24), NOTES_ADMIN_EMAIL, NOTES_ADMIN_PASSWORD (12+ characters)
docker compose up -d --build

Open http://<host>:8080 and sign in with the administrator account from .env. It is created on the first start; afterwards remove NOTES_ADMIN_PASSWORD from .env. Add more users in the app (account menu > Manage users).

The stack has two containers: notes (the app, port 8080) and notes-db (PostgreSQL 17, not published). Attachments live in the notes-files volume, everything else in the database (notes-db volume).

Important

Put Notes behind a reverse proxy with HTTPS (Caddy, Traefik, Nginx Proxy Manager, …) before you use it outside your home network, and set NOTES_PUBLIC_URL and NOTES_TRUST_PROXY=true. The deployment guide has ready-to-use proxy configurations.

Released versions are also published as signed multi-arch images (ghcr.io/kamineko/notes:<version>); see using the published image. Updating, backups, restore, the command line and removing Notes are all covered in the deployment guide.

Configuration

Settings go into .env; docker-compose.yml passes them to the app. Every app setting can also be set directly as Notes__<Name> (ASP.NET Core configuration). Settings are checked on start: an invalid value (say Notes__CookieSecure=yes or a NOTES_PUBLIC_URL without https://) stops the app with a message naming it, instead of quietly running with a different policy.

.env App setting Default Meaning
POSTGRES_PASSWORD (required) Password of the database user notes.
NOTES_ADMIN_EMAIL, NOTES_ADMIN_PASSWORD Notes__Admin__Email, Notes__Admin__Password First administrator, created while there are no users yet.
HOST_PORT 8080 Host port the app is published on, e.g. 127.0.0.1:8080 to reach it only through a local proxy.
NOTES_PUBLIC_URL Notes__PublicUrl The URL you open, e.g. https://notes.example.com. Allowed as request origin; with https:// the session cookie is Secure.
NOTES_TRUST_PROXY Notes__TrustProxy false Trust X-Forwarded-For/-Proto/-Host from a reverse proxy.
NOTES_TRUSTED_PROXIES Notes__TrustedProxies private networks Addresses or CIDR ranges the proxy connects from (comma-separated). Only needed when it isn't on a private network.
NOTES_VERSION_RETENTION_DAYS Notes__VersionRetentionDays 0 Delete versions older than this many days (0 keeps all).
NOTES_TRASH_RETENTION_DAYS Notes__TrashRetentionDays 0 Delete notes and notebooks that have been in the trash this many days (0 keeps them until deleted by hand).
NOTES_MAX_UPLOAD_MB Notes__MaxUploadMb 25 Largest attachment.
NOTES_ATTACHMENT_CLEANUP_DAYS Notes__AttachmentCleanupDays 0 Delete attachments that no note, trashed note or version links to this many days after upload, and stray files without a database row (0 keeps them).
NOTES_QUOTA_MB Notes__QuotaMb 0 Attachment space per user in MB (0: unlimited). Administrators can set another limit per user.
NOTES_MAX_IMPORT_MB Notes__MaxImportMb 200 Largest ZIP accepted by Import notes.
NOTES_ALLOW_REMOTE_IMAGES Notes__AllowRemoteImages false Show https: images from other websites in notes. Off by default because each remote image tells its host who opened the note.
Notes__VersionIntervalMinutes 10 Edits within this many minutes of the last version don't create another one.
Notes__SessionLifetimeDays, Notes__SessionMaxAgeDays 30, 90 A session ends after this many days without use, and at the latest this many days after sign-in.
Notes__LoginMaxFailures 10 Failed sign-ins within 15 minutes that lock an account for 15 minutes.
Notes__CookieSecure auto auto (Secure over HTTPS), true or false.
Notes__RateLimitMax, Notes__LoginRateLimitMax 1000, 30 API requests and sign-in attempts per client address and 15 minutes.

Moving your notes in and out

Into Notes: paste a note's Markdown into a new note and it keeps its formatting. Links to other notes and attachments are written as :/<32-character id>; they work once the target exists here with that id, and attachments need to be added again. There is no automatic importer yet.

Away from Notes: account menu > Export notes downloads all your notes as a ZIP: one Markdown file per note with YAML front matter (title, dates, tags, to-do state), folders per notebook, attachments in _resources/, and links rewritten to relative paths. Obsidian and most Markdown editors open it directly.

Documentation

Deployment guide Install (also on Proxmox), reverse proxy and HTTPS, updates, backup and restore, command line, removing Notes, troubleshooting
Security guide Security model, what Notes defends against and what not, hardening checklist, security log, data protection
Security policy Supported versions, how to report a vulnerability, response times, verifying releases
CRA compliance How Notes meets the EU Cyber Resilience Act requirement by requirement
Architecture (arc42) Goals, context, building blocks, runtime, deployment, concepts, decisions, quality scenarios, risks, glossary
Changelog What changed in each version, including breaking changes

Development

Everything needed (the .NET 10 SDK, Node.js 24, PostgreSQL 17) comes with the dev container: open the folder in VS Code (from WSL too) and choose Reopen in Container. Without it, install those three yourself and create a database user notes with password notes.

# Backend: API on http://localhost:5080, Development settings seed a demo account
dotnet run --project backend/src/Notes.Api

# Client: http://localhost:5173, proxies /api to the backend
npm ci   # once: installs the client and packages/ui (npm workspaces)
npm --prefix client run dev

Demo login: demo@notes.test / demo-password.

backend/   .NET 10 API (minimal APIs, EF Core, PostgreSQL) and its integration tests
client/    React app (Vite, Tailwind, TanStack Query, CodeMirror 6)
  e2e/     Playwright smoke tests
packages/
  ui/      Shared UI package: shadcn/ui components, theme tokens, theme switch
docker/    Production Dockerfile
docs/      Guides, arc42 architecture, screenshots
Command
cd backend && dotnet test Backend integration tests (each test class gets its own database, NOTES_TEST_DATABASE)
npm --prefix client run lint / test / build Client lint, unit tests (Vitest), production build
npm --prefix packages/ui run lint / typecheck / test Shared UI package lint, type check, unit tests
npm --prefix client run test:e2e Playwright smoke tests; starts backend and client itself (E2E_DATABASE)
npm --prefix client run screenshots README screenshots into docs/images (backend and client must run)

CI runs all of these on every pull request, plus the security checks above and a Docker image build. See CONTRIBUTING.md for how to report bugs and send changes; CLAUDE.md has the same conventions in full, for contributors and AI assistants alike.

License

MIT

About

Your Markdown notes, self-hosted, in any browser. Private by design.

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages