Files

5.4 KiB

Installation Guide

Prerequisites

  • Docker (or Docker Compose)
  • A Linux host (x86_64 or ARM64, e.g. Synology NAS)

Quick Install

# Clone the repo
git clone https://git.aholck.net/anders-pub/markdown-hub.git
cd markdown-hub

# Build the image
docker build -t markdownhub .

# Run
docker run -d \
  --name markdownhub \
  --restart unless-stopped \
  -p 8080:8080 \
  -v /path/to/data:/app/data \
  -e MH_SECRET="$(openssl rand -hex 32)" \
  -e MH_ADMIN_EMAIL="you@example.com" \
  -e MH_ADMIN_PASSWORD="changeme" \
  markdownhub

Open http://your-host:8080 and log in with the admin credentials above.

Change your password immediately in ⚙️ Preferences after first login.

Environment Variables

Variable Required Default Description
MH_SECRET Yes dev-secret-change-me JWT signing key. Generate with openssl rand -hex 32
MH_ADMIN_EMAIL No admin@localhost Admin email (only used on first run)
MH_ADMIN_PASSWORD No admin Admin password (only used on first run)
MH_PORT No 8080 Internal port (change the -p mapping instead)
MH_DATA_DIR No /app/data Data directory inside container
MH_AI_ENDPOINT No LiteLLM/OpenAI-compatible API URL for AI features
MH_AI_API_KEY No API key for AI endpoint
MH_AI_MODEL No gpt-4 Default model name
MH_LDAP_URL No LDAP server URL (e.g. ldap://ldap.example.com:389)
MH_LDAP_BIND_DN No Service account DN for user search
MH_LDAP_BIND_PASS No Service account password
MH_LDAP_BASE_DN No Base DN for user search (e.g. dc=example,dc=com)
MH_LDAP_USER_FILTER No (&(objectClass=inetOrgPerson)(uid=%s)) LDAP search filter (%s = username)
MH_LDAP_SKIP_TLS No false Skip TLS verification (for self-signed certs)

LDAP Notes

  • Use ldaps://host:636 for SLDAP (LDAP over TLS)
  • LDAP settings can also be configured from the Admin panel (⚙️👤) without restarting
  • If a required group is set, only users who are members of that group can log in
  • On first LDAP login, a local user is auto-created (for preferences, file storage, etc.)
  • Local accounts still work alongside LDAP — local auth is tried first

Data Volume

Mount a persistent volume to /app/data. This contains:

/app/data/
├── db/
│   └── markdownhub.db    # SQLite database (users, permissions, jobs)
└── files/
    └── {user-id}/         # Each user's markdown files + git repo

Reverse Proxy (HTTPS)

Put behind nginx/Caddy/Traefik for HTTPS. Example nginx config:

server {
    listen 443 ssl;
    server_name md.example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # WebSocket for real-time collab
    location /ws/ {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
    }
}

Synology NAS

  1. Install Docker from Package Center
  2. SSH into your NAS or use Task Scheduler
  3. Run the commands from Quick Install above
  4. Use /volume1/docker/markdownhub/data as your data path

For ARM-based Synology (e.g. DS124), build with:

docker build --platform linux/arm64 -t markdownhub .

Updating

cd markdown-hub
git pull
docker build -t markdownhub .
docker rm -f markdownhub
docker run -d \
  --name markdownhub \
  --restart unless-stopped \
  -p 8080:8080 \
  -v /path/to/data:/app/data \
  -e MH_SECRET="your-existing-secret" \
  markdownhub

Your data persists in the volume — only the app binary and frontend are replaced.

Backup

# Stop (optional, for consistency)
docker stop markdownhub

# Copy data
cp -r /path/to/data /path/to/backup/markdownhub-$(date +%Y%m%d)

# Restart
docker start markdownhub

Restore

docker stop markdownhub
rm -rf /path/to/data
cp -r /path/to/backup/markdownhub-YYYYMMDD /path/to/data
docker start markdownhub

Build Daemon (Optional)

For the AI build pipeline, run the daemon on a machine with Pi installed:

export MH_URL=https://md.example.com
export MH_DAEMON_TOKEN=your-api-token
export MH_WORKSPACE=~/builds
python3 daemon/build_daemon.py

Or run in screen/tmux:

screen -dmS mh-daemon python3 daemon/build_daemon.py

CLI Tool (Optional)

Build the mdsync CLI:

cd markdown-hub
go build -o mdsync ./cmd/mdsync
sudo mv mdsync /usr/local/bin/

Usage:

mdsync login https://md.example.com you@example.com yourpassword
mdsync pull .          # Download all files to current directory
mdsync push .          # Upload local .md files to server
mdsync status          # Check git sync status

Troubleshooting

Can't login: Check MH_SECRET hasn't changed between restarts. If it has, existing tokens are invalid — just login again.

Port in use: Change the host port: -p 9090:8080

Permission denied on data volume: Ensure the directory is writable: chmod 777 /path/to/data

WebSocket not connecting (collab): Make sure your reverse proxy forwards /ws/ with upgrade headers (see nginx example above).