Initial commit - Jetson Home Hub Setup (Face/Finger Auth, RustDesk, Authentik, Whisper)
This commit is contained in:
commit
cf46181e48
215
AI-SETUP-INSTRUCTIONS.md
Normal file
215
AI-SETUP-INSTRUCTIONS.md
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
# HOFMANNS.AI - SETUP INSTRUCTIONS FOR AI AGENTS
|
||||
|
||||
**Ziel:** Jetson Orin Nano als zentraler Hub mit SSO (Passkeys) + RustDesk
|
||||
|
||||
---
|
||||
|
||||
## WICHTIG: Architektur
|
||||
|
||||
```
|
||||
JETSON (192.168.1.50) = MASTER
|
||||
├── Authentik (SSO mit Face ID / Fingerprint)
|
||||
├── RustDesk Server (hbbs/hbbr)
|
||||
├── Alle Services (HA, Whisper, Jellyfin, etc.)
|
||||
├── Private Daten (Kunden, Source, Docs)
|
||||
└── Cloudflare Tunnel → *.hofmanns.ai
|
||||
|
||||
INFOMANIAK (185.143.102.153) = DEV/PILOT
|
||||
├── Git Repos
|
||||
├── Dev Environments
|
||||
├── AI Agents arbeiten hier
|
||||
└── Kann jederzeit resettet werden
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## FILES IN THIS PACKAGE
|
||||
|
||||
```
|
||||
jetson-setup/
|
||||
│
|
||||
├── FOR JETSON (192.168.1.50):
|
||||
│ ├── setup.sh → Run first after JetPack flash
|
||||
│ ├── docker-compose.yml → All services including Authentik
|
||||
│ ├── homepage/ → Dashboard config
|
||||
│ └── whisper-webui-jetson/ → GPU-accelerated Whisper
|
||||
│
|
||||
├── FOR INFOMANIAK (185.143.102.153):
|
||||
│ └── infomaniak/
|
||||
│ ├── setup-infomaniak.sh → Optional dev setup
|
||||
│ └── docker-compose.yml → Dev services only
|
||||
│
|
||||
└── DOCUMENTATION:
|
||||
├── CHAT-SUMMARY-COMPLETE.md → Full context
|
||||
├── README.md → User guide
|
||||
└── AI-SETUP-INSTRUCTIONS.md → This file
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## JETSON SETUP STEPS
|
||||
|
||||
### 1. Flash JetPack (on Ubuntu PC with SDK Manager)
|
||||
|
||||
```bash
|
||||
# Jetson in Recovery Mode
|
||||
# SDK Manager → Jetson Orin Nano 8GB → JetPack 6.x → NVMe
|
||||
```
|
||||
|
||||
### 2. First Boot Config
|
||||
|
||||
```bash
|
||||
# After first boot, copy files to Jetson
|
||||
scp -r jetson-setup/ d@192.168.1.50:~/
|
||||
|
||||
# SSH to Jetson
|
||||
ssh d@192.168.1.50
|
||||
|
||||
# Run setup
|
||||
cd ~/jetson-setup
|
||||
chmod +x setup.sh
|
||||
sudo ./setup.sh
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
### 3. Start Services
|
||||
|
||||
```bash
|
||||
cd ~/docker
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### 4. Configure Authentik
|
||||
|
||||
1. Open: `http://192.168.1.50:9000/if/flow/initial-setup/`
|
||||
2. Create admin account
|
||||
3. Enable WebAuthn/Passkeys:
|
||||
- Admin → Flows → default-authentication-flow
|
||||
- Add Stage: "authenticator_validate" with WebAuthn
|
||||
4. Create Application for each service
|
||||
5. Set up Forward Auth proxy
|
||||
|
||||
### 5. Configure Cloudflare Tunnel
|
||||
|
||||
```bash
|
||||
# Install cloudflared
|
||||
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64 -o cloudflared
|
||||
chmod +x cloudflared
|
||||
sudo mv cloudflared /usr/local/bin/
|
||||
|
||||
# Login and create tunnel
|
||||
cloudflared tunnel login
|
||||
cloudflared tunnel create jetson-home
|
||||
|
||||
# Configure tunnel
|
||||
cat > ~/.cloudflared/config.yml << EOF
|
||||
tunnel: <TUNNEL_ID>
|
||||
credentials-file: /home/d/.cloudflared/<TUNNEL_ID>.json
|
||||
|
||||
ingress:
|
||||
- hostname: auth.hofmanns.ai
|
||||
service: http://localhost:9000
|
||||
- hostname: portal.hofmanns.ai
|
||||
service: http://localhost:3001
|
||||
- hostname: home.hofmanns.ai
|
||||
service: http://localhost:8123
|
||||
- hostname: whisper.hofmanns.ai
|
||||
service: http://localhost:7860
|
||||
- hostname: files.hofmanns.ai
|
||||
service: http://localhost:8081
|
||||
- hostname: "*.hofmanns.ai"
|
||||
service: http://localhost:80
|
||||
- service: http_status:404
|
||||
EOF
|
||||
|
||||
# Run as service
|
||||
sudo cloudflared service install
|
||||
sudo systemctl enable cloudflared
|
||||
sudo systemctl start cloudflared
|
||||
```
|
||||
|
||||
### 6. DNS Records (Cloudflare)
|
||||
|
||||
| Type | Name | Content |
|
||||
|------|------|---------|
|
||||
| CNAME | auth | <TUNNEL_ID>.cfargotunnel.com |
|
||||
| CNAME | portal | <TUNNEL_ID>.cfargotunnel.com |
|
||||
| CNAME | home | <TUNNEL_ID>.cfargotunnel.com |
|
||||
| CNAME | whisper | <TUNNEL_ID>.cfargotunnel.com |
|
||||
| CNAME | files | <TUNNEL_ID>.cfargotunnel.com |
|
||||
|
||||
### 7. Register Passkeys
|
||||
|
||||
1. Open auth.hofmanns.ai on each device
|
||||
2. Login with initial password
|
||||
3. Settings → MFA → Add WebAuthn Device
|
||||
4. Use Face ID / Fingerprint to register
|
||||
5. Done - no more passwords needed
|
||||
|
||||
---
|
||||
|
||||
## RUSTDESK SETUP
|
||||
|
||||
### Server runs on Jetson:
|
||||
|
||||
```bash
|
||||
# After docker-compose up, get the key:
|
||||
cat ~/docker/rustdesk/id_ed25519.pub
|
||||
```
|
||||
|
||||
### Client Config (all devices):
|
||||
|
||||
| Setting | Value |
|
||||
|---------|-------|
|
||||
| ID Server | jetson.hofmanns.ai (or via tunnel) |
|
||||
| Relay Server | jetson.hofmanns.ai |
|
||||
| Key | (from id_ed25519.pub) |
|
||||
|
||||
---
|
||||
|
||||
## PORTS OVERVIEW
|
||||
|
||||
### Jetson (192.168.1.50):
|
||||
|
||||
| Port | Service |
|
||||
|------|---------|
|
||||
| 80 | Nginx Proxy Manager |
|
||||
| 443 | Nginx Proxy Manager (SSL) |
|
||||
| 81 | NPM Admin UI |
|
||||
| 3001 | Homepage Dashboard |
|
||||
| 8123 | Home Assistant |
|
||||
| 9000 | Authentik |
|
||||
| 9090 | Cockpit |
|
||||
| 7860 | Whisper |
|
||||
| 8096 | Jellyfin |
|
||||
| 8081 | FileBrowser |
|
||||
| 8384 | Syncthing |
|
||||
| 11434 | Ollama |
|
||||
| 21115-21119 | RustDesk |
|
||||
|
||||
---
|
||||
|
||||
## USER REQUIREMENTS
|
||||
|
||||
- **NO passwords** - only Face ID / Fingerprint
|
||||
- **NO email codes** - Passkeys only
|
||||
- **NO 2FA apps** - device IS the auth
|
||||
- **ONE login** - session stays active
|
||||
- **ALL devices** - Quest 3, Android, Laptop, TV
|
||||
- **Browser-based** - no apps needed (except RustDesk client)
|
||||
|
||||
---
|
||||
|
||||
## RESULT
|
||||
|
||||
After setup, user experience:
|
||||
|
||||
1. Open browser → portal.hofmanns.ai
|
||||
2. Touch finger OR show face
|
||||
3. **Done. Everything accessible. All day.**
|
||||
|
||||
---
|
||||
|
||||
**Package created:** December 2025
|
||||
**For:** Dee / hofmanns.ai / DOUANA®
|
||||
**By:** Claude (Anthropic)
|
||||
370
CHAT-SUMMARY-COMPLETE.md
Normal file
370
CHAT-SUMMARY-COMPLETE.md
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
# Hofmanns.AI - Complete Infrastructure Setup
|
||||
|
||||
**Chat Summary - Dezember 2025**
|
||||
**Erstellt für:** Dee / DOUANA® / ZFEB GmbH
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Das Problem
|
||||
|
||||
- 48 Jahre alt, Enterprise-Kunden (Banken, Konzerne)
|
||||
- Jeden Tag 1-2 Stunden verloren mit: Logins, Passwörter, Email-Codes, Verify-Me, 2FA-Apps
|
||||
- Jedes Device, jede App, jeder Service will eigenen Login
|
||||
- Kein Bock mehr auf Console-Gefrickel
|
||||
- Meta Quest 3 als primäres Arbeitsgerät → braucht Browser-UI
|
||||
|
||||
**Das Ziel:** Ein Finger/Gesicht → alles offen. Fertig.
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Die Architektur
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ AUTHENTIK SSO │
|
||||
│ auth.hofmanns.ai (Passkeys/WebAuthn) │
|
||||
│ Face ID / Fingerprint = einmal einloggen = fertig │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌─────────────────────┼─────────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
||||
│ INFOMANIAK │ │ JETSON │ │ DEVICES │
|
||||
│ SERVER │ │ ORIN NANO │ │ │
|
||||
│ (öffentlich) │◄──►│ (privat) │◄──►│ Quest 3 │
|
||||
│ │ │ │ │ Android │
|
||||
│ - Git Repos │ │ - Kundendaten │ │ Laptop │
|
||||
│ - Dev/Pilot │ │ - Source Code │ │ TV │
|
||||
│ - Auth Server │ │ - Dokumente │ │ │
|
||||
│ - RustDesk ID │ │ - Home Hub │ │ │
|
||||
└───────────────┘ └───────────────┘ └───────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📍 Server Overview
|
||||
|
||||
### Infomaniak Server (öffentlich)
|
||||
|
||||
| Info | Wert |
|
||||
|------|------|
|
||||
| IP | 185.143.102.153 |
|
||||
| OS | Debian 12 (bookworm) |
|
||||
| User | debian |
|
||||
| SSH | Port 22 mit RSA Key |
|
||||
| Projekt | /home/debian/hofmanns.ai |
|
||||
| Command | `hof` → navigiert zum Projekt |
|
||||
|
||||
**Domains (alle auf diesem Server):**
|
||||
- hofmanns.ai
|
||||
- hofmanns.tech
|
||||
- hofmanns.app
|
||||
- hofmanns.shop
|
||||
- hofmanns.ltd
|
||||
- hofmann-s.com
|
||||
|
||||
**Was läuft dort:**
|
||||
- Git Repository (git.hofmanns.ai)
|
||||
- Dev/Pilot Umgebungen
|
||||
- AI Agents arbeiten hier (Claude, Manus, Perplexity)
|
||||
- Docker installiert
|
||||
|
||||
**Was NOCH drauf kommt:**
|
||||
- Authentik (SSO mit Passkeys)
|
||||
- RustDesk ID Server (hbbs/hbbr)
|
||||
- Cloudflare Tunnel oder direkt
|
||||
|
||||
### Jetson Orin Nano (privat, zu Hause)
|
||||
|
||||
| Info | Wert |
|
||||
|------|------|
|
||||
| IP | 192.168.1.50 |
|
||||
| OS | JetPack 6.x (Ubuntu-based) |
|
||||
| User | d |
|
||||
| Storage | 1TB NVMe |
|
||||
| GPU | NVIDIA (für AI) |
|
||||
| Standort | Am TV, zentral in Wohnung |
|
||||
|
||||
**Was läuft dort:**
|
||||
- Kundendaten
|
||||
- Source Code (produktiv)
|
||||
- Wichtige Dokumente
|
||||
- Home Assistant
|
||||
- AdGuard DNS
|
||||
- Whisper (Sprache → Text)
|
||||
- Jellyfin (Media)
|
||||
- Private Cloud (FileBrowser)
|
||||
- Syncthing
|
||||
- Ollama (LLMs)
|
||||
|
||||
---
|
||||
|
||||
## 🔐 SSO mit Passkeys (WebAuthn)
|
||||
|
||||
**Keine Passwörter. Keine Email-Codes. Kein 2FA-App Stress.**
|
||||
|
||||
### So funktioniert es:
|
||||
|
||||
1. **Einmalig einrichten:** Passkey auf jedem Gerät registrieren
|
||||
2. **Danach:** Finger auf Sensor oder Gesicht zeigen → eingeloggt
|
||||
3. **Session:** Bleibt aktiv, kein ständiges neu einloggen
|
||||
|
||||
### Unterstützte Geräte:
|
||||
|
||||
| Gerät | Auth-Methode |
|
||||
|-------|--------------|
|
||||
| Android Handy | Fingerprint / Face |
|
||||
| Meta Quest 3 | Handy als Authenticator (zeigt in VR) |
|
||||
| Laptop | Fingerprint / Windows Hello |
|
||||
| iPad/iPhone | Face ID / Touch ID |
|
||||
|
||||
### Authentik Setup:
|
||||
|
||||
```
|
||||
auth.hofmanns.ai
|
||||
│
|
||||
├── Passkey Registration
|
||||
├── Session Management
|
||||
├── Application Proxy
|
||||
│
|
||||
└── Geschützte Apps:
|
||||
├── portal.hofmanns.ai (Dashboard)
|
||||
├── git.hofmanns.ai
|
||||
├── home.hofmanns.ai (Home Assistant)
|
||||
├── files.hofmanns.ai (FileBrowser)
|
||||
├── whisper.hofmanns.ai
|
||||
└── ... alle anderen Services
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🖥️ Das Dashboard
|
||||
|
||||
**Ein Tab. Alles drin. Vollbild. Kein OS-Scheiss.**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ portal.hofmanns.ai │
|
||||
│ (nach Passkey-Auth = sofort da) │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ Home │ │ Whisper │ │ Jellyfin │ │
|
||||
│ │ Assistant │ │ Speech→Text│ │ Media │ │
|
||||
│ │ │ │ (GPU) │ │ │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ Portainer │ │ Files │ │ Syncthing │ │
|
||||
│ │ Docker │ │ Cloud │ │ Sync │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ Git │ │ RustDesk │ │ Ollama │ │
|
||||
│ │ Repos │ │ Remote │ │ LLM │ │
|
||||
│ │ │ │ Desktop │ │ │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔌 RustDesk (Self-Hosted TeamViewer)
|
||||
|
||||
**Kein WireGuard Console-Gefrickel. GUI everywhere.**
|
||||
|
||||
### Server (auf Infomaniak):
|
||||
|
||||
```yaml
|
||||
rustdesk-hbbs: # ID/Rendezvous Server
|
||||
ports: 21115, 21116, 21118
|
||||
|
||||
rustdesk-hbbr: # Relay Server
|
||||
ports: 21117, 21119
|
||||
```
|
||||
|
||||
### Client Setup:
|
||||
|
||||
1. RustDesk App installieren (alle Plattformen)
|
||||
2. Settings → Network → ID/Relay Server
|
||||
3. ID Server: `185.143.102.153` (oder rustdesk.hofmanns.ai)
|
||||
4. Relay Server: `185.143.102.153`
|
||||
5. Key: (wird beim ersten Start generiert)
|
||||
|
||||
### Zugriff:
|
||||
|
||||
- Von Quest 3 Browser → RustDesk Web Client
|
||||
- Von Handy → RustDesk App
|
||||
- Von Laptop → RustDesk App
|
||||
- Auf alle Rechner: Jetson, Gaming PC, Server
|
||||
|
||||
---
|
||||
|
||||
## 📱 Jetson Orin Nano - Services
|
||||
|
||||
| Port | Domain | Service |
|
||||
|------|--------|---------|
|
||||
| 3001 | portal.hofmanns.ai | Homepage Dashboard |
|
||||
| 81 | - | Nginx Proxy Manager |
|
||||
| 9443 | docker.hofmanns.ai | Portainer |
|
||||
| 9090 | system.hofmanns.ai | Cockpit |
|
||||
| 8123 | home.hofmanns.ai | Home Assistant |
|
||||
| 3000 | dns.hofmanns.ai | AdGuard Home |
|
||||
| 7860 | whisper.hofmanns.ai | Whisper WebUI |
|
||||
| 8096 | media.hofmanns.ai | Jellyfin |
|
||||
| 8081 | files.hofmanns.ai | FileBrowser |
|
||||
| 8384 | sync.hofmanns.ai | Syncthing |
|
||||
| 11434 | llm.hofmanns.ai | Ollama |
|
||||
|
||||
---
|
||||
|
||||
## 🌐 Netzwerk Setup
|
||||
|
||||
### Zu Hause:
|
||||
|
||||
```
|
||||
5G Antenne (500 CHF)
|
||||
│
|
||||
▼
|
||||
Netgear Nighthawk M5
|
||||
(DHCP 192.168.1.x, DNS=192.168.1.50)
|
||||
│
|
||||
▼
|
||||
Netgear 8-Port Switch
|
||||
│
|
||||
├── Jetson Orin Nano (192.168.1.50)
|
||||
│ └── USB WiFi → AP "Home.8"
|
||||
│
|
||||
└── Gaming PC (RTX 4080)
|
||||
```
|
||||
|
||||
### Tunnel nach draussen:
|
||||
|
||||
```
|
||||
Jetson ──► Cloudflare Tunnel ──► *.hofmanns.ai
|
||||
│
|
||||
└── RustDesk ──► Infomaniak Server ──► Clients überall
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Hardware Übersicht
|
||||
|
||||
| Gerät | Zweck | Status |
|
||||
|-------|-------|--------|
|
||||
| Jetson Orin Nano 8GB | Home Hub, AI, Private Cloud | Setup pending |
|
||||
| Gaming PC (Ryzen 9, RTX 4080, 64GB) | Workstation, Gaming | Aktiv |
|
||||
| Netgear Nighthawk M5 | 5G Router, 800 Mbit | Aktiv |
|
||||
| TP-Link USB WiFi Antenne | AP für Jetson | Vorhanden |
|
||||
| Meta Quest 3 | VR, primäres Arbeitsgerät | Aktiv |
|
||||
| 5x Raspberry Pi 5 | Übrig, verkaufen oder Projekte | Unused |
|
||||
| Infomaniak Root Server | Public Services, Auth, Git | Aktiv |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Installation - Reihenfolge
|
||||
|
||||
### Phase 1: Jetson Setup (zu Hause)
|
||||
|
||||
1. JetPack auf NVMe flashen (SDK Manager)
|
||||
2. `setup.sh` ausführen
|
||||
3. Docker Services starten
|
||||
4. WiFi AP "Home.8" aktivieren
|
||||
5. AdGuard DNS konfigurieren
|
||||
|
||||
### Phase 2: Infomaniak Server
|
||||
|
||||
1. SSH verbinden: `ssh hofmanns.ai`
|
||||
2. Authentik installieren (Docker)
|
||||
3. RustDesk Server installieren
|
||||
4. Cloudflare Tunnel oder Nginx konfigurieren
|
||||
5. DNS Records für alle Subdomains
|
||||
|
||||
### Phase 3: SSO Integration
|
||||
|
||||
1. Authentik Passkeys einrichten
|
||||
2. Alle Services als Applications registrieren
|
||||
3. Proxy-Provider für jeden Service
|
||||
4. Passkey auf allen Geräten registrieren
|
||||
|
||||
### Phase 4: Dashboard
|
||||
|
||||
1. Homepage auf Jetson konfigurieren
|
||||
2. Alle Services einbinden
|
||||
3. Authentik Forward Auth
|
||||
4. Testen von allen Devices
|
||||
|
||||
---
|
||||
|
||||
## 📁 Dateien in diesem Setup
|
||||
|
||||
```
|
||||
jetson-setup/
|
||||
├── setup.sh # Haupt-Setup für Jetson
|
||||
├── docker-compose.yml # Alle lokalen Services
|
||||
├── CHAT-SUMMARY.md # Diese Datei
|
||||
├── adguard-dns-rewrites.txt # DNS Einträge
|
||||
├── homepage/
|
||||
│ ├── services.yaml
|
||||
│ ├── settings.yaml
|
||||
│ ├── widgets.yaml
|
||||
│ ├── docker.yaml
|
||||
│ └── bookmarks.yaml
|
||||
└── whisper-webui-jetson/
|
||||
├── Dockerfile
|
||||
└── app.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔑 Wichtige Credentials (ÄNDERN!)
|
||||
|
||||
| Was | Default | Ändern auf |
|
||||
|-----|---------|------------|
|
||||
| WiFi "Home.8" | 123 | Sicheres Passwort |
|
||||
| Nginx Proxy Manager | admin@example.com / changeme | Eigene |
|
||||
| FileBrowser | admin / admin | Eigene |
|
||||
| Portainer | (bei Setup) | Eigene |
|
||||
| Authentik | (bei Setup) | Eigene |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Das Endergebnis
|
||||
|
||||
**Morgens aufstehen:**
|
||||
|
||||
1. Quest 3 aufsetzen
|
||||
2. Browser öffnen → portal.hofmanns.ai
|
||||
3. Handy kurz ans Gesicht halten (Face ID)
|
||||
4. **Fertig. Alles offen. Den ganzen Tag.**
|
||||
|
||||
**Unterwegs:**
|
||||
|
||||
1. Laptop/Handy öffnen
|
||||
2. portal.hofmanns.ai
|
||||
3. Finger auf Sensor
|
||||
4. **Fertig. Voller Zugriff auf alles.**
|
||||
|
||||
**Keine Passwörter. Keine Codes. Keine Apps. Keine Scheisse.**
|
||||
|
||||
---
|
||||
|
||||
## 📞 Nächste Schritte
|
||||
|
||||
1. [ ] Jetson JetPack flashen
|
||||
2. [ ] `setup.sh` ausführen auf Jetson
|
||||
3. [ ] Authentik auf Infomaniak installieren
|
||||
4. [ ] RustDesk Server auf Infomaniak
|
||||
5. [ ] DNS Records für Subdomains
|
||||
6. [ ] Cloudflare Tunnel einrichten
|
||||
7. [ ] Passkeys registrieren
|
||||
8. [ ] Testen mit Quest 3
|
||||
|
||||
---
|
||||
|
||||
**Erstellt:** Dezember 2025
|
||||
**Chat mit:** Claude (Anthropic)
|
||||
**Für:** Dee / hofmanns.ai / DOUANA®
|
||||
131
CHAT-SUMMARY.md
Normal file
131
CHAT-SUMMARY.md
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
# Jetson Orin Nano - Home Hub Setup
|
||||
|
||||
## Ausgangsproblem
|
||||
|
||||
Raspberry Pi 5 als Access Point für "Home.8" WiFi hatte falsche Konfiguration:
|
||||
- **Problem:** NetworkManager Hotspot Mode erstellt eigenes Subnetz (10.42.0.x) mit NAT
|
||||
- **Gewollt:** Einfache Bridge die IPs vom Nighthawk Router (192.168.1.x) durchreicht
|
||||
|
||||
## Lösung: Jetson Orin Nano als zentraler Hub
|
||||
|
||||
Statt den RP5 weiter zu debuggen → komplettes Setup auf Jetson Orin Nano am TV.
|
||||
|
||||
### Hardware Setup
|
||||
|
||||
```
|
||||
5G Antenne (500 CHF) ──► Netgear Nighthawk M5 (800 Mbit)
|
||||
│
|
||||
Netgear 8-Port Switch
|
||||
│
|
||||
┌─────────┴─────────┐
|
||||
│ │
|
||||
Jetson Orin Nano Gaming PC
|
||||
(@ TV, NVMe 1TB) (RTX 4080)
|
||||
│
|
||||
┌──────────┼──────────┐
|
||||
│ │ │
|
||||
USB WiFi HDMI 4K Docker Services
|
||||
(TP-Link) TV (alles lokal)
|
||||
```
|
||||
|
||||
### Services (alle mit Web UI!)
|
||||
|
||||
| Port | Service | Beschreibung |
|
||||
|------|---------|--------------|
|
||||
| 3001 | Homepage | Zentrales Dashboard |
|
||||
| 81 | Nginx Proxy Manager | Reverse Proxy mit GUI |
|
||||
| 9443 | Portainer | Docker Management |
|
||||
| 9090 | Cockpit | System Management |
|
||||
| 8123 | Home Assistant | Smart Home |
|
||||
| 3000 | AdGuard Home | DNS + Werbeblocker |
|
||||
| 7860 | Whisper WebUI | Sprache → Text (GPU) |
|
||||
| 8096 | Jellyfin | Media Server |
|
||||
| 8081 | FileBrowser | Private Cloud |
|
||||
| 8384 | Syncthing | File Sync |
|
||||
| 11434 | Ollama | Lokale LLMs |
|
||||
| 21115-21119 | RustDesk | Remote Desktop Server |
|
||||
|
||||
### Warum diese Entscheidungen
|
||||
|
||||
1. **RustDesk statt WireGuard** - Remote Desktop mit GUI, kein Console-Gefrickel
|
||||
2. **Nginx Proxy Manager statt Caddy** - Proxy-Konfiguration per Web UI
|
||||
3. **Homepage Dashboard** - Zentrales UI für alles, perfekt für Meta Quest 3 Browser
|
||||
4. **Cockpit** - System-Management im Browser statt SSH
|
||||
|
||||
### Dateien im Setup
|
||||
|
||||
```
|
||||
jetson-setup/
|
||||
├── setup.sh # Hauptscript
|
||||
├── docker-compose.yml # Alle Services
|
||||
├── adguard-dns-rewrites.txt # DNS Einträge
|
||||
├── homepage/
|
||||
│ ├── services.yaml # Dashboard Services
|
||||
│ ├── settings.yaml # Dashboard Settings
|
||||
│ ├── widgets.yaml # System Widgets
|
||||
│ ├── docker.yaml # Docker Integration
|
||||
│ └── bookmarks.yaml # Links
|
||||
└── whisper-webui-jetson/
|
||||
├── Dockerfile
|
||||
└── app.py # Gradio Web UI
|
||||
```
|
||||
|
||||
### Installation
|
||||
|
||||
1. **JetPack auf NVMe flashen** (SDK Manager am Ubuntu PC)
|
||||
2. **Setup-Dateien kopieren:**
|
||||
```bash
|
||||
scp -r jetson-setup/ d@192.168.1.50:~/
|
||||
```
|
||||
3. **Setup ausführen:**
|
||||
```bash
|
||||
cd ~/jetson-setup
|
||||
chmod +x setup.sh
|
||||
sudo ./setup.sh
|
||||
sudo reboot
|
||||
```
|
||||
4. **Services starten:**
|
||||
```bash
|
||||
cd ~/docker
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Nach dem Setup
|
||||
|
||||
1. **Homepage öffnen:** `http://192.168.1.50:3001`
|
||||
2. **Nginx Proxy Manager:** `http://192.168.1.50:81` (admin@example.com / changeme)
|
||||
3. **AdGuard DNS Rewrites** für .lan Domains einrichten
|
||||
4. **RustDesk Key holen:** `cat ~/docker/rustdesk/id_ed25519.pub`
|
||||
|
||||
### RustDesk Client Setup
|
||||
|
||||
1. RustDesk App installieren (Windows/Mac/Linux/Android/iOS)
|
||||
2. Settings → Network → ID/Relay Server
|
||||
3. ID Server: `192.168.1.50`
|
||||
4. Relay Server: `192.168.1.50`
|
||||
5. Key: (aus `id_ed25519.pub`)
|
||||
|
||||
### Vorteile
|
||||
|
||||
- **100% lokal** - keine Cloud-Abhängigkeit
|
||||
- **Alles Web UI** - nix Console im Alltag
|
||||
- **GPU beschleunigt** - Whisper, Ollama, Jellyfin Transcoding
|
||||
- **Meta Quest 3 kompatibel** - Dashboard im VR Browser
|
||||
- **Remote Access** - RustDesk für Desktop, alle Services über Proxy
|
||||
|
||||
### Hardware die rumliegt
|
||||
|
||||
- 5x Raspberry Pi 5 → verkaufen oder andere Projekte
|
||||
- Jetson Orin Nano → jetzt der zentrale Hub
|
||||
- TP-Link USB WiFi Antenne → AP "Home.8" am Jetson
|
||||
- Netgear Nighthawk M5 → 5G Internet + DHCP
|
||||
- Gaming PC (Ryzen 9, RTX 4080, 64GB) → bleibt Workstation
|
||||
|
||||
### Noch zu tun
|
||||
|
||||
- [ ] WiFi Passwort ändern (aktuell: 123)
|
||||
- [ ] Nginx Proxy Manager Domains einrichten
|
||||
- [ ] AdGuard DNS Rewrites hinzufügen
|
||||
- [ ] RustDesk auf allen Geräten installieren
|
||||
- [ ] Home Assistant Geräte einbinden
|
||||
- [ ] Whisper/Piper für HA Voice Assistant
|
||||
269
README.md
Normal file
269
README.md
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
# Jetson Orin Nano 8GB - Complete Home Hub
|
||||
|
||||
## Übersicht
|
||||
|
||||
Alles lokal, keine Cloud, volle Kontrolle.
|
||||
|
||||
| Domain | Service | Beschreibung |
|
||||
|--------|---------|--------------|
|
||||
| `home.lan` | Home Assistant | Smart Home Zentrale |
|
||||
| `adguard.lan` | AdGuard Home | DNS + Werbeblocker |
|
||||
| `whisper.lan` | Whisper WebUI | Sprache → Text (GPU) |
|
||||
| `jellyfin.lan` | Jellyfin | Media Server |
|
||||
| `portainer.lan` | Portainer | Docker Management |
|
||||
| `vpn.lan` | WireGuard Easy | VPN für unterwegs |
|
||||
| `files.lan` | FileBrowser | Private Cloud |
|
||||
| `sync.lan` | Syncthing | Dateisync |
|
||||
| `ollama.lan` | Ollama | Lokale LLMs |
|
||||
|
||||
## Hardware Setup
|
||||
|
||||
```
|
||||
5G Antenne ──► Nighthawk M5 (DHCP, DNS=192.168.1.50)
|
||||
│
|
||||
Netgear Switch
|
||||
│
|
||||
└── Jetson Orin Nano @ TV
|
||||
├── eth0: 192.168.1.50
|
||||
├── USB: TP-Link WiFi → AP "Home.8"
|
||||
└── HDMI: 4K TV
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
### 1. JetPack flashen (am PC mit Ubuntu)
|
||||
|
||||
```bash
|
||||
# SDK Manager: https://developer.nvidia.com/sdk-manager
|
||||
# Jetson in Recovery Mode (Power aus, Recovery halten, Power an)
|
||||
sdkmanager
|
||||
# → Jetson Orin Nano 8GB
|
||||
# → JetPack 6.x
|
||||
# → NVMe als Ziel
|
||||
```
|
||||
|
||||
### 2. Nach erstem Boot
|
||||
|
||||
```bash
|
||||
# Dateien auf Jetson kopieren
|
||||
scp -r jetson-setup/ d@192.168.1.50:~/
|
||||
|
||||
# SSH zum Jetson
|
||||
ssh d@192.168.1.50
|
||||
|
||||
# Setup ausführen
|
||||
cd ~/jetson-setup
|
||||
chmod +x setup.sh
|
||||
sudo ./setup.sh
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
### 3. Nach Reboot
|
||||
|
||||
```bash
|
||||
cd ~/docker
|
||||
docker-compose up -d
|
||||
|
||||
# Logs
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
### 4. AdGuard DNS Rewrites einrichten
|
||||
|
||||
1. Öffne `http://192.168.1.50:3000`
|
||||
2. Setup durchführen
|
||||
3. Settings → DNS rewrites
|
||||
4. Alle Einträge aus `adguard-dns-rewrites.txt` hinzufügen
|
||||
|
||||
### 5. Nighthawk DNS ändern
|
||||
|
||||
Im Nighthawk Router: DNS auf `192.168.1.50` setzen
|
||||
|
||||
Jetzt funktionieren alle `.lan` Domains!
|
||||
|
||||
## Zugriff
|
||||
|
||||
### Im LAN
|
||||
|
||||
Einfach im Browser:
|
||||
- `http://home.lan`
|
||||
- `http://adguard.lan`
|
||||
- `http://whisper.lan`
|
||||
- `http://portainer.lan`
|
||||
- etc.
|
||||
|
||||
### Unterwegs (VPN)
|
||||
|
||||
1. Öffne `http://vpn.lan` (Passwort: 123 - ÄNDERN!)
|
||||
2. Neuen Client erstellen
|
||||
3. QR-Code mit WireGuard App scannen
|
||||
4. Verbinden - fertig, alle .lan Domains erreichbar
|
||||
|
||||
**Wichtig:** `WG_HOST` in docker-compose.yml auf deine externe IP/DynDNS setzen!
|
||||
|
||||
## Services im Detail
|
||||
|
||||
### Home Assistant (`home.lan`)
|
||||
|
||||
Voice Assistant einrichten:
|
||||
1. Settings → Devices & Services → Add Integration
|
||||
2. "Wyoming Protocol" hinzufügen
|
||||
3. Whisper: `localhost:10300`
|
||||
4. Piper TTS: `localhost:10200`
|
||||
|
||||
### Whisper WebUI (`whisper.lan`)
|
||||
|
||||
- Sprache aufnehmen im Browser
|
||||
- Dateien hochladen
|
||||
- Läuft 100% lokal auf GPU
|
||||
- Deutsch, Englisch, etc.
|
||||
|
||||
### FileBrowser (`files.lan`)
|
||||
|
||||
Private Cloud für alle Dateien:
|
||||
- Default Login: `admin` / `admin`
|
||||
- Zugriff auf `/home/d/`
|
||||
|
||||
### Syncthing (`sync.lan`)
|
||||
|
||||
Dateien zwischen Geräten synchronisieren:
|
||||
- Handy ↔ Jetson ↔ PC
|
||||
- Verschlüsselt, kein Server in der Mitte
|
||||
|
||||
### Portainer (`portainer.lan`)
|
||||
|
||||
Docker Management mit GUI:
|
||||
- Container starten/stoppen
|
||||
- Logs anschauen
|
||||
- Compose verwalten
|
||||
|
||||
## Dateistruktur
|
||||
|
||||
```
|
||||
~/docker/
|
||||
├── docker-compose.yml
|
||||
├── caddy/
|
||||
│ └── Caddyfile
|
||||
├── homeassistant/config/
|
||||
├── adguard/conf/
|
||||
├── whisper/models/
|
||||
├── jellyfin/config/
|
||||
├── portainer/
|
||||
├── wireguard/
|
||||
├── filebrowser/
|
||||
├── syncthing/
|
||||
└── ollama/
|
||||
```
|
||||
|
||||
## Passwörter ändern!
|
||||
|
||||
```bash
|
||||
# WiFi AP
|
||||
sudo nano /etc/hostapd/hostapd.conf
|
||||
# wpa_passphrase=NEUES_PASSWORT
|
||||
sudo systemctl restart hostapd
|
||||
|
||||
# WireGuard
|
||||
nano ~/docker/docker-compose.yml
|
||||
# PASSWORD=NEUES_PASSWORT
|
||||
docker-compose up -d wg-easy
|
||||
```
|
||||
|
||||
## Port Forwarding (für VPN von aussen)
|
||||
|
||||
Im Nighthawk Router:
|
||||
- UDP 51820 → 192.168.1.50:51820
|
||||
|
||||
## Whisper Modelle
|
||||
|
||||
| Modell | VRAM | Speed | Qualität |
|
||||
|--------|------|-------|----------|
|
||||
| tiny | ~1GB | ⚡⚡⚡⚡ | ★★☆☆☆ |
|
||||
| base | ~1GB | ⚡⚡⚡ | ★★★☆☆ |
|
||||
| small | ~2GB | ⚡⚡ | ★★★★☆ |
|
||||
| medium | ~5GB | ⚡ | ★★★★★ |
|
||||
|
||||
Ändern in `docker-compose.yml`:
|
||||
```yaml
|
||||
environment:
|
||||
- WHISPER_MODEL=small
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Domains funktionieren nicht
|
||||
|
||||
```bash
|
||||
# DNS Test
|
||||
nslookup home.lan 192.168.1.50
|
||||
|
||||
# AdGuard läuft?
|
||||
docker logs adguard
|
||||
```
|
||||
|
||||
### WiFi AP startet nicht
|
||||
|
||||
```bash
|
||||
sudo systemctl status hostapd
|
||||
sudo journalctl -u hostapd -f
|
||||
iw dev
|
||||
```
|
||||
|
||||
### GPU nicht erkannt
|
||||
|
||||
```bash
|
||||
# Test
|
||||
docker run --rm --runtime=nvidia nvidia/cuda:11.4-base nvidia-smi
|
||||
|
||||
# Jetson Stats
|
||||
sudo pip3 install jetson-stats
|
||||
jtop
|
||||
```
|
||||
|
||||
### Container startet nicht
|
||||
|
||||
```bash
|
||||
docker-compose logs <container-name>
|
||||
docker-compose up <container-name> # ohne -d für live output
|
||||
```
|
||||
|
||||
## Updates
|
||||
|
||||
```bash
|
||||
cd ~/docker
|
||||
docker-compose pull
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Backup
|
||||
|
||||
```bash
|
||||
# Alles
|
||||
tar -czvf jetson-backup.tar.gz ~/docker/
|
||||
|
||||
# Nur Configs
|
||||
tar -czvf ha-backup.tar.gz ~/docker/homeassistant/config
|
||||
tar -czvf adguard-backup.tar.gz ~/docker/adguard/conf
|
||||
```
|
||||
|
||||
## Nützliche Befehle
|
||||
|
||||
```bash
|
||||
# Alle Container Status
|
||||
docker ps -a
|
||||
|
||||
# Ressourcen
|
||||
docker stats
|
||||
|
||||
# Jetson GPU/CPU Monitor
|
||||
jtop
|
||||
|
||||
# Logs live
|
||||
docker-compose logs -f
|
||||
|
||||
# Neustart einzelner Service
|
||||
docker-compose restart homeassistant
|
||||
|
||||
# Shell in Container
|
||||
docker exec -it homeassistant bash
|
||||
```
|
||||
48
adguard-dns-rewrites.txt
Normal file
48
adguard-dns-rewrites.txt
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# =============================================================================
|
||||
# ADGUARD DNS REWRITES
|
||||
# Nach AdGuard Setup: Settings → DNS rewrites → Bulk Add
|
||||
# Kopiere alles unten und füge es ein
|
||||
# =============================================================================
|
||||
|
||||
# Home Assistant
|
||||
home.lan 192.168.1.50
|
||||
ha.lan 192.168.1.50
|
||||
|
||||
# AdGuard
|
||||
adguard.lan 192.168.1.50
|
||||
dns.lan 192.168.1.50
|
||||
|
||||
# Whisper
|
||||
whisper.lan 192.168.1.50
|
||||
stt.lan 192.168.1.50
|
||||
|
||||
# Jellyfin
|
||||
jellyfin.lan 192.168.1.50
|
||||
media.lan 192.168.1.50
|
||||
tv.lan 192.168.1.50
|
||||
|
||||
# Portainer
|
||||
portainer.lan 192.168.1.50
|
||||
docker.lan 192.168.1.50
|
||||
|
||||
# VPN
|
||||
vpn.lan 192.168.1.50
|
||||
wg.lan 192.168.1.50
|
||||
|
||||
# Ollama
|
||||
ollama.lan 192.168.1.50
|
||||
llm.lan 192.168.1.50
|
||||
|
||||
# Cockpit
|
||||
cockpit.lan 192.168.1.50
|
||||
system.lan 192.168.1.50
|
||||
|
||||
# FileBrowser
|
||||
files.lan 192.168.1.50
|
||||
cloud.lan 192.168.1.50
|
||||
|
||||
# Syncthing
|
||||
sync.lan 192.168.1.50
|
||||
|
||||
# Jetson direkt
|
||||
jetson.lan 192.168.1.50
|
||||
72
caddy/Caddyfile
Normal file
72
caddy/Caddyfile
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# =============================================================================
|
||||
# CADDY REVERSE PROXY
|
||||
# Lokale Domains - kein HTTPS nötig im LAN
|
||||
# =============================================================================
|
||||
|
||||
# Home Assistant
|
||||
home.lan, ha.lan {
|
||||
reverse_proxy localhost:8123
|
||||
}
|
||||
|
||||
# AdGuard Home
|
||||
adguard.lan, dns.lan {
|
||||
reverse_proxy localhost:80
|
||||
}
|
||||
|
||||
# Whisper Web UI
|
||||
whisper.lan, stt.lan {
|
||||
reverse_proxy localhost:7860
|
||||
}
|
||||
|
||||
# Jellyfin
|
||||
jellyfin.lan, media.lan, tv.lan {
|
||||
reverse_proxy localhost:8096
|
||||
}
|
||||
|
||||
# Portainer (Docker Management)
|
||||
portainer.lan, docker.lan {
|
||||
reverse_proxy localhost:9443 {
|
||||
transport http {
|
||||
tls_insecure_skip_verify
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Ollama API
|
||||
ollama.lan, llm.lan {
|
||||
reverse_proxy localhost:11434
|
||||
}
|
||||
|
||||
# Whisper API
|
||||
whisper-api.lan {
|
||||
reverse_proxy localhost:9000
|
||||
}
|
||||
|
||||
# WireGuard Easy (VPN Management)
|
||||
vpn.lan, wg.lan {
|
||||
reverse_proxy localhost:51821
|
||||
}
|
||||
|
||||
# Cockpit (System Management) - falls installiert
|
||||
cockpit.lan, system.lan {
|
||||
reverse_proxy localhost:9090 {
|
||||
transport http {
|
||||
tls_insecure_skip_verify
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# FileBrowser (Private Cloud)
|
||||
files.lan, cloud.lan {
|
||||
reverse_proxy localhost:8081
|
||||
}
|
||||
|
||||
# Syncthing
|
||||
sync.lan {
|
||||
reverse_proxy localhost:8384
|
||||
}
|
||||
|
||||
# Fallback - zeigt Status
|
||||
:80 {
|
||||
respond "Jetson Home Hub - Use: home.lan, adguard.lan, whisper.lan, jellyfin.lan, portainer.lan, vpn.lan, files.lan, sync.lan"
|
||||
}
|
||||
292
docker-compose.yml
Normal file
292
docker-compose.yml
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
version: '3.8'
|
||||
|
||||
# =============================================================================
|
||||
# JETSON ORIN NANO - COMPLETE HOME HUB
|
||||
# Alles mit Web UI - keine Console!
|
||||
# =============================================================================
|
||||
|
||||
services:
|
||||
# ===========================================
|
||||
# NGINX PROXY MANAGER (Reverse Proxy mit GUI!)
|
||||
# ===========================================
|
||||
npm:
|
||||
container_name: nginx-proxy-manager
|
||||
image: jc21/nginx-proxy-manager:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "81:81"
|
||||
volumes:
|
||||
- ./npm/data:/data
|
||||
- ./npm/letsencrypt:/etc/letsencrypt
|
||||
|
||||
# ===========================================
|
||||
# HOMEPAGE - Zentrales Dashboard
|
||||
# ===========================================
|
||||
homepage:
|
||||
container_name: homepage
|
||||
image: ghcr.io/gethomepage/homepage:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3001:3000"
|
||||
volumes:
|
||||
- ./homepage:/app/config
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
|
||||
# ===========================================
|
||||
# PORTAINER - Docker Management UI
|
||||
# ===========================================
|
||||
portainer:
|
||||
container_name: portainer
|
||||
image: portainer/portainer-ce:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "9443:9443"
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./portainer:/data
|
||||
|
||||
# ===========================================
|
||||
# RUSTDESK SERVER (Self-hosted Remote Desktop)
|
||||
# ===========================================
|
||||
rustdesk-hbbs:
|
||||
container_name: rustdesk-hbbs
|
||||
image: rustdesk/rustdesk-server:latest
|
||||
restart: unless-stopped
|
||||
command: hbbs
|
||||
ports:
|
||||
- "21115:21115"
|
||||
- "21116:21116"
|
||||
- "21116:21116/udp"
|
||||
- "21118:21118"
|
||||
volumes:
|
||||
- ./rustdesk:/root
|
||||
depends_on:
|
||||
- rustdesk-hbbr
|
||||
|
||||
rustdesk-hbbr:
|
||||
container_name: rustdesk-hbbr
|
||||
image: rustdesk/rustdesk-server:latest
|
||||
restart: unless-stopped
|
||||
command: hbbr
|
||||
ports:
|
||||
- "21117:21117"
|
||||
- "21119:21119"
|
||||
volumes:
|
||||
- ./rustdesk:/root
|
||||
|
||||
# ===========================================
|
||||
# HOME ASSISTANT
|
||||
# ===========================================
|
||||
homeassistant:
|
||||
container_name: homeassistant
|
||||
image: ghcr.io/home-assistant/home-assistant:stable
|
||||
restart: unless-stopped
|
||||
privileged: true
|
||||
network_mode: host
|
||||
depends_on:
|
||||
- adguard
|
||||
volumes:
|
||||
- ./homeassistant/config:/config
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /run/dbus:/run/dbus:ro
|
||||
environment:
|
||||
- TZ=Europe/Zurich
|
||||
|
||||
# ===========================================
|
||||
# ADGUARD HOME (DNS + Ad Blocking + Local DNS)
|
||||
# ===========================================
|
||||
adguard:
|
||||
container_name: adguard
|
||||
image: adguard/adguardhome:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "53:53/tcp"
|
||||
- "53:53/udp"
|
||||
- "3000:3000/tcp"
|
||||
- "8080:80/tcp"
|
||||
volumes:
|
||||
- ./adguard/work:/opt/adguardhome/work
|
||||
- ./adguard/conf:/opt/adguardhome/conf
|
||||
|
||||
# ===========================================
|
||||
# WHISPER GRADIO WEB UI
|
||||
# ===========================================
|
||||
whisper-webui:
|
||||
container_name: whisper-webui
|
||||
build:
|
||||
context: ./whisper-webui-jetson
|
||||
dockerfile: Dockerfile
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "7860:7860"
|
||||
volumes:
|
||||
- ./whisper/models:/root/.cache/whisper
|
||||
runtime: nvidia
|
||||
environment:
|
||||
- NVIDIA_VISIBLE_DEVICES=all
|
||||
- WHISPER_MODEL=base
|
||||
devices:
|
||||
- /dev/snd:/dev/snd
|
||||
|
||||
# ===========================================
|
||||
# WYOMING WHISPER (Home Assistant Voice)
|
||||
# ===========================================
|
||||
wyoming-whisper:
|
||||
container_name: wyoming-whisper
|
||||
image: rhasspy/wyoming-whisper:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "10300:10300"
|
||||
command: --model base --language de
|
||||
volumes:
|
||||
- ./whisper/wyoming:/data
|
||||
runtime: nvidia
|
||||
|
||||
# ===========================================
|
||||
# PIPER TTS (Text-to-Speech)
|
||||
# ===========================================
|
||||
piper:
|
||||
container_name: piper
|
||||
image: rhasspy/wyoming-piper:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "10200:10200"
|
||||
command: --voice de_DE-thorsten-high
|
||||
volumes:
|
||||
- ./piper:/data
|
||||
|
||||
# ===========================================
|
||||
# JELLYFIN (Media Server)
|
||||
# ===========================================
|
||||
jellyfin:
|
||||
container_name: jellyfin
|
||||
image: jellyfin/jellyfin:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8096:8096"
|
||||
volumes:
|
||||
- ./jellyfin/config:/config
|
||||
- ./jellyfin/cache:/cache
|
||||
- /media:/media:ro
|
||||
environment:
|
||||
- TZ=Europe/Zurich
|
||||
- NVIDIA_VISIBLE_DEVICES=all
|
||||
runtime: nvidia
|
||||
devices:
|
||||
- /dev/dri:/dev/dri
|
||||
|
||||
# ===========================================
|
||||
# OLLAMA (Local LLM)
|
||||
# ===========================================
|
||||
ollama:
|
||||
container_name: ollama
|
||||
image: ollama/ollama:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "11434:11434"
|
||||
volumes:
|
||||
- ./ollama:/root/.ollama
|
||||
runtime: nvidia
|
||||
environment:
|
||||
- NVIDIA_VISIBLE_DEVICES=all
|
||||
|
||||
# ===========================================
|
||||
# FILEBROWSER (Private Cloud)
|
||||
# ===========================================
|
||||
filebrowser:
|
||||
container_name: filebrowser
|
||||
image: filebrowser/filebrowser:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8081:80"
|
||||
volumes:
|
||||
- /home/d:/srv
|
||||
- ./filebrowser/database.db:/database.db
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
|
||||
# ===========================================
|
||||
# AUTHENTIK - SSO mit Passkeys
|
||||
# ===========================================
|
||||
authentik-postgres:
|
||||
container_name: authentik-postgres
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./authentik/database:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${PG_PASS:-supersecret}
|
||||
POSTGRES_USER: authentik
|
||||
POSTGRES_DB: authentik
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U authentik"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
authentik-redis:
|
||||
container_name: authentik-redis
|
||||
image: redis:alpine
|
||||
command: --save 60 1 --loglevel warning
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./authentik/redis:/data
|
||||
|
||||
authentik:
|
||||
container_name: authentik
|
||||
image: ghcr.io/goauthentik/server:2024.2
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
AUTHENTIK_REDIS__HOST: authentik-redis
|
||||
AUTHENTIK_POSTGRESQL__HOST: authentik-postgres
|
||||
AUTHENTIK_POSTGRESQL__USER: authentik
|
||||
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS:-supersecret}
|
||||
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:-changeme-run-openssl-rand-60-base64}
|
||||
ports:
|
||||
- "9000:9000"
|
||||
depends_on:
|
||||
- authentik-postgres
|
||||
- authentik-redis
|
||||
|
||||
authentik-worker:
|
||||
container_name: authentik-worker
|
||||
image: ghcr.io/goauthentik/server:2024.2
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
environment:
|
||||
AUTHENTIK_REDIS__HOST: authentik-redis
|
||||
AUTHENTIK_POSTGRESQL__HOST: authentik-postgres
|
||||
AUTHENTIK_POSTGRESQL__USER: authentik
|
||||
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS:-supersecret}
|
||||
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:-changeme-run-openssl-rand-60-base64}
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
depends_on:
|
||||
- authentik-postgres
|
||||
- authentik-redis
|
||||
|
||||
# ===========================================
|
||||
# SYNCTHING (File Sync)
|
||||
# ===========================================
|
||||
syncthing:
|
||||
container_name: syncthing
|
||||
image: syncthing/syncthing:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8384:8384"
|
||||
- "22000:22000/tcp"
|
||||
- "22000:22000/udp"
|
||||
- "21027:21027/udp"
|
||||
volumes:
|
||||
- ./syncthing:/var/syncthing
|
||||
- /home/d/sync:/data
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
21
first-boot.sh
Normal file
21
first-boot.sh
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# FIRST BOOT - Run this from USB stick after JetPack flash
|
||||
# =============================================================================
|
||||
|
||||
echo "Copying setup files to home directory..."
|
||||
cp -r /media/$USER/*/jetson-setup ~/jetson-setup 2>/dev/null || \
|
||||
cp -r /media/*/jetson-setup ~/jetson-setup 2>/dev/null || \
|
||||
echo "Please copy jetson-setup folder manually to ~/"
|
||||
|
||||
if [ -d ~/jetson-setup ]; then
|
||||
echo "Files copied. Now run:"
|
||||
echo ""
|
||||
echo " cd ~/jetson-setup"
|
||||
echo " chmod +x setup.sh"
|
||||
echo " sudo ./setup.sh"
|
||||
echo ""
|
||||
else
|
||||
echo "ERROR: Could not find jetson-setup on USB"
|
||||
echo "Copy manually and run setup.sh"
|
||||
fi
|
||||
19
homepage/bookmarks.yaml
Normal file
19
homepage/bookmarks.yaml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# =============================================================================
|
||||
# HOMEPAGE DASHBOARD - Bookmarks
|
||||
# =============================================================================
|
||||
|
||||
- Management:
|
||||
- Nighthawk Router:
|
||||
- icon: router
|
||||
href: http://192.168.1.1
|
||||
- Proxy Manager:
|
||||
- icon: nginx-proxy-manager.svg
|
||||
href: http://192.168.1.50:81
|
||||
|
||||
- Dokumentation:
|
||||
- Home Assistant:
|
||||
- icon: home-assistant.svg
|
||||
href: https://www.home-assistant.io/docs/
|
||||
- RustDesk:
|
||||
- icon: rustdesk.svg
|
||||
href: https://rustdesk.com/docs/
|
||||
6
homepage/docker.yaml
Normal file
6
homepage/docker.yaml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# =============================================================================
|
||||
# HOMEPAGE DASHBOARD - Docker Configuration
|
||||
# =============================================================================
|
||||
|
||||
my-docker:
|
||||
socket: /var/run/docker.sock
|
||||
105
homepage/services.yaml
Normal file
105
homepage/services.yaml
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
# =============================================================================
|
||||
# HOMEPAGE DASHBOARD - Services Configuration
|
||||
# =============================================================================
|
||||
|
||||
- Smart Home:
|
||||
- Home Assistant:
|
||||
icon: home-assistant.svg
|
||||
href: http://home.lan
|
||||
description: Smart Home Zentrale
|
||||
server: my-docker
|
||||
container: homeassistant
|
||||
widget:
|
||||
type: homeassistant
|
||||
url: http://192.168.1.50:8123
|
||||
key: YOUR_HA_TOKEN
|
||||
|
||||
- Netzwerk:
|
||||
- AdGuard Home:
|
||||
icon: adguard-home.svg
|
||||
href: http://adguard.lan
|
||||
description: DNS & Werbeblocker
|
||||
server: my-docker
|
||||
container: adguard
|
||||
widget:
|
||||
type: adguard
|
||||
url: http://192.168.1.50:8080
|
||||
username: admin
|
||||
password: YOUR_PASSWORD
|
||||
|
||||
- Nginx Proxy Manager:
|
||||
icon: nginx-proxy-manager.svg
|
||||
href: http://192.168.1.50:81
|
||||
description: Reverse Proxy GUI
|
||||
server: my-docker
|
||||
container: nginx-proxy-manager
|
||||
|
||||
- Remote Access:
|
||||
- RustDesk:
|
||||
icon: rustdesk.svg
|
||||
href: http://rustdesk.lan
|
||||
description: Remote Desktop Server
|
||||
server: my-docker
|
||||
container: rustdesk-hbbs
|
||||
|
||||
- Portainer:
|
||||
icon: portainer.svg
|
||||
href: http://portainer.lan
|
||||
description: Docker Management
|
||||
server: my-docker
|
||||
container: portainer
|
||||
widget:
|
||||
type: portainer
|
||||
url: https://192.168.1.50:9443
|
||||
env: 1
|
||||
key: YOUR_PORTAINER_KEY
|
||||
|
||||
- AI & Voice:
|
||||
- Whisper:
|
||||
icon: openai.svg
|
||||
href: http://whisper.lan
|
||||
description: Sprache zu Text (GPU)
|
||||
server: my-docker
|
||||
container: whisper-webui
|
||||
|
||||
- Ollama:
|
||||
icon: ollama.svg
|
||||
href: http://ollama.lan
|
||||
description: Lokale LLMs
|
||||
server: my-docker
|
||||
container: ollama
|
||||
|
||||
- Piper TTS:
|
||||
icon: mdi-text-to-speech
|
||||
href: "#"
|
||||
description: Text zu Sprache
|
||||
server: my-docker
|
||||
container: piper
|
||||
|
||||
- Media:
|
||||
- Jellyfin:
|
||||
icon: jellyfin.svg
|
||||
href: http://jellyfin.lan
|
||||
description: Media Server
|
||||
server: my-docker
|
||||
container: jellyfin
|
||||
widget:
|
||||
type: jellyfin
|
||||
url: http://192.168.1.50:8096
|
||||
key: YOUR_JELLYFIN_KEY
|
||||
enableBlocks: true
|
||||
|
||||
- Cloud & Sync:
|
||||
- FileBrowser:
|
||||
icon: filebrowser.svg
|
||||
href: http://files.lan
|
||||
description: Private Cloud
|
||||
server: my-docker
|
||||
container: filebrowser
|
||||
|
||||
- Syncthing:
|
||||
icon: syncthing.svg
|
||||
href: http://sync.lan
|
||||
description: File Sync
|
||||
server: my-docker
|
||||
container: syncthing
|
||||
40
homepage/settings.yaml
Normal file
40
homepage/settings.yaml
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# =============================================================================
|
||||
# HOMEPAGE DASHBOARD - Settings
|
||||
# =============================================================================
|
||||
|
||||
title: Jetson Home Hub
|
||||
description: Dein lokales Smart Home & AI Center
|
||||
|
||||
theme: dark
|
||||
color: slate
|
||||
|
||||
background:
|
||||
image: https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=1920
|
||||
blur: sm
|
||||
opacity: 30
|
||||
|
||||
cardBlur: md
|
||||
|
||||
favicon: https://raw.githubusercontent.com/home-assistant/assets/master/favicon/favicon.ico
|
||||
|
||||
layout:
|
||||
Smart Home:
|
||||
style: row
|
||||
columns: 1
|
||||
Netzwerk:
|
||||
style: row
|
||||
columns: 2
|
||||
Remote Access:
|
||||
style: row
|
||||
columns: 2
|
||||
AI & Voice:
|
||||
style: row
|
||||
columns: 3
|
||||
Media:
|
||||
style: row
|
||||
columns: 1
|
||||
Cloud & Sync:
|
||||
style: row
|
||||
columns: 2
|
||||
|
||||
headerStyle: clean
|
||||
29
homepage/widgets.yaml
Normal file
29
homepage/widgets.yaml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# =============================================================================
|
||||
# HOMEPAGE DASHBOARD - Widgets (System Info)
|
||||
# =============================================================================
|
||||
|
||||
- logo:
|
||||
icon: https://developer.nvidia.com/sites/default/files/akamai/embedded/images/jetson-orin-nano/jetson-orin-nano-front.png
|
||||
|
||||
- greeting:
|
||||
text_size: xl
|
||||
text: Jetson Home Hub
|
||||
|
||||
- datetime:
|
||||
text_size: l
|
||||
format:
|
||||
dateStyle: long
|
||||
timeStyle: short
|
||||
hour12: false
|
||||
|
||||
- resources:
|
||||
cpu: true
|
||||
memory: true
|
||||
disk: /
|
||||
cputemp: true
|
||||
uptime: true
|
||||
label: System
|
||||
|
||||
- search:
|
||||
provider: google
|
||||
target: _blank
|
||||
18
infomaniak/.env.example
Normal file
18
infomaniak/.env.example
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# =============================================================================
|
||||
# AUTHENTIK ENVIRONMENT
|
||||
# Für Infomaniak Server (185.143.102.153)
|
||||
# =============================================================================
|
||||
|
||||
# PostgreSQL
|
||||
PG_PASS=CHANGE_ME_SECURE_PASSWORD_HERE
|
||||
|
||||
# Authentik Secret Key (generieren mit: openssl rand 60 | base64 -w 0)
|
||||
AUTHENTIK_SECRET_KEY=CHANGE_ME_RUN_openssl_rand_60_base64
|
||||
|
||||
# Optional: Email
|
||||
# AUTHENTIK_EMAIL__HOST=smtp.example.com
|
||||
# AUTHENTIK_EMAIL__PORT=587
|
||||
# AUTHENTIK_EMAIL__USERNAME=
|
||||
# AUTHENTIK_EMAIL__PASSWORD=
|
||||
# AUTHENTIK_EMAIL__USE_TLS=true
|
||||
# AUTHENTIK_EMAIL__FROM=authentik@hofmanns.ai
|
||||
128
infomaniak/docker-compose.yml
Normal file
128
infomaniak/docker-compose.yml
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
version: "3.8"
|
||||
|
||||
# =============================================================================
|
||||
# INFOMANIAK SERVER - AUTH + RUSTDESK
|
||||
# Für: 185.143.102.153 / hofmanns.ai
|
||||
# =============================================================================
|
||||
|
||||
services:
|
||||
# ===========================================
|
||||
# AUTHENTIK - SSO mit Passkeys/WebAuthn
|
||||
# ===========================================
|
||||
postgresql:
|
||||
container_name: authentik-postgres
|
||||
image: docker.io/library/postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
|
||||
start_period: 20s
|
||||
interval: 30s
|
||||
retries: 5
|
||||
timeout: 5s
|
||||
volumes:
|
||||
- ./authentik/database:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${PG_PASS:?database password required}
|
||||
POSTGRES_USER: authentik
|
||||
POSTGRES_DB: authentik
|
||||
|
||||
redis:
|
||||
container_name: authentik-redis
|
||||
image: docker.io/library/redis:alpine
|
||||
command: --save 60 1 --loglevel warning
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||
start_period: 20s
|
||||
interval: 30s
|
||||
retries: 5
|
||||
timeout: 3s
|
||||
volumes:
|
||||
- ./authentik/redis:/data
|
||||
|
||||
authentik-server:
|
||||
container_name: authentik-server
|
||||
image: ghcr.io/goauthentik/server:2024.2
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
AUTHENTIK_REDIS__HOST: redis
|
||||
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||
AUTHENTIK_POSTGRESQL__USER: authentik
|
||||
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
|
||||
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
|
||||
volumes:
|
||||
- ./authentik/media:/media
|
||||
- ./authentik/custom-templates:/templates
|
||||
ports:
|
||||
- "9000:9000"
|
||||
- "9443:9443"
|
||||
depends_on:
|
||||
- postgresql
|
||||
- redis
|
||||
|
||||
authentik-worker:
|
||||
container_name: authentik-worker
|
||||
image: ghcr.io/goauthentik/server:2024.2
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
environment:
|
||||
AUTHENTIK_REDIS__HOST: redis
|
||||
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||
AUTHENTIK_POSTGRESQL__USER: authentik
|
||||
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
|
||||
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./authentik/media:/media
|
||||
- ./authentik/certs:/certs
|
||||
- ./authentik/custom-templates:/templates
|
||||
depends_on:
|
||||
- postgresql
|
||||
- redis
|
||||
|
||||
# ===========================================
|
||||
# RUSTDESK SERVER - Remote Desktop
|
||||
# ===========================================
|
||||
rustdesk-hbbs:
|
||||
container_name: rustdesk-hbbs
|
||||
image: rustdesk/rustdesk-server:latest
|
||||
restart: unless-stopped
|
||||
command: hbbs
|
||||
ports:
|
||||
- "21115:21115"
|
||||
- "21116:21116"
|
||||
- "21116:21116/udp"
|
||||
- "21118:21118"
|
||||
volumes:
|
||||
- ./rustdesk:/root
|
||||
|
||||
rustdesk-hbbr:
|
||||
container_name: rustdesk-hbbr
|
||||
image: rustdesk/rustdesk-server:latest
|
||||
restart: unless-stopped
|
||||
command: hbbr
|
||||
ports:
|
||||
- "21117:21117"
|
||||
- "21119:21119"
|
||||
volumes:
|
||||
- ./rustdesk:/root
|
||||
|
||||
# ===========================================
|
||||
# NGINX - Reverse Proxy mit SSL
|
||||
# ===========================================
|
||||
nginx:
|
||||
container_name: nginx
|
||||
image: nginx:alpine
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx/conf.d:/etc/nginx/conf.d:ro
|
||||
- ./nginx/ssl:/etc/nginx/ssl:ro
|
||||
- ./nginx/html:/usr/share/nginx/html:ro
|
||||
depends_on:
|
||||
- authentik-server
|
||||
82
infomaniak/nginx/conf.d/hofmanns.conf
Normal file
82
infomaniak/nginx/conf.d/hofmanns.conf
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
# =============================================================================
|
||||
# NGINX CONFIG - hofmanns.ai
|
||||
# =============================================================================
|
||||
|
||||
# Authentik SSO
|
||||
server {
|
||||
listen 80;
|
||||
server_name auth.hofmanns.ai;
|
||||
|
||||
location / {
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name auth.hofmanns.ai;
|
||||
|
||||
ssl_certificate /etc/nginx/ssl/hofmanns.ai.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl/hofmanns.ai.key;
|
||||
|
||||
location / {
|
||||
proxy_pass http://authentik-server:9000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
}
|
||||
|
||||
# RustDesk Web (optional)
|
||||
server {
|
||||
listen 80;
|
||||
server_name rustdesk.hofmanns.ai;
|
||||
|
||||
location / {
|
||||
proxy_pass http://rustdesk-hbbs:21118;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
}
|
||||
|
||||
# Forward Auth für alle geschützten Services
|
||||
# Beispiel für einen Service hinter Authentik
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name portal.hofmanns.ai;
|
||||
|
||||
ssl_certificate /etc/nginx/ssl/hofmanns.ai.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl/hofmanns.ai.key;
|
||||
|
||||
# Authentik Forward Auth
|
||||
location /outpost.goauthentik.io {
|
||||
proxy_pass http://authentik-server:9000/outpost.goauthentik.io;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location / {
|
||||
auth_request /outpost.goauthentik.io/auth/nginx;
|
||||
error_page 401 = @goauthentik_proxy_signin;
|
||||
|
||||
# Nach erfolgreicher Auth → weiterleiten zum Jetson
|
||||
proxy_pass http://JETSON_TUNNEL_OR_IP:3001;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
|
||||
location @goauthentik_proxy_signin {
|
||||
internal;
|
||||
add_header Set-Cookie $auth_cookie;
|
||||
return 302 /outpost.goauthentik.io/start?rd=$request_uri;
|
||||
}
|
||||
}
|
||||
80
infomaniak/setup-infomaniak.sh
Normal file
80
infomaniak/setup-infomaniak.sh
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# INFOMANIAK SERVER SETUP
|
||||
# Server: 185.143.102.153 (hofmanns.ai)
|
||||
# Run as: debian user
|
||||
# =============================================================================
|
||||
|
||||
set -e
|
||||
|
||||
echo "=========================================="
|
||||
echo " HOFMANNS.AI - INFOMANIAK SERVER SETUP"
|
||||
echo "=========================================="
|
||||
|
||||
# 1. Update System
|
||||
echo "[1/6] System Update..."
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
|
||||
# 2. Install Docker (falls noch nicht)
|
||||
echo "[2/6] Docker Check..."
|
||||
if ! command -v docker &> /dev/null; then
|
||||
curl -fsSL https://get.docker.com | sudo sh
|
||||
sudo usermod -aG docker debian
|
||||
echo "Docker installed. Please logout and login again, then re-run this script."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 3. Install Docker Compose
|
||||
echo "[3/6] Docker Compose Check..."
|
||||
if ! command -v docker-compose &> /dev/null; then
|
||||
sudo apt install -y docker-compose-plugin
|
||||
fi
|
||||
|
||||
# 4. Create directories
|
||||
echo "[4/6] Creating directories..."
|
||||
mkdir -p ~/hofmanns-auth/{authentik,rustdesk,nginx/conf.d,nginx/ssl,nginx/html}
|
||||
|
||||
# 5. Copy config files
|
||||
echo "[5/6] Copying config files..."
|
||||
cp docker-compose.yml ~/hofmanns-auth/
|
||||
cp .env.example ~/hofmanns-auth/.env
|
||||
cp -r nginx/* ~/hofmanns-auth/nginx/
|
||||
|
||||
# 6. Generate secrets
|
||||
echo "[6/6] Generating secrets..."
|
||||
cd ~/hofmanns-auth
|
||||
|
||||
# Generate Authentik secret
|
||||
AUTHENTIK_SECRET=$(openssl rand 60 | base64 -w 0)
|
||||
sed -i "s/CHANGE_ME_RUN_openssl_rand_60_base64/$AUTHENTIK_SECRET/" .env
|
||||
|
||||
# Generate PostgreSQL password
|
||||
PG_PASSWORD=$(openssl rand -base64 32)
|
||||
sed -i "s/CHANGE_ME_SECURE_PASSWORD_HERE/$PG_PASSWORD/" .env
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo " SETUP COMPLETE!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo " NEXT STEPS:"
|
||||
echo ""
|
||||
echo " 1. SSL Zertifikate erstellen (Let's Encrypt):"
|
||||
echo " sudo certbot certonly --standalone -d auth.hofmanns.ai"
|
||||
echo " sudo cp /etc/letsencrypt/live/auth.hofmanns.ai/* ~/hofmanns-auth/nginx/ssl/"
|
||||
echo ""
|
||||
echo " 2. Services starten:"
|
||||
echo " cd ~/hofmanns-auth"
|
||||
echo " docker compose up -d"
|
||||
echo ""
|
||||
echo " 3. Authentik Initial Setup:"
|
||||
echo " https://auth.hofmanns.ai/if/flow/initial-setup/"
|
||||
echo ""
|
||||
echo " 4. RustDesk Key anzeigen:"
|
||||
echo " cat ~/hofmanns-auth/rustdesk/id_ed25519.pub"
|
||||
echo ""
|
||||
echo " PORTS:"
|
||||
echo " - 80/443 → Nginx (Authentik Proxy)"
|
||||
echo " - 9000 → Authentik (intern)"
|
||||
echo " - 21115-21119 → RustDesk"
|
||||
echo ""
|
||||
172
setup.sh
Normal file
172
setup.sh
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# JETSON ORIN NANO 8GB - COMPLETE SETUP SCRIPT
|
||||
# Run this ONCE after JetPack flash
|
||||
# =============================================================================
|
||||
|
||||
set -e
|
||||
|
||||
USER="d"
|
||||
WIFI_SSID="Home.8"
|
||||
WIFI_PASS="123"
|
||||
STATIC_IP="192.168.1.50"
|
||||
GATEWAY="192.168.1.1"
|
||||
|
||||
echo "=========================================="
|
||||
echo " JETSON ORIN NANO - HOME HUB SETUP"
|
||||
echo "=========================================="
|
||||
|
||||
# 1. System Update
|
||||
echo "[1/10] System Update..."
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
|
||||
# 2. Install required packages
|
||||
echo "[2/10] Installing packages..."
|
||||
sudo apt install -y \
|
||||
docker.io docker-compose \
|
||||
hostapd bridge-utils \
|
||||
git curl wget htop \
|
||||
python3-pip \
|
||||
alsa-utils pulseaudio \
|
||||
ffmpeg \
|
||||
nvtop
|
||||
|
||||
# 3. Add user to docker group
|
||||
echo "[3/10] Docker permissions..."
|
||||
sudo usermod -aG docker $USER
|
||||
|
||||
# 4. Create swap (8GB for Whisper models)
|
||||
echo "[4/10] Creating 8GB swap..."
|
||||
sudo fallocate -l 8G /swapfile
|
||||
sudo chmod 600 /swapfile
|
||||
sudo mkswap /swapfile
|
||||
sudo swapon /swapfile
|
||||
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
|
||||
|
||||
# 5. Set static IP for eth0
|
||||
echo "[5/10] Network configuration..."
|
||||
sudo tee /etc/netplan/01-netcfg.yaml << EOF
|
||||
network:
|
||||
version: 2
|
||||
renderer: NetworkManager
|
||||
ethernets:
|
||||
eth0:
|
||||
addresses:
|
||||
- ${STATIC_IP}/24
|
||||
routes:
|
||||
- to: default
|
||||
via: ${GATEWAY}
|
||||
nameservers:
|
||||
addresses:
|
||||
- 127.0.0.1
|
||||
- 1.1.1.1
|
||||
EOF
|
||||
|
||||
# 6. Disable NetworkManager for wlan (we use hostapd)
|
||||
echo "[6/10] Disable NetworkManager for wlan..."
|
||||
sudo tee /etc/NetworkManager/conf.d/99-unmanaged-wlan.conf << EOF
|
||||
[keyfile]
|
||||
unmanaged-devices=interface-name:wlan*
|
||||
EOF
|
||||
|
||||
# 7. Setup Bridge for AP
|
||||
echo "[7/10] Bridge configuration..."
|
||||
sudo tee /etc/network/interfaces.d/br0 << EOF
|
||||
auto br0
|
||||
iface br0 inet dhcp
|
||||
bridge_ports eth0
|
||||
bridge_stp off
|
||||
bridge_fd 0
|
||||
EOF
|
||||
|
||||
# 8. hostapd configuration (Bridge Mode - NO NAT!)
|
||||
echo "[8/10] hostapd configuration..."
|
||||
sudo tee /etc/hostapd/hostapd.conf << EOF
|
||||
interface=wlan0
|
||||
bridge=br0
|
||||
driver=nl80211
|
||||
ssid=${WIFI_SSID}
|
||||
hw_mode=a
|
||||
channel=36
|
||||
wmm_enabled=1
|
||||
macaddr_acl=0
|
||||
auth_algs=1
|
||||
ignore_broadcast_ssid=0
|
||||
wpa=2
|
||||
wpa_passphrase=${WIFI_PASS}
|
||||
wpa_key_mgmt=WPA-PSK
|
||||
rsn_pairwise=CCMP
|
||||
country_code=CH
|
||||
|
||||
# 802.11n/ac settings
|
||||
ieee80211n=1
|
||||
ieee80211ac=1
|
||||
ht_capab=[HT40+][SHORT-GI-20][SHORT-GI-40]
|
||||
vht_capab=[SHORT-GI-80][MAX-MPDU-11454]
|
||||
vht_oper_chwidth=1
|
||||
vht_oper_centr_freq_seg0_idx=42
|
||||
EOF
|
||||
|
||||
sudo sed -i 's|#DAEMON_CONF=""|DAEMON_CONF="/etc/hostapd/hostapd.conf"|' /etc/default/hostapd
|
||||
|
||||
# 9. Enable services
|
||||
echo "[9/10] Enable services..."
|
||||
sudo systemctl unmask hostapd
|
||||
sudo systemctl enable hostapd
|
||||
sudo systemctl enable docker
|
||||
|
||||
# 10. Create docker directory structure
|
||||
echo "[10/10] Creating directory structure..."
|
||||
mkdir -p /home/$USER/docker/{homeassistant,adguard,whisper,jellyfin,portainer,filebrowser,syncthing,ollama,piper,rustdesk,homepage,npm}
|
||||
mkdir -p /home/$USER/docker/homeassistant/config
|
||||
mkdir -p /home/$USER/docker/adguard/{work,conf}
|
||||
mkdir -p /home/$USER/docker/whisper/{models,wyoming}
|
||||
mkdir -p /home/$USER/docker/jellyfin/{config,cache}
|
||||
mkdir -p /home/$USER/docker/npm/{data,letsencrypt}
|
||||
mkdir -p /home/$USER/docker/syncthing
|
||||
mkdir -p /home/$USER/sync
|
||||
|
||||
# Copy all config files
|
||||
cp /home/$USER/jetson-setup/docker-compose.yml /home/$USER/docker/
|
||||
cp -r /home/$USER/jetson-setup/homepage/* /home/$USER/docker/homepage/
|
||||
cp -r /home/$USER/jetson-setup/whisper-webui-jetson /home/$USER/docker/
|
||||
|
||||
# Create filebrowser database
|
||||
touch /home/$USER/docker/filebrowser/database.db
|
||||
|
||||
# Install Cockpit for system management (Web UI)
|
||||
sudo apt install -y cockpit
|
||||
|
||||
# Set permissions
|
||||
chown -R $USER:$USER /home/$USER/docker
|
||||
chown -R $USER:$USER /home/$USER/sync
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo " SETUP COMPLETE!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo " NEXT STEPS:"
|
||||
echo " 1. REBOOT: sudo reboot"
|
||||
echo " 2. After reboot, start services:"
|
||||
echo " cd ~/docker && docker-compose up -d"
|
||||
echo ""
|
||||
echo " WEB UIs (alle im Browser!):"
|
||||
echo " ─────────────────────────────────────────"
|
||||
echo " http://192.168.1.50:3001 → Homepage Dashboard"
|
||||
echo " http://192.168.1.50:81 → Nginx Proxy Manager"
|
||||
echo " http://192.168.1.50:9443 → Portainer (Docker)"
|
||||
echo " http://192.168.1.50:9090 → Cockpit (System)"
|
||||
echo " http://192.168.1.50:8123 → Home Assistant"
|
||||
echo " http://192.168.1.50:3000 → AdGuard Setup"
|
||||
echo " http://192.168.1.50:7860 → Whisper (Speech→Text)"
|
||||
echo " http://192.168.1.50:8096 → Jellyfin (Media)"
|
||||
echo " http://192.168.1.50:8081 → FileBrowser (Cloud)"
|
||||
echo " http://192.168.1.50:8384 → Syncthing"
|
||||
echo ""
|
||||
echo " RUSTDESK Server: 192.168.1.50"
|
||||
echo " → Ports: 21115-21119"
|
||||
echo " → Key: cat ~/docker/rustdesk/id_ed25519.pub"
|
||||
echo ""
|
||||
echo " WiFi AP: ${WIFI_SSID} (CHANGE PASSWORD!)"
|
||||
echo ""
|
||||
16
whisper-webui-jetson/Dockerfile
Normal file
16
whisper-webui-jetson/Dockerfile
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Jetson Orin Nano optimized Whisper WebUI
|
||||
FROM dustynv/whisper:r36.2.0
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install Gradio
|
||||
RUN pip3 install --no-cache-dir gradio scipy
|
||||
|
||||
# Copy app
|
||||
COPY app.py /app/app.py
|
||||
|
||||
EXPOSE 7860
|
||||
|
||||
ENV WHISPER_MODEL=base
|
||||
|
||||
CMD ["python3", "/app/app.py"]
|
||||
177
whisper-webui-jetson/app.py
Normal file
177
whisper-webui-jetson/app.py
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Whisper Web UI - Browser-based Speech-to-Text
|
||||
Runs locally on Jetson Orin Nano with GPU acceleration
|
||||
"""
|
||||
|
||||
import gradio as gr
|
||||
import whisper
|
||||
import torch
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Load model (use GPU if available)
|
||||
device = "cuda" if torch.cuda.is_available() else "cpu"
|
||||
print(f"Using device: {device}")
|
||||
|
||||
MODEL_SIZE = os.getenv("WHISPER_MODEL", "base")
|
||||
print(f"Loading Whisper model: {MODEL_SIZE}")
|
||||
model = whisper.load_model(MODEL_SIZE, device=device)
|
||||
print("Model loaded!")
|
||||
|
||||
|
||||
def transcribe_audio(audio_path, language="auto", task="transcribe"):
|
||||
"""Transcribe audio file using Whisper"""
|
||||
if audio_path is None:
|
||||
return "No audio provided"
|
||||
|
||||
try:
|
||||
# Transcribe
|
||||
options = {
|
||||
"task": task,
|
||||
"fp16": device == "cuda"
|
||||
}
|
||||
|
||||
if language != "auto":
|
||||
options["language"] = language
|
||||
|
||||
result = model.transcribe(audio_path, **options)
|
||||
|
||||
# Format output
|
||||
text = result["text"]
|
||||
detected_lang = result.get("language", "unknown")
|
||||
|
||||
output = f"**Detected Language:** {detected_lang}\n\n"
|
||||
output += f"**Transcription:**\n{text}\n\n"
|
||||
|
||||
# Add segments with timestamps
|
||||
output += "**Segments:**\n"
|
||||
for segment in result["segments"]:
|
||||
start = segment["start"]
|
||||
end = segment["end"]
|
||||
segment_text = segment["text"]
|
||||
output += f"[{start:.2f}s - {end:.2f}s] {segment_text}\n"
|
||||
|
||||
return output
|
||||
|
||||
except Exception as e:
|
||||
return f"Error: {str(e)}"
|
||||
|
||||
|
||||
def transcribe_microphone(audio, language="auto", task="transcribe"):
|
||||
"""Transcribe from microphone input"""
|
||||
if audio is None:
|
||||
return "No audio recorded"
|
||||
|
||||
# audio is a tuple (sample_rate, numpy_array) from gradio
|
||||
sr, audio_data = audio
|
||||
|
||||
# Save to temp file
|
||||
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
|
||||
import scipy.io.wavfile as wav
|
||||
wav.write(f.name, sr, audio_data)
|
||||
return transcribe_audio(f.name, language, task)
|
||||
|
||||
|
||||
# Language options
|
||||
LANGUAGES = [
|
||||
("Auto Detect", "auto"),
|
||||
("German", "de"),
|
||||
("English", "en"),
|
||||
("French", "fr"),
|
||||
("Italian", "it"),
|
||||
("Spanish", "es"),
|
||||
("Portuguese", "pt"),
|
||||
("Dutch", "nl"),
|
||||
("Russian", "ru"),
|
||||
("Chinese", "zh"),
|
||||
("Japanese", "ja"),
|
||||
("Korean", "ko"),
|
||||
]
|
||||
|
||||
# Create Gradio interface
|
||||
with gr.Blocks(title="Whisper Local - Speech to Text", theme=gr.themes.Soft()) as demo:
|
||||
gr.Markdown("""
|
||||
# 🎤 Whisper Local - Speech to Text
|
||||
### Runs 100% locally on Jetson Orin Nano with GPU acceleration
|
||||
No cloud, no internet required, your audio stays private.
|
||||
""")
|
||||
|
||||
with gr.Tabs():
|
||||
# Tab 1: Microphone
|
||||
with gr.TabItem("🎙️ Microphone"):
|
||||
gr.Markdown("Record audio directly from your microphone")
|
||||
|
||||
with gr.Row():
|
||||
mic_input = gr.Audio(
|
||||
sources=["microphone"],
|
||||
type="numpy",
|
||||
label="Record Audio"
|
||||
)
|
||||
|
||||
with gr.Row():
|
||||
mic_language = gr.Dropdown(
|
||||
choices=LANGUAGES,
|
||||
value="auto",
|
||||
label="Language"
|
||||
)
|
||||
mic_task = gr.Radio(
|
||||
choices=["transcribe", "translate"],
|
||||
value="transcribe",
|
||||
label="Task (translate = to English)"
|
||||
)
|
||||
|
||||
mic_button = gr.Button("🚀 Transcribe", variant="primary")
|
||||
mic_output = gr.Markdown(label="Result")
|
||||
|
||||
mic_button.click(
|
||||
fn=transcribe_microphone,
|
||||
inputs=[mic_input, mic_language, mic_task],
|
||||
outputs=mic_output
|
||||
)
|
||||
|
||||
# Tab 2: File Upload
|
||||
with gr.TabItem("📁 File Upload"):
|
||||
gr.Markdown("Upload an audio or video file")
|
||||
|
||||
with gr.Row():
|
||||
file_input = gr.Audio(
|
||||
sources=["upload"],
|
||||
type="filepath",
|
||||
label="Upload Audio/Video"
|
||||
)
|
||||
|
||||
with gr.Row():
|
||||
file_language = gr.Dropdown(
|
||||
choices=LANGUAGES,
|
||||
value="auto",
|
||||
label="Language"
|
||||
)
|
||||
file_task = gr.Radio(
|
||||
choices=["transcribe", "translate"],
|
||||
value="transcribe",
|
||||
label="Task (translate = to English)"
|
||||
)
|
||||
|
||||
file_button = gr.Button("🚀 Transcribe", variant="primary")
|
||||
file_output = gr.Markdown(label="Result")
|
||||
|
||||
file_button.click(
|
||||
fn=transcribe_audio,
|
||||
inputs=[file_input, file_language, file_task],
|
||||
outputs=file_output
|
||||
)
|
||||
|
||||
gr.Markdown(f"""
|
||||
---
|
||||
**Model:** {MODEL_SIZE} | **Device:** {device} | **GPU:** {'✅ CUDA' if device == 'cuda' else '❌ CPU'}
|
||||
""")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo.launch(
|
||||
server_name="0.0.0.0",
|
||||
server_port=7860,
|
||||
share=False,
|
||||
ssl_verify=False
|
||||
)
|
||||
24
whisper-webui/Dockerfile
Normal file
24
whisper-webui/Dockerfile
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
FROM nvcr.io/nvidia/l4t-pytorch:r35.2.1-pth2.0-py3
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
ffmpeg \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Python packages
|
||||
RUN pip3 install --no-cache-dir \
|
||||
openai-whisper \
|
||||
gradio \
|
||||
numpy \
|
||||
torch \
|
||||
torchaudio
|
||||
|
||||
# Create the web interface
|
||||
COPY app.py /app/app.py
|
||||
|
||||
EXPOSE 7860
|
||||
|
||||
CMD ["python3", "app.py"]
|
||||
177
whisper-webui/app.py
Normal file
177
whisper-webui/app.py
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Whisper Web UI - Browser-based Speech-to-Text
|
||||
Runs locally on Jetson Orin Nano with GPU acceleration
|
||||
"""
|
||||
|
||||
import gradio as gr
|
||||
import whisper
|
||||
import torch
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Load model (use GPU if available)
|
||||
device = "cuda" if torch.cuda.is_available() else "cpu"
|
||||
print(f"Using device: {device}")
|
||||
|
||||
MODEL_SIZE = os.getenv("WHISPER_MODEL", "base")
|
||||
print(f"Loading Whisper model: {MODEL_SIZE}")
|
||||
model = whisper.load_model(MODEL_SIZE, device=device)
|
||||
print("Model loaded!")
|
||||
|
||||
|
||||
def transcribe_audio(audio_path, language="auto", task="transcribe"):
|
||||
"""Transcribe audio file using Whisper"""
|
||||
if audio_path is None:
|
||||
return "No audio provided"
|
||||
|
||||
try:
|
||||
# Transcribe
|
||||
options = {
|
||||
"task": task,
|
||||
"fp16": device == "cuda"
|
||||
}
|
||||
|
||||
if language != "auto":
|
||||
options["language"] = language
|
||||
|
||||
result = model.transcribe(audio_path, **options)
|
||||
|
||||
# Format output
|
||||
text = result["text"]
|
||||
detected_lang = result.get("language", "unknown")
|
||||
|
||||
output = f"**Detected Language:** {detected_lang}\n\n"
|
||||
output += f"**Transcription:**\n{text}\n\n"
|
||||
|
||||
# Add segments with timestamps
|
||||
output += "**Segments:**\n"
|
||||
for segment in result["segments"]:
|
||||
start = segment["start"]
|
||||
end = segment["end"]
|
||||
segment_text = segment["text"]
|
||||
output += f"[{start:.2f}s - {end:.2f}s] {segment_text}\n"
|
||||
|
||||
return output
|
||||
|
||||
except Exception as e:
|
||||
return f"Error: {str(e)}"
|
||||
|
||||
|
||||
def transcribe_microphone(audio, language="auto", task="transcribe"):
|
||||
"""Transcribe from microphone input"""
|
||||
if audio is None:
|
||||
return "No audio recorded"
|
||||
|
||||
# audio is a tuple (sample_rate, numpy_array) from gradio
|
||||
sr, audio_data = audio
|
||||
|
||||
# Save to temp file
|
||||
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
|
||||
import scipy.io.wavfile as wav
|
||||
wav.write(f.name, sr, audio_data)
|
||||
return transcribe_audio(f.name, language, task)
|
||||
|
||||
|
||||
# Language options
|
||||
LANGUAGES = [
|
||||
("Auto Detect", "auto"),
|
||||
("German", "de"),
|
||||
("English", "en"),
|
||||
("French", "fr"),
|
||||
("Italian", "it"),
|
||||
("Spanish", "es"),
|
||||
("Portuguese", "pt"),
|
||||
("Dutch", "nl"),
|
||||
("Russian", "ru"),
|
||||
("Chinese", "zh"),
|
||||
("Japanese", "ja"),
|
||||
("Korean", "ko"),
|
||||
]
|
||||
|
||||
# Create Gradio interface
|
||||
with gr.Blocks(title="Whisper Local - Speech to Text", theme=gr.themes.Soft()) as demo:
|
||||
gr.Markdown("""
|
||||
# 🎤 Whisper Local - Speech to Text
|
||||
### Runs 100% locally on Jetson Orin Nano with GPU acceleration
|
||||
No cloud, no internet required, your audio stays private.
|
||||
""")
|
||||
|
||||
with gr.Tabs():
|
||||
# Tab 1: Microphone
|
||||
with gr.TabItem("🎙️ Microphone"):
|
||||
gr.Markdown("Record audio directly from your microphone")
|
||||
|
||||
with gr.Row():
|
||||
mic_input = gr.Audio(
|
||||
sources=["microphone"],
|
||||
type="numpy",
|
||||
label="Record Audio"
|
||||
)
|
||||
|
||||
with gr.Row():
|
||||
mic_language = gr.Dropdown(
|
||||
choices=LANGUAGES,
|
||||
value="auto",
|
||||
label="Language"
|
||||
)
|
||||
mic_task = gr.Radio(
|
||||
choices=["transcribe", "translate"],
|
||||
value="transcribe",
|
||||
label="Task (translate = to English)"
|
||||
)
|
||||
|
||||
mic_button = gr.Button("🚀 Transcribe", variant="primary")
|
||||
mic_output = gr.Markdown(label="Result")
|
||||
|
||||
mic_button.click(
|
||||
fn=transcribe_microphone,
|
||||
inputs=[mic_input, mic_language, mic_task],
|
||||
outputs=mic_output
|
||||
)
|
||||
|
||||
# Tab 2: File Upload
|
||||
with gr.TabItem("📁 File Upload"):
|
||||
gr.Markdown("Upload an audio or video file")
|
||||
|
||||
with gr.Row():
|
||||
file_input = gr.Audio(
|
||||
sources=["upload"],
|
||||
type="filepath",
|
||||
label="Upload Audio/Video"
|
||||
)
|
||||
|
||||
with gr.Row():
|
||||
file_language = gr.Dropdown(
|
||||
choices=LANGUAGES,
|
||||
value="auto",
|
||||
label="Language"
|
||||
)
|
||||
file_task = gr.Radio(
|
||||
choices=["transcribe", "translate"],
|
||||
value="transcribe",
|
||||
label="Task (translate = to English)"
|
||||
)
|
||||
|
||||
file_button = gr.Button("🚀 Transcribe", variant="primary")
|
||||
file_output = gr.Markdown(label="Result")
|
||||
|
||||
file_button.click(
|
||||
fn=transcribe_audio,
|
||||
inputs=[file_input, file_language, file_task],
|
||||
outputs=file_output
|
||||
)
|
||||
|
||||
gr.Markdown(f"""
|
||||
---
|
||||
**Model:** {MODEL_SIZE} | **Device:** {device} | **GPU:** {'✅ CUDA' if device == 'cuda' else '❌ CPU'}
|
||||
""")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo.launch(
|
||||
server_name="0.0.0.0",
|
||||
server_port=7860,
|
||||
share=False,
|
||||
ssl_verify=False
|
||||
)
|
||||
6
whisper-webui/requirements.txt
Normal file
6
whisper-webui/requirements.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
openai-whisper
|
||||
gradio>=4.0.0
|
||||
torch
|
||||
torchaudio
|
||||
numpy
|
||||
scipy
|
||||
Loading…
Reference in a new issue