Sign inSign up

tallon43/md-library

By tallon43

•Updated 8 days ago

Self-hosted personal Markdown notes library: catalog, nested collections, editor & full-text search

Image
0

1.1K

tallon43/md-library repository overview

⁠md-library

A self-hosted personal library for Markdown notes: write, upload, organise, read and edit notes, documentation, recipes, journals or snippets from a catalog styled like a library card index. Built to run in Docker on a home server (TrueNAS SCALE and friends), with configurable storage paths.

Sister app of pdf-library: same catalog, nested collections, role-based login, per-user sharing and Docker deployment — but here the content is editable Markdown, with an editor, rendered preview, autosave and full-text search.

Your notes are stored as plain .md files on disk, not inside the database. You can read, back up or move them with any tool you like.

⁠Features

  • Markdown editor (CodeMirror 6) with live preview, side by side or tabbed on mobile.
  • GitHub Flavored Markdown: tables, task lists, strikethrough, links and syntax-highlighted code.
  • Autosave with a 2 s debounce, an always-visible save indicator, an unload warning and Ctrl/Cmd+S to save immediately.
  • Data-loss protection: if the note changed elsewhere while you were editing, the save stops and you choose what to do (overwrite, reload or download your version). A draft mirror is kept in the browser, and files are written to disk atomically.
  • Upload one or many .md files at once, with per-file progress and errors.
  • YAML front matter (--- ... ---) is preserved verbatim in the file, hidden from the preview and never used to derive the title.
  • Nested collections with unlimited depth. Deleting a collection never deletes notes: they are left uncategorised and subfolders move up one level.
  • Sortable, filterable catalog with an excerpt of the first lines on each card.
  • Full-text search powered by SQLite FTS5: searches titles and body, is accent-insensitive, supports prefixes and highlights the matching snippet.
  • Role-based login: admin (full control) and user (read only), with per-user collection sharing.
  • English and Spanish interface, remembered per user.
  • Download any note as .md.

⁠Tags & architectures

  • latest, 1.0.0
  • linux/amd64, linux/arm64

⁠Quick start

Create a .env file:

PORT=3000
MAX_UPLOAD_MB=5
# Generate one with: openssl rand -hex 32
JWT_SECRET=
ADMIN_USER=admin
ADMIN_PASSWORD=
STORAGE_HOST_PATH=./storage
DB_HOST_PATH=./data

And a docker-compose.yml:

services:
  md-library:
    image: tallon43/md-library:latest
    container_name: md-library
    restart: unless-stopped
    ports:
      - "${PORT:-3000}:3000"
    environment:
      PORT: 3000
      NOTES_STORAGE_PATH: /data/storage
      DB_PATH: /data/db/library.db
      MAX_UPLOAD_MB: ${MAX_UPLOAD_MB:-5}
      JWT_SECRET: ${JWT_SECRET:?Set JWT_SECRET in .env}
      ADMIN_USER: ${ADMIN_USER:-admin}
      ADMIN_PASSWORD: ${ADMIN_PASSWORD:-}
    volumes:
      - ${STORAGE_HOST_PATH:-./storage}:/data/storage
      - ${DB_HOST_PATH:-./data}:/data/db

Then:

docker compose up -d
docker compose logs -f md-library

⁠Environment variables

VariableDescriptionDefault
PORTServer port3000
NOTES_STORAGE_PATHWhere the real .md files are stored/data/storage
DB_PATHPath to the SQLite metadata file/data/db/library.db
MAX_UPLOAD_MBPer-file upload and per-save size limit (MB)5
JWT_SECRETSecret used to sign the session JWT (required)—
SESSION_DAYSSession lifetime in days (JWT and cookie)7
ADMIN_USERAdmin user created on first runadmin
ADMIN_PASSWORDAdmin password. If empty, a random one is generated and printed once in the log(generated)

⁠Volumes

  • /data/storage — the .md note files.
  • /data/db — the SQLite database (metadata and the full-text index).

⁠First login

On first run an admin user is created. If you did not set ADMIN_PASSWORD, the generated password is printed once in the container log — save it, it will not be shown again. There is no public sign-up; further users are created by the admin from the Users screen.

⁠Notes

  • A single container serves both the API and the compiled frontend on one port.
  • Back up both volumes: the .md files hold the text, but titles, collections, users and dates live in the database. If the search index ever falls out of sync with the notes, it rebuilds itself on startup by reading the files from disk.
  • Put it behind a reverse proxy with TLS if you expose it outside your LAN.

Tag summary

Content type

Image

Digest

sha256:d6576857b…

Size

77.3 MB

Last updated

8 days ago

docker pull tallon43/md-library