# Installation Guide ## Prerequisites - Docker (or Docker Compose) - A Linux host (x86_64 or ARM64, e.g. Synology NAS) ## Quick Install ```bash # 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: ```nginx 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: ```bash docker build --platform linux/arm64 -t markdownhub . ``` ## Updating ```bash 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 ```bash # 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 ```bash 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: ```bash 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: ```bash screen -dmS mh-daemon python3 daemon/build_daemon.py ``` ## CLI Tool (Optional) Build the `mdsync` CLI: ```bash cd markdown-hub go build -o mdsync ./cmd/mdsync sudo mv mdsync /usr/local/bin/ ``` Usage: ```bash 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).