service-llm-private/setupserver.md
2026-02-06 02:00:35 +01:00

20 KiB

Local LLM Server - Komplette Setup-Anleitung

Von GitHub Repo-Setup über Cursor bis zum automatischen Deployment auf Infomaniak.


Access

Server Data

IP 83.228.200.109 Instance: local-llm Ubuntu 24.04 LTS Noble Numbat 83.228.226.58, 2001:1600:16:10::7e3 nvl4-a8-ram16-disk0 ollama-deploy-key Active az-1 Connect: ssh -i "C:\Users\pmots\Downloads\ollama-deploy-key.pem" ubuntu@83.228.200.109

Übersicht

┌─────────────────┐                    ┌─────────────────┐
│     Cursor      │◄──── sync ────────▶│     GitHub      │
│  (lokale Dev)   │                    │   private-llm   │
└─────────────────┘                    └────────┬────────┘
                                                │
                                                │ Push to main
                                                ▼
                                       ┌─────────────────┐
                                       │  GitHub Actions │
                                       └────────┬────────┘
                                                │
                                                │ SSH Deploy
                                                ▼
                                       ┌─────────────────┐
                                       │ Infomaniak GPU  │
                                       │     Server      │
                                       │  ┌───────────┐  │
                                       │  │  Ollama   │  │
                                       │  │  + Flask  │  │
                                       │  │  (LLM +   │  │
                                       │  │  Vision)  │  │
                                       │  └───────────┘  │
                                       └─────────────────┘

Teil A: GitHub Repository Setup

A.1 Repository klonen in Cursor

Öffne ein Terminal in Cursor oder lokal:

# In deinen Projektordner wechseln
cd ~/Projects  # oder wo du deine Projekte speicherst

# Repository klonen
git clone https://github.com/valueonag/private-llm.git

# In den Ordner wechseln
cd private-llm

A.2 Cursor mit Repo verbinden

Option 1: Ordner in Cursor öffnen

  1. Cursor öffnen
  2. File → Open Folder
  3. Wähle den private-llm Ordner

Option 2: Über Terminal

cd ~/Projects/private-llm
cursor .

A.3 Projektstruktur erstellen

Erstelle folgende Struktur:

private-llm/
├── app.py                      # Deine Flask App
├── requirements.txt            # Python Dependencies
├── templates/
│   └── index.html              # Frontend Template
├── static/                     # CSS, JS, Bilder (optional)
├── .github/
│   └── workflows/
│       └── deploy.yml          # CI/CD Pipeline
├── .gitignore
└── README.md

A.3.1 requirements.txt

Erstelle requirements.txt:

flask>=3.0.0
flask-cors>=4.0.0
requests>=2.31.0
pymupdf>=1.24.0
gunicorn>=21.0.0

A.3.2 .gitignore

Erstelle .gitignore:

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
venv/
env/
.venv/

# IDE
.idea/
.vscode/
*.swp
*.swo
.cursor/

# OS
.DS_Store
Thumbs.db

# Logs
*.log
logs/

# Environment
.env
.env.local

# Test
.pytest_cache/
.coverage
htmlcov/

A.3.3 README.md

Erstelle README.md:

# Private LLM - Belegscanner

KI-Dokumentenanalyse mit lokalen Ollama Vision-Modellen.

## Features

- Rechnungen, Belege, Bankauszüge analysieren
- Handschrift erkennen
- PDF-Support
- 100% lokal - keine Cloud-APIs

## Tech Stack

- **Backend:** Python Flask
- **AI:** Ollama Vision Models
- **Server:** Infomaniak Swiss Cloud (GPU)

## Deployment

Automatisches Deployment via GitHub Actions bei Push zu `main`.

Teil B: GitHub Actions Deploy Workflow

B.1 Workflow-Datei erstellen

Erstelle .github/workflows/deploy.yml:

name: Deploy to Infomaniak

on:
  push:
    branches:
      - main
  workflow_dispatch:  # Manueller Trigger möglich

env:
  APP_DIR: /opt/ollama-webapp
  SERVICE_NAME: ollama-webapp

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
      # 1. Code auschecken
      - name: Checkout code
        uses: actions/checkout@v4

      # 2. SSH Setup
      - name: Setup SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key
          chmod 600 ~/.ssh/deploy_key
          ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts          

      # 3. Dateien zum Server kopieren
      - name: Deploy files to server
        run: |
          rsync -avz --delete \
            -e "ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=no" \
            --exclude '.git' \
            --exclude '.github' \
            --exclude '__pycache__' \
            --exclude '*.pyc' \
            --exclude 'venv' \
            --exclude '.env' \
            --exclude 'logs' \
            ./ ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:${{ env.APP_DIR }}/app/          

      # 4. Dependencies installieren und Service neu starten
      - name: Install dependencies and restart service
        run: |
          ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=no \
            ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }} << 'ENDSSH'
            
            echo "📦 Installing dependencies..."
            cd /opt/ollama-webapp
            ./venv/bin/pip install -r app/requirements.txt --quiet --upgrade
            
            echo "🔄 Restarting service..."
            sudo systemctl restart ollama-webapp
            
            echo "⏳ Waiting for service to start..."
            sleep 5
            
            echo "📊 Service status:"
            sudo systemctl status ollama-webapp --no-pager -l
            
            echo "✅ Deployment complete!"
          ENDSSH          

      # 5. Health Check
      - name: Health Check
        run: |
          echo "🏥 Running health check..."
          sleep 3
          
          HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
            http://${{ secrets.SERVER_HOST }}:5000/api/health || echo "000")
          
          if [ "$HTTP_STATUS" = "200" ]; then
            echo "✅ Health check passed! (HTTP $HTTP_STATUS)"
          else
            echo "❌ Health check failed! (HTTP $HTTP_STATUS)"
            exit 1
          fi          

      # 6. Deployment Summary
      - name: Deployment Summary
        if: success()
        run: |
          echo "🎉 Deployment successful!"
          echo ""
          echo "📍 App URL: http://${{ secrets.SERVER_HOST }}:5000"
          echo "📍 Health:  http://${{ secrets.SERVER_HOST }}:5000/api/health"
          echo "📍 Ollama:  http://${{ secrets.SERVER_HOST }}:5000/api/ollama/status"          

B.2 GitHub Secrets einrichten

  1. Gehe zu: https://github.com/valueonag/private-llm/settings/secrets/actions
  2. Klicke New repository secret
  3. Erstelle diese 3 Secrets:
Secret Name Wert Beschreibung
SERVER_HOST 185.xxx.xxx.xxx Deine Server-IP
SERVER_USER ubuntu SSH Benutzer
SSH_PRIVATE_KEY -----BEGIN OPENSSH... Der Private Key (ganzer Inhalt)

Teil C: Infomaniak Server Setup

C.1 Horizon Dashboard Login

  1. Öffne: https://api.pub1.infomaniak.cloud/horizon
  2. Login-Daten:
Feld Wert
Domain PCU-MPXPVCR
User Name PCU-MPXPVCR
Password Dein OpenStack-Passwort

C.2 SSH Key Pair erstellen

  1. Gehe zu: Compute → Key Pairs
  2. Klicke: Create Key Pair
  3. Fülle aus:
Feld Wert
Key Pair Name ollama-deploy-key
Key Type SSH Key
  1. Klicke Create Key Pair
  2. ⚠️ WICHTIG: Die .pem Datei wird automatisch heruntergeladen
    • Speichere sie sicher ab (z.B. ~/Downloads/ollama-deploy-key.pem)
    • Du brauchst sie später für SSH-Zugang!

C.3 Security Group erstellen

  1. Gehe zu: Network → Security Groups
  2. Klicke: Create Security Group
  3. Fülle aus:
Feld Wert
Name ollama-webapp
Description Ports für Ollama und Flask App
  1. Klicke Create Security Group
  2. In der Liste: Klicke Manage Rules bei ollama-webapp
  3. Klicke Add Rule und erstelle diese Regeln:
Rule Direction Ether Type IP Protocol Port Range CIDR
1 Ingress IPv4 TCP 22 0.0.0.0/0
2 Ingress IPv4 TCP 80 0.0.0.0/0
3 Ingress IPv4 TCP 443 0.0.0.0/0
4 Ingress IPv4 TCP 5000 0.0.0.0/0
5 Ingress IPv4 TCP 11434 0.0.0.0/0

Für jede Regel:

  • Klicke Add Rule
  • Direction: Ingress
  • Wähle bei "Rule": Custom TCP Rule
  • Port: Jeweilige Portnummer eingeben
  • CIDR: 0.0.0.0/0
  • Klicke Add

C.4 GPU-Instanz erstellen

  1. Gehe zu: Compute → Instances
  2. Klicke: Launch Instance

Tab 1: Details

Feld Wert
Instance Name local-llm
Description Local LLM Server
Availability Zone nova (Standard lassen)
Count 1

→ Klicke Next

Tab 2: Source

Feld Wert
Select Boot Source Image
Create New Volume Yes
Volume Size (GB) 150
Delete Volume on Instance Delete No

Image auswählen:

  1. In der unteren Liste "Available" suche: Ubuntu 24.04 LTS Noble Numbat
  2. Klicke den ↑ Pfeil rechts davon
  3. Das Image erscheint oben unter "Allocated"

→ Klicke Next

Tab 3: Flavor

GPU-Flavor auswählen:

In der Liste "Available" suche nach GPU-Flavors (beginnen mit nvl4-, t4-, oder a2-):

Flavor GPU VRAM vCPUs RAM Empfehlung
nvl4-12-46-0 L4 24GB 12 46GB ✓ Beste Wahl
t4-8-32-0 T4 16GB 8 32GB Budget
a2-8-32-0 A2 16GB 8 32GB Alternative
  1. Finde den gewünschten Flavor (z.B. mit "L4" oder "nvl4" im Namen)
  2. Klicke den ↑ Pfeil rechts davon
  3. Der Flavor erscheint oben unter "Allocated"

→ Klicke Next

Tab 4: Networks

Feld Wert
Network ext-net1
  1. In der Liste "Available" finde: ext-net1
  2. Klicke den ↑ Pfeil
  3. ext-net1 erscheint unter "Allocated"

→ Klicke Next

Tab 5: Network Ports

Überspringe diesen Tab (leer lassen).

→ Klicke Next

Tab 6: Security Groups

  1. Falls default unter "Allocated" steht: Klicke den ↓ Pfeil um es zu entfernen
  2. In "Available" finde: ollama-webapp
  3. Klicke den ↑ Pfeil
  4. Unter "Allocated" sollte nur ollama-webapp stehen

→ Klicke Next

Tab 7: Key Pair

  1. In "Available" finde: ollama-deploy-key
  2. Klicke den ↑ Pfeil
  3. Unter "Allocated" steht: ollama-deploy-key

→ Klicke Next

Tab 8: Configuration (optional)

Überspringe diesen Tab (leer lassen).

→ Klicke Next

Tab 9: Server Groups (optional)

Überspringe diesen Tab (leer lassen).

→ Klicke Next

Tab 10: Scheduler Hints (optional)

Überspringe diesen Tab (leer lassen).

→ Klicke Next

Tab 11: Metadata (optional)

Überspringe diesen Tab (leer lassen).


Instanz starten

Klicke: Launch Instance

Warte bis der Status von Build zu Active wechselt (ca. 1-3 Minuten).


C.5 Floating IP zuweisen

Die Instanz braucht eine öffentliche IP-Adresse:

  1. Gehe zu: Network → Floating IPs
  2. Klicke: Allocate IP to Project
  3. Wähle:
Feld Wert
Pool ext-net1
Description IP für Ollama Server
  1. Klicke Allocate IP
  2. In der Liste: Klicke Associate bei der neuen IP
  3. Wähle:
Feld Wert
Port to be associated local-llm (deine Instanz)
  1. Klicke Associate

📝 Notiere dir die IP-Adresse (z.B. 185.132.xxx.xxx) - du brauchst sie für:

  • SSH-Zugang
  • GitHub Secrets
  • Browser-Zugriff auf die App

C.6 Zusammenfassung deiner Instanz

Nach erfolgreichem Setup hast du:

Komponente Wert
Instance Name local-llm
Description Local LLM Server
Image Ubuntu 24.04 LTS
Flavor GPU mit L4/T4/A2
Disk 150 GB
Network ext-net1
Security Group ollama-webapp
Key Pair ollama-deploy-key
Floating IP 185.xxx.xxx.xxx

C.2 Server Basis-Setup

SSH zum Server:

ssh -i ~/Downloads/ollama-deploy-key.pem ubuntu@185.xxx.xxx.xxx

System aktualisieren

sudo apt update && sudo apt upgrade -y

NVIDIA-Treiber installieren

sudo apt install -y nvidia-driver-550
sudo reboot

Nach Neustart wieder verbinden und prüfen:

nvidia-smi

Ollama installieren

# Installieren
curl -fsSL https://ollama.com/install.sh | sh

# Konfigurieren
sudo systemctl edit ollama

Füge ein:

[Service]
Environment="OLLAMA_HOST=0.0.0.0"
Environment="OLLAMA_ORIGINS=*"
Environment="OLLAMA_NUM_PARALLEL=4"
Environment="OLLAMA_MAX_LOADED_MODELS=2"
sudo systemctl restart ollama
sudo systemctl enable ollama

Modelle herunterladen

ollama pull granite3.2-vision
ollama pull qwen2.5vl:7b
ollama pull deepseek-ocr

C.3 Python-Umgebung vorbereiten

# Pakete installieren
sudo apt install -y python3-pip python3-venv git

# App-Verzeichnis erstellen
sudo mkdir -p /opt/ollama-webapp/{app,venv,logs}
sudo chown -R ubuntu:ubuntu /opt/ollama-webapp

# Virtual Environment erstellen
python3 -m venv /opt/ollama-webapp/venv

# Basis-Pakete installieren
/opt/ollama-webapp/venv/bin/pip install --upgrade pip
/opt/ollama-webapp/venv/bin/pip install flask flask-cors requests pymupdf gunicorn

C.4 Deploy SSH-Key erstellen (für GitHub Actions)

# Key erstellen
ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/github_deploy_key -N ""

# Zu authorized_keys hinzufügen
cat ~/.ssh/github_deploy_key.pub >> ~/.ssh/authorized_keys

# Private Key anzeigen - DIESEN IN GITHUB SECRETS KOPIEREN!
echo ""
echo "=========================================="
echo "DIESEN KEY ALS 'SSH_PRIVATE_KEY' IN GITHUB SPEICHERN:"
echo "=========================================="
cat ~/.ssh/github_deploy_key
echo ""
echo "=========================================="

Kopiere den kompletten Private Key (inkl. -----BEGIN... und -----END...) und speichere ihn als GitHub Secret SSH_PRIVATE_KEY.

C.5 Systemd Service erstellen

sudo nano /etc/systemd/system/ollama-webapp.service

Inhalt:

[Unit]
Description=Belegscanner Flask App
After=network.target ollama.service
Wants=ollama.service

[Service]
Type=simple
User=ubuntu
Group=ubuntu
WorkingDirectory=/opt/ollama-webapp/app
Environment="PATH=/opt/ollama-webapp/venv/bin:/usr/bin"
Environment="FLASK_ENV=production"
ExecStart=/opt/ollama-webapp/venv/bin/gunicorn \
    --bind 0.0.0.0:5000 \
    --workers 2 \
    --timeout 3600 \
    --access-logfile /opt/ollama-webapp/logs/access.log \
    --error-logfile /opt/ollama-webapp/logs/error.log \
    app:app
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Aktivieren:

sudo systemctl daemon-reload
sudo systemctl enable ollama-webapp

C.6 Sudo-Rechte für GitHub Actions

sudo visudo

Füge am Ende hinzu:

ubuntu ALL=(ALL) NOPASSWD: /bin/systemctl restart ollama-webapp
ubuntu ALL=(ALL) NOPASSWD: /bin/systemctl status ollama-webapp
ubuntu ALL=(ALL) NOPASSWD: /bin/systemctl stop ollama-webapp
ubuntu ALL=(ALL) NOPASSWD: /bin/systemctl start ollama-webapp

C.7 Templates-Ordner erstellen

Falls deine Flask-App Templates verwendet:

mkdir -p /opt/ollama-webapp/app/templates
mkdir -p /opt/ollama-webapp/app/static

Teil D: Erster Commit und Deploy

D.1 In Cursor: Code committen

Öffne Terminal in Cursor (im private-llm Ordner):

# Status prüfen
git status

# Alle Dateien hinzufügen
git add .

# Commit erstellen
git commit -m "Initial setup: Flask app with CI/CD"

# Zu GitHub pushen
git push origin main

D.2 GitHub Actions beobachten

  1. Gehe zu: https://github.com/valueonag/private-llm/actions
  2. Du solltest einen laufenden Workflow sehen
  3. Klicke drauf um den Fortschritt zu sehen

D.3 App testen

Nach erfolgreichem Deploy:

# Health Check
curl http://185.xxx.xxx.xxx:5000/api/health

# Ollama Status
curl http://185.xxx.xxx.xxx:5000/api/ollama/status

# Im Browser öffnen
open http://185.xxx.xxx.xxx:5000

Teil E: Entwicklungs-Workflow

E.1 Lokale Entwicklung in Cursor

# Virtual Environment erstellen (einmalig)
cd ~/Projects/private-llm
python3 -m venv venv
source venv/bin/activate  # Mac/Linux
# oder: .\venv\Scripts\activate  # Windows

# Dependencies installieren
pip install -r requirements.txt

# Lokal starten (mit lokalem Ollama)
python app.py

E.2 Änderungen deployen

# Änderungen speichern
git add .

# Commit mit Beschreibung
git commit -m "Feature: Neue Funktion XYZ"

# Push zu GitHub → Automatischer Deploy!
git push origin main

E.3 Cursor Git-Integration

In Cursor kannst du auch die GUI nutzen:

  1. Source Control Tab (linke Sidebar)
  2. Änderungen sehen
  3. + um Dateien zu stagen
  4. Commit Message eingeben
  5. zum Committen
  6. ...Push zum Pushen

Teil F: Nützliche Befehle

Server-Befehle

# SSH zum Server
ssh -i ~/Downloads/ollama-deploy-key.pem ubuntu@185.xxx.xxx.xxx

# Service Status
sudo systemctl status ollama-webapp
sudo systemctl status ollama

# Logs anschauen
tail -f /opt/ollama-webapp/logs/access.log
tail -f /opt/ollama-webapp/logs/error.log
sudo journalctl -u ollama-webapp -f

# Service neu starten
sudo systemctl restart ollama-webapp

# GPU Status
nvidia-smi

# Ollama Modelle
ollama list
ollama pull <modell>

Git-Befehle

# Status
git status

# Änderungen sehen
git diff

# Commit und Push
git add .
git commit -m "Beschreibung"
git push origin main

# Vom Server holen (falls jemand anders gepusht hat)
git pull origin main

Teil G: Troubleshooting

Deploy schlägt fehl

  1. GitHub Actions Tab prüfen - Fehlermeldung lesen
  2. SSH testen:
    ssh -i ~/.ssh/github_deploy_key ubuntu@185.xxx.xxx.xxx
    
  3. Secrets prüfen - Sind alle 3 Secrets korrekt?

App startet nicht

# Auf dem Server:
sudo systemctl status ollama-webapp -l
cat /opt/ollama-webapp/logs/error.log

Ollama nicht erreichbar

# Status prüfen
sudo systemctl status ollama

# Neu starten
sudo systemctl restart ollama

# Logs
sudo journalctl -u ollama -f

Checkliste

GitHub Setup

  • Repository geklont
  • Cursor mit Repo verbunden
  • requirements.txt erstellt
  • .gitignore erstellt
  • .github/workflows/deploy.yml erstellt
  • GitHub Secrets konfiguriert:
    • SERVER_HOST
    • SERVER_USER
    • SSH_PRIVATE_KEY

Server Setup

  • GPU-Instanz erstellt
  • Floating IP zugewiesen
  • NVIDIA-Treiber installiert
  • Ollama installiert und konfiguriert
  • Modelle heruntergeladen
  • Python venv erstellt
  • Deploy SSH-Key erstellt
  • Systemd Service erstellt
  • Sudo-Rechte konfiguriert

Erster Deploy

  • Code committed und gepusht
  • GitHub Actions erfolgreich
  • Health Check funktioniert
  • App im Browser erreichbar

URLs

Service URL
App http://DEINE-IP:5000
Health Check http://DEINE-IP:5000/api/health
Ollama Status http://DEINE-IP:5000/api/ollama/status
GitHub Repo https://github.com/valueonag/private-llm
GitHub Actions https://github.com/valueonag/private-llm/actions