master
MarkdownHub
Self-hosted collaborative markdown workspace with real-time editing, Git integration, and AI-powered code generation.
Features
- Three editor modes: WYSIWYG (Milkdown), raw markdown, and split-pane with live preview
- File management: Tree-based file browser, folders, search, drag-and-drop, rename, trash
- Git versioning: Auto-commit on save, full history, diff viewer, restore previous versions
- External Git sync: Per-user remotes (Gitea, GitHub, etc.), push/pull on demand
- Real-time collaboration: Yjs CRDT via WebSocket — multiple users editing simultaneously
- Sharing: Share files/folders with other users (read-only or read-write)
- AI integration: Verify specs, generate prompts, summarize — via LiteLLM/vLLM
- AI Build Pipeline: Write a spec → verify → build entire project → push to Gitea
- Authentication: Local accounts, LDAP/SLDAP, TOTP 2FA, group-based access control
- Light/Dark theme: Toggle in UI, persisted in preferences
- Export: PDF, HTML, raw markdown download
- Image upload: Drag-drop images into the editor
- PWA / Offline: Service worker, IndexedDB caching, sync on reconnect
- Multi-device: Responsive with mobile hamburger menu
- Docker deployment: Single container, easy backup
- Admin panel: User management, LDAP configuration (no restart needed)
- Security: Rate limiting, encrypted tokens, audit log, password complexity
Quick Start
git clone https://git.aholck.net/anders-pub/markdown-hub.git
cd markdown-hub
docker build -t markdownhub .
docker run -d --name markdownhub \
--restart unless-stopped \
-p 8080:8080 \
-v ./data:/app/data \
-e MH_SECRET="$(openssl rand -hex 32)" \
markdownhub
Default admin: admin@localhost / admin — change password immediately.
See INSTALL.md for full deployment guide.
Configuration
Environment variables:
| Variable | Default | Description |
|---|---|---|
MH_PORT |
8080 |
Server port |
MH_DATA_DIR |
./data |
Data directory (SQLite + files) |
MH_SECRET |
dev-secret-change-me |
JWT signing secret |
MH_ADMIN_EMAIL |
admin@localhost |
Initial admin email |
MH_ADMIN_PASSWORD |
admin |
Initial admin password |
MH_AI_ENDPOINT |
— | LiteLLM-compatible API URL |
MH_AI_API_KEY |
— | API key for AI endpoint |
MH_AI_MODEL |
gpt-4 |
Default model for AI features |
MH_LDAP_URL |
— | LDAP server (ldap:// or ldaps://) |
MH_LDAP_BIND_DN |
— | Service account DN |
MH_LDAP_BIND_PASS |
— | Service account password |
MH_LDAP_BASE_DN |
— | Base DN for user search |
MH_LDAP_USER_FILTER |
(&(objectClass=inetOrgPerson)(uid=%s)) |
User search filter |
MH_LDAP_GROUP_FILTER |
— | Required group DN for login |
MH_LDAP_SKIP_TLS |
false |
Skip TLS verification |
LDAP settings can also be configured from the Admin panel (no restart needed).
Architecture
┌─────────────┐ ┌──────────────┐ ┌────────┐
│ Frontend │────▶│ Go Backend │────▶│ SQLite │
│ (Vue 3) │◀────│ (net/http) │ └────────┘
└─────────────┘ │ │────▶ Filesystem (.md files)
│ │────▶ Git (per-user repos)
│ │◀───▶ LDAP (optional)
└──────────────┘
│
┌──────▼───────┐ ┌────────┐
│ Build Daemon │────▶│ Gitea │
│ (Python) │ └────────┘
└──────────────┘
- Backend: Go 1.23, stdlib
net/http, SQLite (modernc.org/sqlite), gorilla/websocket - Frontend: Vue 3, Vite, Milkdown, marked, Yjs
- Auth: JWT + bcrypt + TOTP + LDAP/SLDAP
- Git: Shell-based git operations (auto-commit, remotes, push/pull)
- AI: LiteLLM-compatible OpenAI API calls
- Build Daemon: Python (stdlib only), polls for build jobs
Project Structure
cmd/server/ — Web server entry point
cmd/mdsync/ — CLI sync tool
internal/api/ — HTTP handlers & routing
internal/auth/ — JWT, bcrypt, TOTP, LDAP
internal/collab/ — Real-time collaboration (Yjs WebSocket hub)
internal/db/ — SQLite schema & migrations
internal/files/ — File CRUD & search
internal/git/ — Git operations
internal/crypto/ — AES-256-GCM encryption
daemon/ — Build daemon (Python)
frontend/ — Vue 3 SPA
CLI Tool
go build -o mdsync ./cmd/mdsync
mdsync login https://md.example.com you@example.com password
mdsync pull .
mdsync push .
mdsync status
Backup & Restore
All data lives in the data/ volume:
data/db/markdownhub.db— SQLite databasedata/files/{user_id}/— User markdown files (also git repos)
# Backup
cp -r ./data ./backup-$(date +%Y%m%d)
# Restore
docker stop markdownhub
rm -rf ./data && cp -r ./backup-YYYYMMDD ./data
docker start markdownhub
License
MIT — Anders Holck 2026
Description
Languages
Go
48.3%
Vue
41%
Python
5.7%
JavaScript
4.3%
Dockerfile
0.4%
Other
0.3%