managarten/docs/MATRIX_SELF_HOSTING.md
Till JS 22a73943e1 chore: complete ManaCore → Mana rename (docs, go modules, plists, images)
Final cleanup of references missed in previous rename commits:

- Dockerfiles: PUBLIC_MANA_CORE_AUTH_URL → PUBLIC_MANA_AUTH_URL
- Go modules: github.com/manacore/* → github.com/mana/* (7 go.mod files)
- launchd plists: com.manacore.* → com.mana.* (14 files renamed + content)
- Image assets: *_Manacore_AI_Credits* → *_Mana_AI_Credits* (11 files)
- .env.example files: ManaCore brand strings → Mana
- .prettierignore: stale apps/manacore/* paths → apps/mana/*
- Markdown docs (CLAUDE.md, /docs/*): mana-core-auth → mana-auth, etc.

Excluded from rename: .claude/, devlog/, manascore/ (historical content),
client testimonials, blueprints, npm package refs (@mana-core/*).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 12:26:10 +02:00

18 KiB

Matrix Self-Hosting auf Mac Mini

Plan für DSGVO-konformes Messaging mit Matrix/Synapse auf dem Mana Server.

Übersicht

┌─────────────────────────────────────────────────────────────────────┐
│  Internet                                                           │
│      │                                                              │
│      ▼                                                              │
│  Cloudflare Tunnel                                                  │
│      │                                                              │
│      ├─── matrix.mana.how ──────► Synapse (Port 8008)               │
│      ├─── element.mana.how ─────► Element Web (Port 8087)           │
│      └─── (bestehende Services)                                     │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  Docker Container                                            │   │
│  │                                                              │   │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐   │   │
│  │  │   Synapse    │  │  Element Web │  │  Matrix Bots     │   │   │
│  │  │   (8008)     │  │   (8087)     │  │  (NestJS)        │   │   │
│  │  └──────┬───────┘  └──────────────┘  └────────┬─────────┘   │   │
│  │         │                                      │             │   │
│  │         ▼                                      ▼             │   │
│  │  ┌──────────────┐                     ┌──────────────┐      │   │
│  │  │  PostgreSQL  │                     │    Ollama    │      │   │
│  │  │  (matrix db) │                     │   (11434)    │      │   │
│  │  └──────────────┘                     └──────────────┘      │   │
│  └─────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────┘

DSGVO-Vorteile

Aspekt Telegram Matrix (Self-Hosted)
Datenstandort Dubai/Singapur Mac Mini (Deutschland)
AV-Vertrag Nicht möglich Nicht nötig (eigene Daten)
E2E-Verschlüsselung Nur Secret Chats Standard für alle Räume
Metadaten Bei Telegram Lokal gespeichert
Löschung Abhängig von Telegram Volle Kontrolle

Phase 1: Synapse Homeserver

1.1 Datenbank erstellen

ssh mana-server

# Neue Datenbank für Matrix
docker exec mana-postgres psql -U postgres -c "CREATE DATABASE matrix;"
docker exec mana-postgres psql -U postgres -c "CREATE USER synapse WITH PASSWORD 'synapse-secure-password';"
docker exec mana-postgres psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE matrix TO synapse;"

1.2 Synapse Konfiguration erstellen

# Verzeichnis erstellen
mkdir -p ~/projects/mana-monorepo/docker/matrix

# Synapse Config generieren (einmalig)
docker run -it --rm \
  -v ~/projects/mana-monorepo/docker/matrix:/data \
  -e SYNAPSE_SERVER_NAME=mana.how \
  -e SYNAPSE_REPORT_STATS=no \
  matrixdotorg/synapse:latest generate

1.3 homeserver.yaml anpassen

Datei: docker/matrix/homeserver.yaml

server_name: "mana.how"
pid_file: /data/homeserver.pid

listeners:
  - port: 8008
    tls: false
    type: http
    x_forwarded: true
    resources:
      - names: [client, federation]
        compress: false

database:
  name: psycopg2
  args:
    user: synapse
    password: "synapse-secure-password"
    database: matrix
    host: postgres
    port: 5432
    cp_min: 5
    cp_max: 10

# Logging
log_config: "/data/mana.how.log.config"

# Media Store (lokaler Speicher für Medien)
media_store_path: /data/media_store
max_upload_size: 50M

# Registrierung
enable_registration: false
enable_registration_without_verification: false

# Admin-Account beim ersten Start erstellen
# Nach dem Start: docker exec -it synapse register_new_matrix_user -c /data/homeserver.yaml http://localhost:8008 -a

# Rate Limiting (für Bots erhöhen)
rc_message:
  per_second: 5
  burst_count: 20

rc_registration:
  per_second: 0.5
  burst_count: 5

# Für Bot-Integration: Application Services erlauben
app_service_config_files: []

# DSGVO: Datenaufbewahrung begrenzen
retention:
  enabled: true
  default_policy:
    min_lifetime: 1d
    max_lifetime: 365d
  allowed_lifetime_min: 1d
  allowed_lifetime_max: 365d
  purge_jobs:
    - longest_max_lifetime: 3d
      interval: 12h
    - shortest_max_lifetime: 365d
      interval: 1d

# Telemetrie deaktivieren
report_stats: false

# Trusted Key Server (Matrix.org)
trusted_key_servers:
  - server_name: "matrix.org"

# Signing Key
signing_key_path: "/data/mana.how.signing.key"

1.4 Docker Compose Ergänzung

Füge zu docker-compose.macmini.yml hinzu:

  # ============================================
  # Matrix Synapse (Homeserver)
  # ============================================

  synapse:
    image: matrixdotorg/synapse:latest
    container_name: mana-synapse
    restart: always
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      SYNAPSE_CONFIG_PATH: /data/homeserver.yaml
    volumes:
      - ./docker/matrix:/data
      - synapse_media:/data/media_store
    ports:
      - "8008:8008"
    healthcheck:
      test: ["CMD", "curl", "-fSs", "http://localhost:8008/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  # ============================================
  # Element Web (Matrix Client)
  # ============================================

  element-web:
    image: vectorim/element-web:latest
    container_name: mana-element
    restart: always
    depends_on:
      synapse:
        condition: service_healthy
    volumes:
      - ./docker/matrix/element-config.json:/app/config.json:ro
    ports:
      - "8087:80"
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:80/"]
      interval: 30s
      timeout: 10s
      retries: 3

# Volumes ergänzen:
volumes:
  synapse_media:
    name: mana-synapse-media

1.5 Element Web Konfiguration

Datei: docker/matrix/element-config.json

{
  "default_server_config": {
    "m.homeserver": {
      "base_url": "https://matrix.mana.how",
      "server_name": "mana.how"
    },
    "m.identity_server": {
      "base_url": ""
    }
  },
  "brand": "Mana Chat",
  "integrations_ui_url": "",
  "integrations_rest_url": "",
  "integrations_widgets_urls": [],
  "disable_guests": true,
  "disable_3pid_login": true,
  "default_country_code": "DE",
  "show_labs_settings": false,
  "features": {
    "feature_video_rooms": true,
    "feature_group_calls": true
  },
  "room_directory": {
    "servers": ["mana.how"]
  },
  "setting_defaults": {
    "breadcrumbs": true
  },
  "default_theme": "dark"
}

1.6 Cloudflare Tunnel erweitern

Datei: ~/.cloudflared/config.yml

# Bestehende Einträge...

  - hostname: matrix.mana.how
    service: http://localhost:8008

  - hostname: element.mana.how
    service: http://localhost:8087

Nach Änderung:

launchctl stop com.cloudflare.cloudflared
launchctl start com.cloudflare.cloudflared

Phase 2: Synapse starten & Admin erstellen

2.1 Container starten

cd ~/projects/mana-monorepo

# Nur Synapse + Element starten
docker compose -f docker-compose.macmini.yml up -d synapse element-web

# Logs prüfen
docker logs -f mana-synapse

2.2 Admin-User erstellen

# Interaktiv einen Admin erstellen
docker exec -it mana-synapse register_new_matrix_user \
  -c /data/homeserver.yaml \
  http://localhost:8008 \
  -a

# Eingeben:
# Username: admin
# Password: (sicheres Passwort)
# Admin: yes

2.3 Testen

# Health Check
curl https://matrix.mana.how/health
# Erwartete Antwort: OK

# Federation Check
curl https://matrix.mana.how/_matrix/federation/v1/version
# Erwartete Antwort: {"server":{"name":"Synapse","version":"..."}}

# Element Web aufrufen
open https://element.mana.how

Phase 3: Bot-Räume einrichten

3.1 Räume erstellen (via Element)

  1. Anmelden bei https://element.mana.how mit Admin-Account
  2. Räume erstellen:
    • #ollama-bot:mana.how - AI Chat Bot
    • #stats-bot:mana.how - Analytics Reports
    • #project-doc-bot:mana.how - Projektdokumentation

3.2 Bot-User erstellen

# Bot-User für jeden Bot erstellen (nicht-Admin)
docker exec -it mana-synapse register_new_matrix_user \
  -c /data/homeserver.yaml \
  http://localhost:8008

# Erstelle:
# - ollama-bot (Password notieren)
# - stats-bot (Password notieren)
# - projectdoc-bot (Password notieren)

3.3 Access Tokens generieren

# Für jeden Bot ein Access Token holen
curl -X POST "https://matrix.mana.how/_matrix/client/v3/login" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "m.login.password",
    "user": "ollama-bot",
    "password": "bot-password"
  }'

# Response: {"access_token": "syt_xxx", ...}
# Token für .env speichern

Phase 4: Bot-Migration (NestJS)

4.1 Neue Package-Struktur

services/
├── telegram-ollama-bot/     # Alt (Telegram)
├── telegram-stats-bot/      # Alt (Telegram)
├── telegram-project-doc-bot/# Alt (Telegram)
│
├── matrix-ollama-bot/       # NEU (Matrix)
├── matrix-stats-bot/        # NEU (Matrix)
└── matrix-project-doc-bot/  # NEU (Matrix)

4.2 Dependencies

cd services/matrix-ollama-bot
pnpm add matrix-bot-sdk

4.3 Bot-Grundstruktur (Beispiel: Ollama Bot)

Datei: services/matrix-ollama-bot/src/bot/matrix.service.ts

import {
  MatrixClient,
  SimpleFsStorageProvider,
  AutojoinRoomsMixin,
  RichConsoleLogger,
  LogService,
} from 'matrix-bot-sdk';
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class MatrixService implements OnModuleInit, OnModuleDestroy {
  private client: MatrixClient;

  constructor(private config: ConfigService) {}

  async onModuleInit() {
    LogService.setLogger(new RichConsoleLogger());

    const homeserverUrl = this.config.get('MATRIX_HOMESERVER_URL');
    const accessToken = this.config.get('MATRIX_ACCESS_TOKEN');

    const storage = new SimpleFsStorageProvider('bot-storage.json');

    this.client = new MatrixClient(homeserverUrl, accessToken, storage);

    // Auto-join bei Einladungen
    AutojoinRoomsMixin.setupOnClient(this.client);

    // Message Handler
    this.client.on('room.message', this.handleMessage.bind(this));

    await this.client.start();
    console.log('Matrix bot started!');
  }

  async onModuleDestroy() {
    await this.client.stop();
  }

  private async handleMessage(roomId: string, event: any) {
    // Eigene Nachrichten ignorieren
    if (event.sender === await this.client.getUserId()) return;

    // Nur Text-Nachrichten
    if (event.content?.msgtype !== 'm.text') return;

    const body = event.content.body;

    // Command-Handler
    if (body.startsWith('!')) {
      await this.handleCommand(roomId, event, body);
    } else {
      // Normaler Chat → Ollama
      await this.handleChat(roomId, event, body);
    }
  }

  private async handleCommand(roomId: string, event: any, body: string) {
    const [command, ...args] = body.slice(1).split(' ');

    switch (command.toLowerCase()) {
      case 'help':
        await this.sendMessage(roomId, this.getHelpText());
        break;
      case 'models':
        // Liste verfügbare Modelle
        break;
      case 'clear':
        // Chat-History löschen
        break;
      // ... weitere Commands
    }
  }

  private async handleChat(roomId: string, event: any, message: string) {
    // Typing-Indikator senden
    await this.client.setTyping(roomId, true);

    // Ollama-Anfrage (wie bisher)
    const response = await this.ollamaService.chat(message);

    await this.client.setTyping(roomId, false);
    await this.sendMessage(roomId, response);
  }

  async sendMessage(roomId: string, message: string) {
    await this.client.sendMessage(roomId, {
      msgtype: 'm.text',
      body: message,
      format: 'org.matrix.custom.html',
      formatted_body: this.markdownToHtml(message),
    });
  }

  private getHelpText(): string {
    return `**Mana Ollama Bot**

Befehle:
- \`!help\` - Diese Hilfe
- \`!models\` - Verfügbare Modelle
- \`!model <name>\` - Modell wechseln
- \`!clear\` - Chat-Verlauf löschen

Einfach eine Nachricht schreiben für AI-Chat.`;
  }
}

4.4 Environment Variables

Datei: services/matrix-ollama-bot/.env

# Server
PORT=3311

# Matrix
MATRIX_HOMESERVER_URL=https://matrix.mana.how
MATRIX_ACCESS_TOKEN=syt_xxx

# Optional: Nur bestimmte Räume erlauben
MATRIX_ALLOWED_ROOMS=#ollama-bot:mana.how

# Ollama
OLLAMA_URL=http://host.docker.internal:11434
OLLAMA_MODEL=gemma3:4b
OLLAMA_TIMEOUT=120000

4.5 Docker Compose für Matrix Bots

  # ============================================
  # Matrix Ollama Bot
  # ============================================

  matrix-ollama-bot:
    image: ghcr.io/memo-2023/matrix-ollama-bot:latest
    container_name: mana-matrix-ollama-bot
    restart: always
    depends_on:
      synapse:
        condition: service_healthy
    environment:
      NODE_ENV: production
      PORT: 3311
      MATRIX_HOMESERVER_URL: http://synapse:8008
      MATRIX_ACCESS_TOKEN: ${MATRIX_OLLAMA_BOT_TOKEN}
      OLLAMA_URL: http://host.docker.internal:11434
      OLLAMA_MODEL: gemma3:4b
    volumes:
      - matrix_ollama_bot_data:/app/data
    ports:
      - "3311:3311"
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3311/health"]
      interval: 30s
      timeout: 10s
      retries: 3

# Volume ergänzen:
volumes:
  matrix_ollama_bot_data:
    name: mana-matrix-ollama-bot

Phase 5: Feature-Mapping Telegram → Matrix

Commands

Telegram Matrix Beschreibung
/start !help Hilfe anzeigen
/help !help Hilfe anzeigen
/models !models Modelle auflisten
/model x !model x Modell wechseln
/clear !clear Chat löschen
/status !status Bot-Status

Media-Handling

Feature Telegram Matrix
Foto senden ctx.message.photo m.image msgtype
Voice senden ctx.message.voice m.audio msgtype
Datei senden ctx.message.document m.file msgtype
Foto antworten ctx.replyWithPhoto() sendMessage() mit m.image

Beispiel: Media-Download in Matrix

async downloadMedia(event: any): Promise<Buffer> {
  const mxcUrl = event.content.url; // mxc://mana.how/abc123
  const httpUrl = this.client.mxcToHttp(mxcUrl);

  const response = await fetch(httpUrl);
  return Buffer.from(await response.arrayBuffer());
}

Phase 6: Health Check & Monitoring

Health Checks ergänzen

Datei: scripts/mac-mini/health-check.sh

# Matrix Synapse
if curl -sf http://localhost:8008/health > /dev/null; then
  echo "✅ Synapse: OK"
else
  echo "❌ Synapse: FAILED"
  FAILED_SERVICES="$FAILED_SERVICES synapse"
fi

# Element Web
if curl -sf http://localhost:8087/ > /dev/null; then
  echo "✅ Element Web: OK"
else
  echo "❌ Element Web: FAILED"
  FAILED_SERVICES="$FAILED_SERVICES element-web"
fi

# Matrix Ollama Bot
if curl -sf http://localhost:3311/health > /dev/null; then
  echo "✅ Matrix Ollama Bot: OK"
else
  echo "❌ Matrix Ollama Bot: FAILED"
  FAILED_SERVICES="$FAILED_SERVICES matrix-ollama-bot"
fi

Prometheus Metrics (optional)

Synapse exportiert Metrics auf Port 9000 (kann aktiviert werden):

# In homeserver.yaml ergänzen
enable_metrics: true
metrics_port: 9000

# prometheus.yml ergänzen
- job_name: 'synapse'
  static_configs:
    - targets: ['synapse:9000']

Zeitplan

Phase Aufgabe Aufwand
1 Synapse + Element aufsetzen 1-2h
2 Admin & Bot-User erstellen 30min
3 Bot-Räume einrichten 30min
4 Ersten Bot migrieren (Ollama) 2-4h
5 Weitere Bots migrieren je 1-2h
6 Monitoring & Alerts 1h

Gesamt: ~1 Tag für Grundsetup + Bot-Migration


Nächste Schritte

  1. docker/matrix/ Verzeichnis erstellen
  2. Synapse Config generieren
  3. Docker Compose erweitern
  4. Cloudflare Tunnel konfigurieren
  5. Synapse starten & testen
  6. Admin-Account erstellen
  7. Bot-User erstellen
  8. matrix-ollama-bot Service erstellen
  9. Bot testen
  10. Weitere Bots migrieren
  11. Telegram Bots deaktivieren

Ressourcen