Compare commits
11
Commits
aeffb66466
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e19978fe6d | ||
|
|
5557ade95b | ||
|
|
ece6dc420a | ||
|
|
1ef3836a10 | ||
|
|
2ed6fd565e | ||
|
|
b174f0fe07 | ||
|
|
aec523a38c | ||
|
|
9a3807b784 | ||
|
|
d75ffbd5ab | ||
|
|
b8e75eac37 | ||
|
|
48817ba2f8 |
+1
-1
@@ -1 +1 @@
|
||||
#❗
|
||||
- [ ] #❗
|
||||
+1
-1
@@ -1 +1 @@
|
||||
#❗
|
||||
- [ ] #❗
|
||||
+1
-1
@@ -1 +1 @@
|
||||
#❗
|
||||
- [ ] #❗
|
||||
@@ -2,39 +2,46 @@
|
||||
|
||||
Sammlung wichtiger BASH-Befehle und Konzepte für die Linux-Konsole.
|
||||
|
||||
| Tastenkombi | Effekt |
|
||||
| ----------- | ---------------------------- |
|
||||
| `CTRL+U` | Lösche Eingabe vor Cursor |
|
||||
| `CTRL+K` | Lösche Eingabe nach Cursor |
|
||||
| `CTRL+A` | Springe ans Ende der Eingabe |
|
||||
|
||||
|
||||
## Grundlegende Konzepte
|
||||
|
||||
- [[BASH Funktionen]] - Wiederverwendbare Funktionen erstellen
|
||||
- [[IT-Know-How/Linux/BASH Basics/BASH Funktionen]] - Wiederverwendbare Funktionen erstellen
|
||||
|
||||
## Dateiverwaltung
|
||||
|
||||
- [[ls]] - Dateien auflisten und Größen anzeigen
|
||||
- [[find]] - Dateien suchen, filtern und verarbeiten (inkl. Datum, Löschen)
|
||||
- [[Symlinks]] - Symbolische Links erstellen und verwalten
|
||||
- [[IT-Know-How/Linux/BASH Basics/ls]] - Dateien auflisten und Größen anzeigen
|
||||
- [[IT-Know-How/Linux/BASH Basics/find]] - Dateien suchen, filtern und verarbeiten (inkl. Datum, Löschen)
|
||||
- [[IT-Know-How/Linux/BASH Basics/Symlinks]] - Symbolische Links erstellen und verwalten
|
||||
|
||||
## Textverarbeitung
|
||||
|
||||
- [[grep]] - Textsuche in Dateien
|
||||
- [[sed]] - Stream-Editor für Textmanipulation
|
||||
- [[awk]] - Datenextraktion und Spaltenverarbeitung
|
||||
- [[IT-Know-How/Linux/BASH Basics/grep]] - Textsuche in Dateien
|
||||
- [[IT-Know-How/Linux/BASH Basics/sed]] - Stream-Editor für Textmanipulation
|
||||
- [[IT-Know-How/Linux/BASH Basics/awk]] - Datenextraktion und Spaltenverarbeitung
|
||||
|
||||
## Berechtigungen
|
||||
|
||||
- [[Dateiberechtigungen]] - chmod und chown (Rechte, Eigentümer, Gruppen)
|
||||
- [[IT-Know-How/Linux/BASH Basics/Dateiberechtigungen]] - chmod und chown (Rechte, Eigentümer, Gruppen)
|
||||
|
||||
## Archive und Backup
|
||||
|
||||
- [[tar]] - Archive erstellen/entpacken und Software installieren
|
||||
- [[rsync]] - Dateien synchronisieren
|
||||
- [[IT-Know-How/Linux/BASH Basics/tar]] - Archive erstellen/entpacken und Software installieren
|
||||
- [[IT-Know-How/Linux/BASH Basics/rsync]] - Dateien synchronisieren
|
||||
|
||||
## System
|
||||
|
||||
- [[lsblk]] - Block-Geräte anzeigen
|
||||
- [[fstab Credentials]] - Zugangsdaten sicher in fstab speichern
|
||||
- [[IT-Know-How/Linux/BASH Basics/lsblk]] - Block-Geräte anzeigen
|
||||
- [[IT-Know-How/Linux/BASH Basics/fstab Credentials]] - Zugangsdaten sicher in fstab speichern
|
||||
|
||||
## Verwandte Themen
|
||||
|
||||
Weitere Linux-Themen im übergeordneten Verzeichnis:
|
||||
- [[Linux]] - Allgemeine Linux-Dokumentation
|
||||
- [[SSH Verbindung in Linux]] - SSH-Verbindungen
|
||||
- [[Navidrome]] - Musik-Server
|
||||
- [[IT-Know-How/Linux/SSH Verbindung in Linux]] - SSH-Verbindungen
|
||||
- [[IT-Know-How/Linux/Navidrome]] - Musik-Server
|
||||
|
||||
@@ -358,8 +358,8 @@ chown alice datei.txt # Permission denied (außer eigene Datei)
|
||||
|
||||
## Siehe auch
|
||||
|
||||
- [[find]] - Dateien mit bestimmten Rechten/Eigentümern finden
|
||||
- [[ls]] - Rechte und Eigentümer anzeigen
|
||||
- [[Symlinks]] - Links bleiben bei chown erhalten
|
||||
- [[tar]] - Rechte in Archiven bewahren
|
||||
- [[rsync]] - Rechte bei Synchronisation
|
||||
- [[IT-Know-How/Linux/BASH Basics/find]] - Dateien mit bestimmten Rechten/Eigentümern finden
|
||||
- [[IT-Know-How/Linux/BASH Basics/ls]] - Rechte und Eigentümer anzeigen
|
||||
- [[IT-Know-How/Linux/BASH Basics/Symlinks]] - Links bleiben bei chown erhalten
|
||||
- [[IT-Know-How/Linux/BASH Basics/tar]] - Rechte in Archiven bewahren
|
||||
- [[IT-Know-How/Linux/BASH Basics/rsync]] - Rechte bei Synchronisation
|
||||
|
||||
@@ -101,7 +101,7 @@ chmod +x weblink.desktop
|
||||
|
||||
## Siehe auch
|
||||
|
||||
- [[find]] - Dateien suchen (z.B. nach Symlinks mit `-type l`)
|
||||
- [[ls]] - Symlinks in Verzeichnissen anzeigen
|
||||
- [[Dateiberechtigungen]] - Rechte von Links und Zielen
|
||||
- [[lsblk]] - Block-Geräte anzeigen
|
||||
- [[IT-Know-How/Linux/BASH Basics/find]] - Dateien suchen (z.B. nach Symlinks mit `-type l`)
|
||||
- [[IT-Know-How/Linux/BASH Basics/ls]] - Symlinks in Verzeichnissen anzeigen
|
||||
- [[IT-Know-How/Linux/BASH Basics/Dateiberechtigungen]] - Rechte von Links und Zielen
|
||||
- [[IT-Know-How/Linux/BASH Basics/lsblk]] - Block-Geräte anzeigen
|
||||
|
||||
@@ -250,8 +250,8 @@ awk '
|
||||
|
||||
## Siehe auch
|
||||
|
||||
- [[grep]] - Textsuche
|
||||
- [[sed]] - Stream-Editor
|
||||
- [[find]] - Dateien finden
|
||||
- [[BASH Funktionen]] - awk in Funktionen nutzen
|
||||
- [[ls]] - Ausgabe mit awk verarbeiten
|
||||
- [[IT-Know-How/Linux/BASH Basics/grep]] - Textsuche
|
||||
- [[IT-Know-How/Linux/BASH Basics/sed]] - Stream-Editor
|
||||
- [[IT-Know-How/Linux/BASH Basics/find]] - Dateien finden
|
||||
- [[IT-Know-How/Linux/BASH Basics/BASH Funktionen]] - awk in Funktionen nutzen
|
||||
- [[IT-Know-How/Linux/BASH Basics/ls]] - Ausgabe mit awk verarbeiten
|
||||
|
||||
@@ -353,10 +353,10 @@ fd -e jpg -x convert {} ... # Mit exec
|
||||
|
||||
## Siehe auch
|
||||
|
||||
- [[ls]] - Dateien auflisten
|
||||
- [[grep]] - Textsuche in gefundenen Dateien
|
||||
- [[Dateiberechtigungen]] - Rechte und Eigentümer von Dateien
|
||||
- [[tar]] - Gefundene Dateien archivieren
|
||||
- [[rsync]] - Dateien synchronisieren
|
||||
- [[sed]] - Gefundene Dateien bearbeiten
|
||||
- [[awk]] - Ausgabe von find verarbeiten
|
||||
- [[IT-Know-How/Linux/BASH Basics/ls]] - Dateien auflisten
|
||||
- [[IT-Know-How/Linux/BASH Basics/grep]] - Textsuche in gefundenen Dateien
|
||||
- [[IT-Know-How/Linux/BASH Basics/Dateiberechtigungen]] - Rechte und Eigentümer von Dateien
|
||||
- [[IT-Know-How/Linux/BASH Basics/tar]] - Gefundene Dateien archivieren
|
||||
- [[IT-Know-How/Linux/BASH Basics/rsync]] - Dateien synchronisieren
|
||||
- [[IT-Know-How/Linux/BASH Basics/sed]] - Gefundene Dateien bearbeiten
|
||||
- [[IT-Know-How/Linux/BASH Basics/awk]] - Ausgabe von find verarbeiten
|
||||
|
||||
@@ -122,6 +122,6 @@ rm /tmp/credentials
|
||||
|
||||
## Siehe auch
|
||||
|
||||
- [[Symlinks]] - Symbolische Links erstellen
|
||||
- [[Dateiberechtigungen]] - Dateien absichern mit chmod/chown
|
||||
- [[lsblk]] - Block-Geräte anzeigen
|
||||
- [[IT-Know-How/Linux/BASH Basics/Symlinks]] - Symbolische Links erstellen
|
||||
- [[IT-Know-How/Linux/BASH Basics/Dateiberechtigungen]] - Dateien absichern mit chmod/chown
|
||||
- [[IT-Know-How/Linux/BASH Basics/lsblk]] - Block-Geräte anzeigen
|
||||
|
||||
@@ -196,7 +196,7 @@ rg "suchtext" /pfad # automatisch rekursiv, ignoriert .gitignore
|
||||
|
||||
## Siehe auch
|
||||
|
||||
- [[find]] - Dateien nach Namen/Eigenschaften suchen
|
||||
- [[sed]] - Stream-Editor für Textmanipulation
|
||||
- [[awk]] - Textverarbeitung und Datenextraktion
|
||||
- [[ls]] - Ausgabe von ls filtern
|
||||
- [[IT-Know-How/Linux/BASH Basics/find]] - Dateien nach Namen/Eigenschaften suchen
|
||||
- [[IT-Know-How/Linux/BASH Basics/sed]] - Stream-Editor für Textmanipulation
|
||||
- [[IT-Know-How/Linux/BASH Basics/awk]] - Textverarbeitung und Datenextraktion
|
||||
- [[IT-Know-How/Linux/BASH Basics/ls]] - Ausgabe von ls filtern
|
||||
|
||||
@@ -232,7 +232,7 @@ Top 10 größte Dateien:
|
||||
du -ah . | sort -rh | head -n 10
|
||||
```
|
||||
|
||||
Mit [[find]]:
|
||||
Mit [[IT-Know-How/Linux/BASH Basics/find]]:
|
||||
|
||||
```bash
|
||||
find . -type f -exec du -h {} + | sort -rh | head -n 10
|
||||
@@ -383,8 +383,8 @@ command ls # Umgeht Alias
|
||||
|
||||
## Siehe auch
|
||||
|
||||
- [[find]] - Erweiterte Dateisuche mit Kriterien
|
||||
- [[grep]] - Ausgabe filtern
|
||||
- [[Dateiberechtigungen]] - Bedeutung der Rechtespalten
|
||||
- [[lsblk]] - Block-Geräte statt Dateien
|
||||
- [[IT-Know-How/Linux/BASH Basics/find]] - Erweiterte Dateisuche mit Kriterien
|
||||
- [[IT-Know-How/Linux/BASH Basics/grep]] - Ausgabe filtern
|
||||
- [[IT-Know-How/Linux/BASH Basics/Dateiberechtigungen]] - Bedeutung der Rechtespalten
|
||||
- [[IT-Know-How/Linux/BASH Basics/lsblk]] - Block-Geräte statt Dateien
|
||||
- [[du]] - Detaillierte Größenanalyse
|
||||
|
||||
@@ -170,8 +170,8 @@ lsblk -o NAME,FSTYPE,SIZE | grep ext4
|
||||
|
||||
## Siehe auch
|
||||
|
||||
- [[ls]] - Dateien und Verzeichnisse auflisten
|
||||
- [[find]] - Dateien suchen
|
||||
- [[fstab Credentials]] - Geräte automatisch einbinden
|
||||
- [[Symlinks]] - Verknüpfungen zu Geräten
|
||||
- [[Dateiberechtigungen]] - Rechte von Geräten prüfen
|
||||
- [[IT-Know-How/Linux/BASH Basics/ls]] - Dateien und Verzeichnisse auflisten
|
||||
- [[IT-Know-How/Linux/BASH Basics/find]] - Dateien suchen
|
||||
- [[IT-Know-How/Linux/BASH Basics/fstab Credentials]] - Geräte automatisch einbinden
|
||||
- [[IT-Know-How/Linux/BASH Basics/Symlinks]] - Verknüpfungen zu Geräten
|
||||
- [[IT-Know-How/Linux/BASH Basics/Dateiberechtigungen]] - Rechte von Geräten prüfen
|
||||
|
||||
@@ -268,8 +268,8 @@ rsync -av --stats quelle/ ziel/
|
||||
|
||||
## Siehe auch
|
||||
|
||||
- [[tar]] - Archive erstellen
|
||||
- [[find]] - Dateien für Backup finden
|
||||
- [[Symlinks]] - Links bleiben mit -a erhalten
|
||||
- [[Dateiberechtigungen]] - Rechte und Eigentümer nach rsync
|
||||
- [[ls]] - Übertragene Dateien anzeigen
|
||||
- [[IT-Know-How/Linux/BASH Basics/tar]] - Archive erstellen
|
||||
- [[IT-Know-How/Linux/BASH Basics/find]] - Dateien für Backup finden
|
||||
- [[IT-Know-How/Linux/BASH Basics/Symlinks]] - Links bleiben mit -a erhalten
|
||||
- [[IT-Know-How/Linux/BASH Basics/Dateiberechtigungen]] - Rechte und Eigentümer nach rsync
|
||||
- [[IT-Know-How/Linux/BASH Basics/ls]] - Übertragene Dateien anzeigen
|
||||
|
||||
@@ -264,7 +264,7 @@ Statt `/` kann `|`, `#` oder andere Zeichen verwendet werden.
|
||||
|
||||
## Siehe auch
|
||||
|
||||
- [[grep]] - Textsuche
|
||||
- [[awk]] - Komplexere Textverarbeitung
|
||||
- [[find]] - Dateien finden und mit sed bearbeiten
|
||||
- [[BASH Funktionen]] - sed in Funktionen verwenden
|
||||
- [[IT-Know-How/Linux/BASH Basics/grep]] - Textsuche
|
||||
- [[IT-Know-How/Linux/BASH Basics/awk]] - Komplexere Textverarbeitung
|
||||
- [[IT-Know-How/Linux/BASH Basics/find]] - Dateien finden und mit sed bearbeiten
|
||||
- [[IT-Know-How/Linux/BASH Basics/BASH Funktionen]] - sed in Funktionen verwenden
|
||||
|
||||
@@ -347,8 +347,8 @@ Nach `make install` werden Dateien meist hier installiert:
|
||||
|
||||
## Siehe auch
|
||||
|
||||
- [[rsync]] - Alternative für Backups
|
||||
- [[find]] - Dateien für Archivierung finden
|
||||
- [[grep]] - Archiv-Inhalte durchsuchen
|
||||
- [[Dateiberechtigungen]] - Rechte in Archiven bewahren
|
||||
- [[ls]] - Archive anzeigen
|
||||
- [[IT-Know-How/Linux/BASH Basics/rsync]] - Alternative für Backups
|
||||
- [[IT-Know-How/Linux/BASH Basics/find]] - Dateien für Archivierung finden
|
||||
- [[IT-Know-How/Linux/BASH Basics/grep]] - Archiv-Inhalte durchsuchen
|
||||
- [[IT-Know-How/Linux/BASH Basics/Dateiberechtigungen]] - Rechte in Archiven bewahren
|
||||
- [[IT-Know-How/Linux/BASH Basics/ls]] - Archive anzeigen
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## Einzeiler
|
||||
```bash
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
```
|
||||
## Grundlegende Methoden
|
||||
|
||||
### 1. Einfache Variante mit `$0`
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
Effortless Folder Creation: You can create multiple directory combinations at once by using `mkdir -p` followed by the directory path with sections in curly braces. For example,
|
||||
```bash
|
||||
mkdir -p ./home/{a,b}/{x,y,z}.
|
||||
```
|
||||
|
||||
|
||||
Backtrack Fast: Instead of repeatedly typing `cd ..` to go back, simply use `cd -` to return to your previous directory immediately.
|
||||
|
||||
|
||||
Bulk File Generation: Create a large range of numbered files in seconds using the touch command with braces. For example, `touch file{1..100}.txt` will instantly create 100 text files.
|
||||
|
||||
|
||||
Real-time Log Monitoring: To watch a log file as it updates, use `tail -f [filename]`. The `-f` flag "follows" the file, so you see new lines of data as they are added in real-time.
|
||||
|
||||
|
||||
Quick Command History: If you need to see your most recent actions, use history followed by a number (e.g., `history 5`) to display exactly that many of your last commands.
|
||||
@@ -52,7 +52,7 @@ Ich fasse mal die Landschaft für dich zusammen: es gibt unter Linux kein exakte
|
||||
- Playlists: statisch + dynamisch.
|
||||
|
||||
- **Android:** Offizielle Clementine-Remote-App für Steuerung, oder Streaming via Subsonic-kompatibler Apps (z. B. [[DSub]], [[Ultrasonic]]).
|
||||
- siehe auch [[Subsonic-API]]
|
||||
- siehe auch [[IT-Know-How/Linux/Subsonic-API]]
|
||||
|
||||
- **Sync:**
|
||||
|
||||
@@ -127,7 +127,7 @@ Ich fasse mal die Landschaft für dich zusammen: es gibt unter Linux kein exakte
|
||||
|
||||
- **Native Linux-Lösung, solide & gepflegt** → **Strawberry auf Linux + GoneMAD auf Android**, Sync per Syncthing/rsync.
|
||||
|
||||
- **Wenn Playcount/Rating-Sync über Geräte _wirklich_ zentral ist** → **[[Navidrome]] (Server) + DSub/Ultrasonic auf Android**.
|
||||
- **Wenn Playcount/Rating-Sync über Geräte _wirklich_ zentral ist** → **[[IT-Know-How/Linux/Navidrome]] (Server) + DSub/Ultrasonic auf Android**.
|
||||
|
||||
|
||||
---
|
||||
@@ -141,24 +141,24 @@ Ich ziehe es vor, wenn es nativ unter Linux läuft. Es **muss** nicht auch nicht
|
||||
---
|
||||
Perfekt — danke für die Präzisierung. Du willst also **native Linux**-Werkzeuge, die in Summe ungefähr so mächtig sind wie MediaMonkey, und die Änderungen am PC (neue Songs, statische + dynamische Playlists, Metadaten usw.) sollen **möglichst 1:1 auf dem Android-Handy verfügbar** sein. Ich habe zwei praxiserprobte, native-unter-Linux-Workflows für genau dieses Ziel — einer ist _server-zentriert_ (am zuverlässigsten für Bidirektionalität von Playcounts/Playlists/Metadaten), der andere ist _Datei-Sync/Offline_-orientiert (besser für rein lokale Dateien/Offline-Nutzung, aber mit Einschränkungen bei Playcount/Ratings). Ich liste jeweils Voraussetzungen, wie es funktioniert, Vor-/Nachteile und konkrete Umsetzungspunkte.
|
||||
|
||||
# Empfehlung A — **(Meine Top-Wahl)** Lokaler Musik-Server ([[Navidrome]]/Airsonic) + native Player (Strawberry) auf PC + Subsonic-Client auf Android (z. B. DSub / Ultrasonic)
|
||||
# Empfehlung A — **(Meine Top-Wahl)** Lokaler Musik-Server ([[IT-Know-How/Linux/Navidrome]]/Airsonic) + native Player (Strawberry) auf PC + Subsonic-Client auf Android (z. B. DSub / Ultrasonic)
|
||||
|
||||
**Warum:** [[Navidrome]] (leichtgewichtiger, moderner Subsonic-kompatibler Server) läuft nativ unter Linux, indexiert deine Musikdateien und stellt Bibliothek + Playlists + Playcounts + Ratings zentral zur Verfügung. Android-Clients, die das Subsonic-API unterstützen, können sowohl streamen als auch offline cachen und melden Wiedergaben/Playcounts zurück an den Server — dadurch hast du eine echte 1:1-Synchronisation der Nutzungsdaten zwischen PC und Handy. [Navidrome] bietet außerdem Transcoding/Download-Transkodierung (nützlich, um Bitrate beim Übertragen zu reduzieren). Auf dem Desktop nutzt du einen richtigen Player/Tag-Editor wie **Strawberry** zum Bearbeiten der Dateien; der Server erkennt Änderungen bei Rescan/Auto-Import. ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
|
||||
**Warum:** [[IT-Know-How/Linux/Navidrome]] (leichtgewichtiger, moderner Subsonic-kompatibler Server) läuft nativ unter Linux, indexiert deine Musikdateien und stellt Bibliothek + Playlists + Playcounts + Ratings zentral zur Verfügung. Android-Clients, die das Subsonic-API unterstützen, können sowohl streamen als auch offline cachen und melden Wiedergaben/Playcounts zurück an den Server — dadurch hast du eine echte 1:1-Synchronisation der Nutzungsdaten zwischen PC und Handy. [Navidrome] bietet außerdem Transcoding/Download-Transkodierung (nützlich, um Bitrate beim Übertragen zu reduzieren). Auf dem Desktop nutzt du einen richtigen Player/Tag-Editor wie **Strawberry** zum Bearbeiten der Dateien; der Server erkennt Änderungen bei Rescan/Auto-Import. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||
|
||||
Wie das zusammenwirkt — Kurzablauf:
|
||||
|
||||
1. Auf dem Linux-PC: music-folder (z. B. `~/Music`) → Strawberry zum Abspielen & Tag-Editing. Strawberry ist native, hat Smart/Dynamic-Playlists und Tag-Editoren. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||
|
||||
2. Auf dem Linux-PC: [[Navidrome]] (als Dienst oder Docker) so konfigurieren, dass es auf genau denselben Music-Ordner zeigt. [[Navidrome]] indexiert die Dateien, liest Tags, Playlists (importiert `.m3u`) und verwaltet Playcounts/ratings serverseitig. ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
|
||||
2. Auf dem Linux-PC: [[IT-Know-How/Linux/Navidrome]] (als Dienst oder Docker) so konfigurieren, dass es auf genau denselben Music-Ordner zeigt. [[IT-Know-How/Linux/Navidrome]] indexiert die Dateien, liest Tags, Playlists (importiert `.m3u`) und verwaltet Playcounts/ratings serverseitig. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||
|
||||
3. Auf Android: Subsonic-kompatible App installieren (z. B. **DSub**, **Ultrasonic** oder Subsonic-App). Diese Apps können streamen, offline cachen/downloaden und (je nach App/Server-Einstellung) Playbacks/Playcounts an [[Navidrome]] zurückmelden; sie unterstützen auch clientseitiges Transcoding / Download-Qualitätssteuerung. (Subsonic-App-Ökosystem ist groß, DSub ist ein verbreiteter Client.) ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
|
||||
3. Auf Android: Subsonic-kompatible App installieren (z. B. **DSub**, **Ultrasonic** oder Subsonic-App). Diese Apps können streamen, offline cachen/downloaden und (je nach App/Server-Einstellung) Playbacks/Playcounts an [[IT-Know-How/Linux/Navidrome]] zurückmelden; sie unterstützen auch clientseitiges Transcoding / Download-Qualitätssteuerung. (Subsonic-App-Ökosystem ist groß, DSub ist ein verbreiteter Client.) ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
|
||||
|
||||
|
||||
Wesentliche Vorteile:
|
||||
|
||||
- **Echte Bidirektionalität** für Playcount/Play/Rating, wenn Client ↔ Server dies unterstützt (sehr viel zuverlässiger als reine Datei-Syncs). ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
|
||||
- **Echte Bidirektionalität** für Playcount/Play/Rating, wenn Client ↔ Server dies unterstützt (sehr viel zuverlässiger als reine Datei-Syncs). ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||
|
||||
- **On-the-fly Transcoding / Bitrate-Limit** beim Stream/Download — du kannst z. B. mobil immer in 128–192 kbps laden, während der PC die Originals behält. ([[Navidrome]](https://www.Navidrome.org/docs/usage/configuration-options/?utm_source=chatgpt.com "[[Navidrome]] Configuration Options"))
|
||||
- **On-the-fly Transcoding / Bitrate-Limit** beim Stream/Download — du kannst z. B. mobil immer in 128–192 kbps laden, während der PC die Originals behält. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/usage/configuration-options/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Configuration Options"))
|
||||
|
||||
- Desktop bleibt native (Strawberry), Server läuft nativ unter Linux. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||
|
||||
@@ -172,9 +172,9 @@ Nachteile / Dinge, die du beachten solltest:
|
||||
|
||||
**Kurz-Setup-Hinweise:**
|
||||
|
||||
- Installiere [[Navidrome]] (Deb/Flatpak/Docker) und stelle `MUSIC_FOLDER` auf deinen bestehenden Musikordner. Aktiviere ggf. `AutoImportPlaylists`. ([[Navidrome]](https://www.Navidrome.org/docs/usage/configuration-options/?utm_source=chatgpt.com "[[Navidrome]] Configuration Options"))
|
||||
- Installiere [[IT-Know-How/Linux/Navidrome]] (Deb/Flatpak/Docker) und stelle `MUSIC_FOLDER` auf deinen bestehenden Musikordner. Aktiviere ggf. `AutoImportPlaylists`. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/usage/configuration-options/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Configuration Options"))
|
||||
|
||||
- Installiere Strawberry als Desktop-Player und bearbeite Tags/Playlists dort; [[Navidrome]] neu scannen lassen oder Auto-Rescan aktivieren. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||
- Installiere Strawberry als Desktop-Player und bearbeite Tags/Playlists dort; [[IT-Know-How/Linux/Navidrome]] neu scannen lassen oder Auto-Rescan aktivieren. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||
|
||||
- Auf Android: DSub/Ultrasonic konfigurieren (Server-URL mit deiner lokalen IP), in der App die Download/Transcode-Qualität setzen. ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
|
||||
|
||||
@@ -219,7 +219,7 @@ Workarounds:
|
||||
|
||||
# Vergleich & Entscheidungshilfe — kurz
|
||||
|
||||
- **Wenn du wirklich möchtest, dass Playcounts / LastPlayed / Ratings verlässlich zwischen PC ↔ Handy synchron sind → wähle den Server-Ansatz ([[Navidrome]] / Airsonic)**. Das ist die sauberste, wartungsarme Lösung für bidirektionale Nutzungsdaten; zusätzlich hast du komfortable Transcoding-Optionen für mobile Daten/Storage. ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
|
||||
- **Wenn du wirklich möchtest, dass Playcounts / LastPlayed / Ratings verlässlich zwischen PC ↔ Handy synchron sind → wähle den Server-Ansatz ([[IT-Know-How/Linux/Navidrome]] / Airsonic)**. Das ist die sauberste, wartungsarme Lösung für bidirektionale Nutzungsdaten; zusätzlich hast du komfortable Transcoding-Optionen für mobile Daten/Storage. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||
|
||||
- **Wenn du maximale Offline-Kontrolle über die Dateien willst (keine Serverstruktur) → wähle Syncthing + ein mächtiges Android-Player,** akzeptiere aber Einschränkungen bei Ratings/Playcounts bzw. plane zusätzliche Scripts/Workarounds ein. ([Gist](https://gist.github.com/johanwiden/d14ec414bd212e2ee8c2fae576115ef7?utm_source=chatgpt.com "How to configure Syncthing for Android"))
|
||||
|
||||
@@ -230,11 +230,11 @@ Workarounds:
|
||||
|
||||
1. **Testlauf Server-Option (empfohlen):**
|
||||
|
||||
- Installiere [[Navidrome]] (Docker oder Paket) und zeige es auf `~/Music`. ([[Navidrome]] ist leicht, kann lokal laufen.) ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
|
||||
- Installiere [[IT-Know-How/Linux/Navidrome]] (Docker oder Paket) und zeige es auf `~/Music`. ([[IT-Know-How/Linux/Navidrome]] ist leicht, kann lokal laufen.) ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||
|
||||
- Installiere DSub (oder Ultrasonic) auf dem Handy, verbinde mit [[Navidrome]]. Teste Streaming + Offline-Download + setzte Download-Bitrate auf z. B. 160 kbps. ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
|
||||
- Installiere DSub (oder Ultrasonic) auf dem Handy, verbinde mit [[IT-Know-How/Linux/Navidrome]]. Teste Streaming + Offline-Download + setzte Download-Bitrate auf z. B. 160 kbps. ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
|
||||
|
||||
- Auf dem PC: installiere **Strawberry**, bearbeite ein paar Tags & Playlists, lasse [[Navidrome]] neu scannen — prüfe die Änderungen im Android-Client. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||
- Auf dem PC: installiere **Strawberry**, bearbeite ein paar Tags & Playlists, lasse [[IT-Know-How/Linux/Navidrome]] neu scannen — prüfe die Änderungen im Android-Client. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||
|
||||
2. **Falls du stattdessen Offline-Dateien bevorzugst:**
|
||||
|
||||
@@ -249,9 +249,9 @@ Workarounds:
|
||||
|
||||
- Strawberry — native Linux Player: Smart/dynamic playlists, Tag-Editor, MusicBrainz/cover lookup. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||
|
||||
- [[Navidrome]] — leichter Subsonic-kompatibler Server, lokal nutzbar; Optionen für AutoImportPlaylists / Transcoding/Download-Transcode. ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
|
||||
- [[IT-Know-How/Linux/Navidrome]] — leichter Subsonic-kompatibler Server, lokal nutzbar; Optionen für AutoImportPlaylists / Transcoding/Download-Transcode. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||
|
||||
- Subsonic/DSub ecosystem — Android-Clients für Subsonic/[[Navidrome]] (Streaming, Offline Caching, Bitrate/Transcode Optionen). ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
|
||||
- Subsonic/DSub ecosystem — Android-Clients für Subsonic/[[IT-Know-How/Linux/Navidrome]] (Streaming, Offline Caching, Bitrate/Transcode Optionen). ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
|
||||
|
||||
- ID3-Frames (PCNT / POPM) — Playcount-Frame `PCNT` ist Teil der ID3v2-Spec (kann in Datei gespeichert werden). ([id3.org](https://id3.org/id3v2.3.0?utm_source=chatgpt.com "id3v2.3.0"))
|
||||
|
||||
@@ -264,7 +264,7 @@ Workarounds:
|
||||
|
||||
Wenn du willst, mache ich sofort eines von beiden für dich praktisch:
|
||||
|
||||
- **Variante A:** Ich erstelle dir eine Schritt-für-Schritt-Anleitung (konkret für Debian/Ubuntu/Fedora) zum Installieren/Einrichten von [[Navidrome]] + Strawberry + DSub (inkl. Beispiel-Config für Transcoding/AutoImport).
|
||||
- **Variante A:** Ich erstelle dir eine Schritt-für-Schritt-Anleitung (konkret für Debian/Ubuntu/Fedora) zum Installieren/Einrichten von [[IT-Know-How/Linux/Navidrome]] + Strawberry + DSub (inkl. Beispiel-Config für Transcoding/AutoImport).
|
||||
|
||||
- **Variante B:** Oder ich schreibe ein kurzes Syncthing-Setup-Tutorial + Hinweise, wie du Ratings/Playcounts am besten per ID3/Script synchronisierst (inkl. Beispielscript, das `PCNT`/`POPM` per `mutagen` oder `eyeD3` setzt).
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
* [[ssh Key erstellen]]
|
||||
* [[mein fstab]]
|
||||
* [[fstab]]
|
||||
*
|
||||
@@ -2,22 +2,22 @@
|
||||
|
||||
|
||||
|
||||
**Warum:** [[Navidrome]] (leichtgewichtiger, moderner Subsonic-kompatibler Server, -> [[Subsonic-API]]) läuft nativ unter Linux, indexiert deine Musikdateien und stellt Bibliothek + Playlists + Playcounts + Ratings zentral zur Verfügung. Android-Clients, die das Subsonic-API unterstützen, können sowohl streamen als auch offline cachen und melden Wiedergaben/Playcounts zurück an den Server — dadurch hast du eine echte 1:1-Synchronisation der Nutzungsdaten zwischen PC und Handy. [Navidrome] bietet außerdem Transcoding/Download-Transkodierung (nützlich, um Bitrate beim Übertragen zu reduzieren). Auf dem Desktop nutzt du einen richtigen Player/Tag-Editor wie [[Strawberry 1]] zum Bearbeiten der Dateien; der Server erkennt Änderungen bei Rescan/Auto-Import. ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
|
||||
**Warum:** [[IT-Know-How/Linux/Navidrome]] (leichtgewichtiger, moderner Subsonic-kompatibler Server, -> [[IT-Know-How/Linux/Subsonic-API]]) läuft nativ unter Linux, indexiert deine Musikdateien und stellt Bibliothek + Playlists + Playcounts + Ratings zentral zur Verfügung. Android-Clients, die das Subsonic-API unterstützen, können sowohl streamen als auch offline cachen und melden Wiedergaben/Playcounts zurück an den Server — dadurch hast du eine echte 1:1-Synchronisation der Nutzungsdaten zwischen PC und Handy. [Navidrome] bietet außerdem Transcoding/Download-Transkodierung (nützlich, um Bitrate beim Übertragen zu reduzieren). Auf dem Desktop nutzt du einen richtigen Player/Tag-Editor wie [[Strawberry 1]] zum Bearbeiten der Dateien; der Server erkennt Änderungen bei Rescan/Auto-Import. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||
|
||||
Wie das zusammenwirkt — Kurzablauf:
|
||||
|
||||
1. Auf dem Linux-PC: music-folder (z. B. `~/Music`) → Strawberry zum Abspielen & Tag-Editing. Strawberry ist native, hat Smart/Dynamic-Playlists und Tag-Editoren. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||
|
||||
2. Auf dem Linux-PC: [[Navidrome]] (als Dienst oder Docker) so konfigurieren, dass es auf genau denselben Music-Ordner zeigt. [[Navidrome]] indexiert die Dateien, liest Tags, Playlists (importiert `.m3u`) und verwaltet Playcounts/ratings serverseitig. ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
|
||||
2. Auf dem Linux-PC: [[IT-Know-How/Linux/Navidrome]] (als Dienst oder Docker) so konfigurieren, dass es auf genau denselben Music-Ordner zeigt. [[IT-Know-How/Linux/Navidrome]] indexiert die Dateien, liest Tags, Playlists (importiert `.m3u`) und verwaltet Playcounts/ratings serverseitig. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||
|
||||
3. Auf Android: Subsonic-kompatible App installieren (z. B. **DSub**, **Ultrasonic** oder Subsonic-App). Diese Apps können streamen, offline cachen/downloaden und (je nach App/Server-Einstellung) Playbacks/Playcounts an [[Navidrome]] zurückmelden; sie unterstützen auch clientseitiges Transcoding / Download-Qualitätssteuerung. (Subsonic-App-Ökosystem ist groß, DSub ist ein verbreiteter Client.) ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
|
||||
3. Auf Android: Subsonic-kompatible App installieren (z. B. **DSub**, **Ultrasonic** oder Subsonic-App). Diese Apps können streamen, offline cachen/downloaden und (je nach App/Server-Einstellung) Playbacks/Playcounts an [[IT-Know-How/Linux/Navidrome]] zurückmelden; sie unterstützen auch clientseitiges Transcoding / Download-Qualitätssteuerung. (Subsonic-App-Ökosystem ist groß, DSub ist ein verbreiteter Client.) ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
|
||||
|
||||
|
||||
Wesentliche Vorteile:
|
||||
|
||||
- **Echte Bidirektionalität** für Playcount/Play/Rating, wenn Client ↔ Server dies unterstützt (sehr viel zuverlässiger als reine Datei-Syncs). ([[Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[Navidrome]] Overview"))
|
||||
- **Echte Bidirektionalität** für Playcount/Play/Rating, wenn Client ↔ Server dies unterstützt (sehr viel zuverlässiger als reine Datei-Syncs). ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/overview/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Overview"))
|
||||
|
||||
- **On-the-fly Transcoding / Bitrate-Limit** beim Stream/Download — du kannst z. B. mobil immer in 128–192 kbps laden, während der PC die Originals behält. ([[Navidrome]](https://www.Navidrome.org/docs/usage/configuration-options/?utm_source=chatgpt.com "[[Navidrome]] Configuration Options"))
|
||||
- **On-the-fly Transcoding / Bitrate-Limit** beim Stream/Download — du kannst z. B. mobil immer in 128–192 kbps laden, während der PC die Originals behält. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/usage/configuration-options/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Configuration Options"))
|
||||
|
||||
- Desktop bleibt native (Strawberry), Server läuft nativ unter Linux. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||
|
||||
@@ -31,9 +31,9 @@ Nachteile / Dinge, die du beachten solltest:
|
||||
|
||||
**Kurz-Setup-Hinweise:**
|
||||
|
||||
- Installiere [[Navidrome]] (Deb/Flatpak/Docker) und stelle `MUSIC_FOLDER` auf deinen bestehenden Musikordner. Aktiviere ggf. `AutoImportPlaylists`. ([[Navidrome]](https://www.Navidrome.org/docs/usage/configuration-options/?utm_source=chatgpt.com "[[Navidrome]] Configuration Options"))
|
||||
- Installiere [[IT-Know-How/Linux/Navidrome]] (Deb/Flatpak/Docker) und stelle `MUSIC_FOLDER` auf deinen bestehenden Musikordner. Aktiviere ggf. `AutoImportPlaylists`. ([[IT-Know-How/Linux/Navidrome]](https://www.Navidrome.org/docs/usage/configuration-options/?utm_source=chatgpt.com "[[IT-Know-How/Linux/Navidrome]] Configuration Options"))
|
||||
|
||||
- Installiere Strawberry als Desktop-Player und bearbeite Tags/Playlists dort; [[Navidrome]] neu scannen lassen oder Auto-Rescan aktivieren. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||
- Installiere Strawberry als Desktop-Player und bearbeite Tags/Playlists dort; [[IT-Know-How/Linux/Navidrome]] neu scannen lassen oder Auto-Rescan aktivieren. ([strawberrymusicplayer.org](https://www.strawberrymusicplayer.org/?utm_source=chatgpt.com "Strawberry Music Player"))
|
||||
|
||||
- Auf Android: DSub/Ultrasonic konfigurieren (Server-URL mit deiner lokalen IP), in der App die Download/Transcode-Qualität setzen. ([subsonic.org](https://www.subsonic.org/pages/apps.jsp?utm_source=chatgpt.com "Subsonic Apps"))
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Perfekt – dann ist eine Subsonic-kompatible Library genau das, was du suchst 👍
|
||||
|
||||
Für [[Python]] gibt es z. B. [`py-sonic`](https://github.com/crustymonkey/py-sonic).
|
||||
Die ist zwar nicht mehr super aktiv gepflegt, funktioniert aber mit [[Navidrome]] problemlos, weil Navidrome die [[Subsonic-API]] spricht.
|
||||
Die ist zwar nicht mehr super aktiv gepflegt, funktioniert aber mit [[IT-Know-How/Linux/Navidrome]] problemlos, weil Navidrome die [[IT-Know-How/Linux/Subsonic-API]] spricht.
|
||||
|
||||
---
|
||||
|
||||
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
# Quick Start
|
||||
|
||||
Once you've [installed Yazi](https://yazi-rs.github.io/docs/installation), start the program with:
|
||||
|
||||
```
|
||||
yazi
|
||||
```
|
||||
|
||||
Press q to quit, F1 or ~ to open the help menu.
|
||||
|
||||
## Shell wrapper
|
||||
|
||||
We suggest using this `y` shell wrapper that provides the ability to change the current working directory when exiting Yazi.
|
||||
|
||||
- Bash / Zsh
|
||||
- Fish
|
||||
- Nushell
|
||||
- POSIX
|
||||
- Elvish
|
||||
- PowerShell
|
||||
- Command Prompt
|
||||
- Xonsh
|
||||
|
||||
```
|
||||
function y() { local tmp="$(mktemp -t "yazi-cwd.XXXXXX")" cwd command yazi "$@" --cwd-file="$tmp" IFS= read -r -d '' cwd < "$tmp" [ "$cwd" != "$PWD" ] && [ -d "$cwd" ] && builtin cd -- "$cwd" rm -f -- "$tmp"}
|
||||
```
|
||||
|
||||
To use it, copy the function into the configuration file of your respective shell.
|
||||
|
||||
Then use `y` instead of `yazi` to start, and press q to quit, you'll see the CWD changed. Sometimes, you don't want to change, press Q to quit.
|
||||
|
||||
## Keybindings
|
||||
|
||||
tip
|
||||
|
||||
For all keybindings, see the [default `keymap.toml` file](https://github.com/sxyazi/yazi/blob/shipped/yazi-config/preset/keymap-default.toml).
|
||||
|
||||
### Navigation
|
||||
|
||||
To navigate between files and directories you can use the arrow keys ←, ↓, ↑ and → or Vim-like keys such as h, j, k, l:
|
||||
|
||||
|Key binding|Alternate key|Action|
|
||||
|---|---|---|
|
||||
|k|↑|Move the cursor up|
|
||||
|j|↓|Move the cursor down|
|
||||
|l|→|Enter hovered directory|
|
||||
|h|←|Leave the current directory and into its parent|
|
||||
|
||||
Further navigation commands can be found in the table below.
|
||||
|
||||
|Key binding|Action|
|
||||
|---|---|
|
||||
|K|Seek up 5 units in the preview|
|
||||
|J|Seek down 5 units in the preview|
|
||||
|g ⇒ g|Move cursor to the top|
|
||||
|G|Move cursor to the bottom|
|
||||
|z|[Cd](https://yazi-rs.github.io/docs/configuration/keymap#mgr.cd) to a directory or [reveal](https://yazi-rs.github.io/docs/configuration/keymap#mgr.reveal) a file via fzf|
|
||||
|Z|[Cd](https://yazi-rs.github.io/docs/configuration/keymap#mgr.cd) to a directory via zoxide|
|
||||
|g ⇒ Space|[Cd](https://yazi-rs.github.io/docs/configuration/keymap#mgr.cd) to a directory or [reveal](https://yazi-rs.github.io/docs/configuration/keymap#mgr.reveal) a file via interactive prompt|
|
||||
|
||||
### Selection
|
||||
|
||||
To select files and directories, the following commands are available.
|
||||
|
||||
|Key binding|Action|
|
||||
|---|---|
|
||||
|Space|Toggle selection of hovered file/directory|
|
||||
|v|Enter visual mode (selection mode)|
|
||||
|V|Enter visual mode (unset mode)|
|
||||
|Ctrl + a|Select all files|
|
||||
|Ctrl + r|Inverse selection of all files|
|
||||
|Esc|Cancel selection|
|
||||
|
||||
### File operations
|
||||
|
||||
To interact with selected files/directories use any of the commands below.
|
||||
|
||||
|Key binding|Action|
|
||||
|---|---|
|
||||
|o|Open selected files|
|
||||
|O|Open selected files interactively|
|
||||
|Enter|Open selected files|
|
||||
|Shift + Enter|Open selected files interactively (some terminals don't support it yet)|
|
||||
|Tab|Show the file information|
|
||||
|y|Yank selected files (copy)|
|
||||
|x|Yank selected files (cut)|
|
||||
|p|Paste yanked files|
|
||||
|P|Paste yanked files (overwrite if the destination exists)|
|
||||
|Y or X|Cancel the yank status|
|
||||
|d|Trash selected files|
|
||||
|D|Permanently delete selected files|
|
||||
|a|Create a file (ends with / for directories)|
|
||||
|r|Rename selected file(s)|
|
||||
|.|Toggle the visibility of hidden files|
|
||||
|
||||
Further file operation commands can be found in the table below.
|
||||
|
||||
|Key binding|Action|
|
||||
|---|---|
|
||||
|;|Run a shell command|
|
||||
|:|Run a shell command (block until finishes)|
|
||||
|-|Symlink the absolute path of yanked files|
|
||||
|_|Symlink the relative path of yanked files|
|
||||
|Ctrl + -|Hardlink yanked files|
|
||||
|
||||
### Copy paths
|
||||
|
||||
To copy paths, use any of the following commands below.
|
||||
|
||||
_Observation: c ⇒ d indicates pressing the c key followed by pressing the d key._
|
||||
|
||||
|Key binding|Action|
|
||||
|---|---|
|
||||
|c ⇒ c|Copy the file path|
|
||||
|c ⇒ d|Copy the directory path|
|
||||
|c ⇒ f|Copy the filename|
|
||||
|c ⇒ n|Copy the filename without extension|
|
||||
|
||||
### Filter files
|
||||
|
||||
|Key binding|Action|
|
||||
|---|---|
|
||||
|f|Filter files|
|
||||
|
||||
### Find files
|
||||
|
||||
|Key binding|Action|
|
||||
|---|---|
|
||||
|/|Find next file|
|
||||
|?|Find previous file|
|
||||
|n|Go to the next found|
|
||||
|N|Go to the previous found|
|
||||
|
||||
### Search files
|
||||
|
||||
|Key binding|Action|
|
||||
|---|---|
|
||||
|s|Search files by name using [fd](https://github.com/sharkdp/fd)|
|
||||
|S|Search files by content using [ripgrep](https://github.com/BurntSushi/ripgrep)|
|
||||
|Ctrl + s|Cancel the ongoing search|
|
||||
|
||||
### Sorting
|
||||
|
||||
To sort files/directories use the following commands.
|
||||
|
||||
_Observation: , ⇒ a indicates pressing the , key followed by pressing the a key._
|
||||
|
||||
|Key binding|Action|
|
||||
|---|---|
|
||||
|, ⇒ m|Sort by modified time|
|
||||
|, ⇒ M|Sort by modified time (reverse)|
|
||||
|, ⇒ b|Sort by birth time|
|
||||
|, ⇒ B|Sort by birth time (reverse)|
|
||||
|, ⇒ e|Sort by file extension|
|
||||
|, ⇒ E|Sort by file extension (reverse)|
|
||||
|, ⇒ a|Sort alphabetically|
|
||||
|, ⇒ A|Sort alphabetically (reverse)|
|
||||
|, ⇒ n|Sort naturally|
|
||||
|, ⇒ N|Sort naturally (reverse)|
|
||||
|, ⇒ s|Sort by size|
|
||||
|, ⇒ S|Sort by size (reverse)|
|
||||
|, ⇒ r|Sort randomly|
|
||||
|
||||
### Multi-tab
|
||||
|
||||
|Key binding|Action|
|
||||
|---|---|
|
||||
|t|Create a new tab with CWD|
|
||||
|1, 2, ..., 9|Switch to the N-th tab|
|
||||
|[|Switch to the previous tab|
|
||||
|]|Switch to the next tab|
|
||||
|{|Swap current tab with previous tab|
|
||||
|}|Swap current tab with next tab|
|
||||
|Ctrl + c|Close the current tab|
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
# 🧭 Übersicht: `/etc/fstab` – Netzlaufwerke & SSHFS
|
||||
|
||||
Diese Datei enthält Einträge für automatisch eingehängte Netzlaufwerke.
|
||||
Wichtig: Teste Änderungen **immer** mit
|
||||
```bash
|
||||
sudo mount -a
|
||||
```
|
||||
um Syntaxfehler zu erkennen, bevor du neustartest.
|
||||
→ siehe [[fstab Grundlagen]]
|
||||
|
||||
---
|
||||
|
||||
## 🗂️ NAS-Laufwerke via NFS
|
||||
|
||||
```fstab
|
||||
192.168.0.14:/volume1/Gemeinsam /mnt/nas/gemeinsam nfs nfsvers=3,rw,_netdev,noac,actimeo=0 0 0
|
||||
```
|
||||
|
||||
**Annahmen:**
|
||||
- NAS-IP: `192.168.0.14`
|
||||
- Freigabe (Quelle): `/volume1/Gemeinsam`
|
||||
- Lokaler Mountpoint (Ziel): `/mnt/nas/gemeinsam`
|
||||
|
||||
**Erläuterung der Optionen:**
|
||||
- `nfsvers=3` → nutzt NFSv3 (älter, aber oft stabiler bei Synology)
|
||||
- `rw` → Schreib-/Lesezugriff
|
||||
- `_netdev` → mountet erst, wenn Netzwerk verfügbar ist
|
||||
- `noac` → deaktiviert Client-Caching (nützlich bei Dateisynchronisierung, kann Performance senken)
|
||||
- `actimeo=0` → setzt Cache-Timeout auf 0 (Dateiattribute werden immer neu gelesen)
|
||||
|
||||
👉 siehe [[NFS unter Linux]] und [[NFS Mount Optionen]]
|
||||
|
||||
💡 *Tipp:*
|
||||
Bei neueren Systemen oder stabilen Netzwerken ist `nfsvers=4` meist die bessere Wahl. Beispiel:
|
||||
```fstab
|
||||
192.168.0.14:/volume1/Gemeinsam /mnt/nas/gemeinsam nfs nfsvers=4,rw,_netdev 0 0
|
||||
```
|
||||
|
||||
📦 **Benötigtes Paket (Debian/Ubuntu):**
|
||||
```bash
|
||||
sudo apt install nfs-common
|
||||
```
|
||||
→ siehe [[NFS Client Installation]]
|
||||
|
||||
---
|
||||
|
||||
## ☁️ HiDrive via SFTP (SSHFS)
|
||||
|
||||
```fstab
|
||||
mathias2784@sftp.hidrive.strato.com:/users/mathias2784 /mnt/hidrive fuse.sshfs defaults,_netdev,IdentityFile=/home/mathias/.ssh/id_ed25519,allow_other 0 0
|
||||
```
|
||||
|
||||
**Erläuterung der Optionen:**
|
||||
- `fuse.sshfs` → nutzt das FUSE-Modul für SSHFS
|
||||
- `_netdev` → warte auf Netzwerk
|
||||
- `IdentityFile=...` → Pfad zum SSH-Key
|
||||
- `allow_other` → erlaubt Zugriff auch für andere Nutzer (Achtung: [[SSHFS Sicherheit]])
|
||||
|
||||
👉 siehe [[SSHFS unter Linux]] und [[HiDrive Konfiguration]]
|
||||
|
||||
💡 *Tipp:*
|
||||
Füge optional `reconnect,ServerAliveInterval=15,ServerAliveCountMax=3` hinzu, damit die Verbindung stabil bleibt:
|
||||
```fstab
|
||||
mathias2784@sftp.hidrive.strato.com:/users/mathias2784 /mnt/hidrive fuse.sshfs _netdev,IdentityFile=/home/mathias/.ssh/id_ed25519,allow_other,reconnect,ServerAliveInterval=15,ServerAliveCountMax=3 0 0
|
||||
```
|
||||
|
||||
📦 **Benötigtes Paket (Debian/Ubuntu):**
|
||||
```bash
|
||||
sudo apt install sshfs
|
||||
```
|
||||
→ siehe [[SSHFS Installation]]
|
||||
|
||||
---
|
||||
|
||||
## 🖥️ "Schneiderserver" via SSHFS
|
||||
|
||||
```fstab
|
||||
root@schneiderserver.site:/root /mnt/strato_vm fuse.sshfs _netdev,IdentityFile=/home/mathias/.ssh/id_ed25519_strato_vm,allow_other 0 0
|
||||
```
|
||||
|
||||
**Optionen wie oben**, jedoch:
|
||||
- Zugriff als `root` nur wenn zwingend notwendig (besser: Benutzer mit begrenzten Rechten)
|
||||
- Key-File ggf. mit restriktiven Rechten (`chmod 600`)
|
||||
|
||||
👉 siehe [[SSH Sicherheit]] und [[Root via SSH vermeiden]]
|
||||
|
||||
📦 **Benötigtes Paket (Debian/Ubuntu):**
|
||||
```bash
|
||||
sudo apt install sshfs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Allgemeine Hinweise
|
||||
|
||||
- Testen: `sudo mount -a`
|
||||
- Mounten einzelner Einträge:
|
||||
```bash
|
||||
sudo mount /mnt/hidrive
|
||||
```
|
||||
- Logs prüfen bei Problemen:
|
||||
```bash
|
||||
sudo journalctl -xe | grep sshfs
|
||||
```
|
||||
|
||||
Weitere Themen: [[fstab Optionen Übersicht]], [[Mount Fehlerbehebung]], [[Systemd Automounts]]
|
||||
@@ -0,0 +1,30 @@
|
||||
Abfrage auf Datenbank Tabelle
|
||||
```bash
|
||||
psql -U <username> -d <dbname> -c "SELECT * FROM information_schema.tables;"
|
||||
```
|
||||
.. fragt zB alle Tabellen in DB aus Systemtabelle ab
|
||||
### Abfrage in Docker Container
|
||||
Finde zuerst Namen des Containers heraus mit
|
||||
```bash
|
||||
docker ps
|
||||
```
|
||||
und dann
|
||||
```bash
|
||||
docker exec -it <container_name> psql -U <username> -d <dbname>
|
||||
```
|
||||
-> interaktive Session
|
||||
oder
|
||||
```bash
|
||||
docker exec -it <container_name> psql -U <username> -d <dbname> -c "SELECT <fields> FROM <table>;"
|
||||
```
|
||||
### Export Ergebnisse
|
||||
```bash
|
||||
docker exec -i <container_name> psql -U <username> -d <dbname> -c "SELECT <fields> FROM <table>;" > path/tp/file.txt
|
||||
```
|
||||
==WICHTIG==: Option `-i`, NICHT ~~`-it`~~, sonst hängt sich BASH auf
|
||||
### Export Ergebnisse als CSV
|
||||
```bash
|
||||
docker exec -i <container_name> psql -U <username> -d <dbname> -A -F, --csv -c "SELECT <fields> FROM <table>;" > path/tp/file.csv
|
||||
```
|
||||
Erklärung:
|
||||
>The `-A` flag (unaligned output), `-F,` (field separator comma), and `--csv` together produce CSV
|
||||
@@ -0,0 +1,44 @@
|
||||
# ripgrep (`rg`) – Quickstart Guide
|
||||
|
||||
> [!info] Was ist ripgrep?
|
||||
> `ripgrep` ist ein extrem schnelles, zeilenorientiertes Suchwerkzeug, das rekursiv Verzeichnisse nach Regex-Mustern durchsucht. Es respektiert standardmäßig `.gitignore` Dateien.
|
||||
|
||||
## 1. Basis-Befehle
|
||||
| Befehl | Beschreibung |
|
||||
| :--- | :--- |
|
||||
| `rg "Suchbegriff"` | Sucht rekursiv im aktuellen Verzeichnis. |
|
||||
| `rg "Suchbegriff" Pfad/zu/Ordner` | Sucht in einem spezifischen Verzeichnis. |
|
||||
| `rg -i "suchbegriff"` | Ignoriert Groß-/Kleinschreibung (*ignore case*). |
|
||||
| `rg -w "wort"` | Sucht nur nach ganzen Wörtern (*whole word*). |
|
||||
| `rg -v "begriff"` | Invertierte Suche (zeigt Zeilen, die den Begriff **nicht** enthalten). |
|
||||
|
||||
## 2. Dateitypen filtern
|
||||
Ripgrep kann Suchen auf bestimmte Dateitypen einschränken:
|
||||
- `rg -t md "Suchbegriff"`: Nur in **Markdown**-Dateien suchen.
|
||||
- `rg -T html "Suchbegriff"`: **HTML**-Dateien ausschließen.
|
||||
- `rg --type-list`: Zeigt alle verfügbaren Dateitypen an.
|
||||
|
||||
## 3. Kontext-Optionen
|
||||
Hilfreich, um die Zeilen um den Treffer herum zu sehen:
|
||||
- `rg -A 3 "Begriff"`: Zeigt 3 Zeilen **nach** (*After*) dem Treffer.
|
||||
- `rg -B 3 "Begriff"`: Zeigt 3 Zeilen **vor** (*Before*) dem Treffer.
|
||||
- `rg -C 3 "Begriff"`: Zeigt 3 Zeilen **Kontext** (davor und danach).
|
||||
|
||||
## 4. Fortgeschrittene Suche
|
||||
- `rg -l "Suchbegriff"`: Gibt nur die **Dateinamen** der Treffer aus.
|
||||
- `rg -n "Suchbegriff"`: Zeigt die **Zeilennummern** an (Standard).
|
||||
- `rg -u`: Ignoriert `.gitignore` (unrestricted). Nutzen Sie `-uu` für versteckte Dateien und `-uuu` für Binärdateien.
|
||||
- `rg -e "Muster1" -e "Muster2"`: Suche nach mehreren Mustern (ODER-Verknüpfung).
|
||||
|
||||
## 5. Suchen und Ersetzen (Trockenübung)
|
||||
`ripgrep` selbst ersetzt keine Dateien, kann aber das Ergebnis für Tools wie `sed` vorbereiten:
|
||||
- `rg "alt" --replace "neu"`: Zeigt in der Konsole an, wie die Ersetzung aussehen würde, ohne die Datei zu ändern.
|
||||
|
||||
## 6. Tipps für Obsidian-Nutzer
|
||||
Falls du `ripgrep` in deinem Vault nutzt:
|
||||
- **Tags finden:** `rg "#projekt/aktiv"`
|
||||
- **Interne Links:** `rg "\[\[Notizname\]\]"`
|
||||
- **Unfertige Aufgaben:** `rg "- \[ \]" -t md`
|
||||
|
||||
---
|
||||
*Erstellt am: 06.05.2026*
|
||||
@@ -0,0 +1,66 @@
|
||||
# yay Cache reparieren – AUR-Update schlägt fehl mit „Kein Git-Repository"
|
||||
|
||||
## Problem
|
||||
|
||||
Ein AUR-Paket lässt sich mit `yay` nicht aktualisieren, obwohl es im AUR existiert und eine neue Version gemeldet wird:
|
||||
|
||||
```bash
|
||||
yay -Syu <paket>
|
||||
```
|
||||
|
||||
Fehlermeldung (Beispiel `supersonic-desktop`, August 2026):
|
||||
|
||||
```
|
||||
:: (0/1) Es wurde nicht geschafft PKGBUILD zu aktualisieren: supersonic-desktop
|
||||
-> Fehler beim Abrufen von supersonic-desktop: Schwerwiegend: Kein Git-Repository
|
||||
(oder irgendeines der Elternverzeichnisse): .git
|
||||
context: exit status 128
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ursache
|
||||
|
||||
Der lokale Klon des AUR-Repos in yays Cache (`~/.cache/yay/<paket>`) ist **korrupt**.
|
||||
Typisch: der `.git`-Ordner ist unvollständig (z. B. fehlen `HEAD` oder `config`),
|
||||
meist nach einem abgebrochenen Clone/Pull oder einer gestörten Synchronisation.
|
||||
|
||||
Das AUR-Paket selbst ist in Ordnung – nur die lokale Kopie ist kaputt.
|
||||
|
||||
---
|
||||
|
||||
## Diagnose
|
||||
|
||||
Prüfen, ob der Klon wirklich korrupt ist:
|
||||
|
||||
```bash
|
||||
git -C ~/.cache/yay/<paket> status
|
||||
```
|
||||
|
||||
Kommt dieselbe Meldung („Kein Git-Repository"), obwohl der Ordner existiert → Cache-Klon löschen.
|
||||
|
||||
---
|
||||
|
||||
## Lösung
|
||||
|
||||
Nur den betroffenen Paketordner entfernen und Update erneut ausführen:
|
||||
|
||||
```bash
|
||||
rm -rf ~/.cache/yay/<paket>
|
||||
yay -Syu
|
||||
```
|
||||
|
||||
yay klont das PKGBUILD-Repo beim nächsten Lauf frisch – danach funktioniert das Update wieder.
|
||||
|
||||
---
|
||||
|
||||
## Allgemein: yay-Cache aufräumen
|
||||
|
||||
| Vorgehen | Befehl | Folge |
|
||||
| --- | --- | --- |
|
||||
| Gezielt ein Paket (bevorzugt) | `rm -rf ~/.cache/yay/<paket>` | Nur dieses Paket wird neu geklont |
|
||||
| Gesamten Cache löschen | `rm -rf ~/.cache/yay` | Sicher, aber alle AUR-Pakete werden beim nächsten `-Syu` neu geklont **und neu kompiliert** (bei großen Builds langsam) |
|
||||
| Alte/unbenutzte Pakete aufräumen | `yay -Sc` | Entfernt alte Caches, aktuelle bleiben erhalten |
|
||||
|
||||
**Faustregel:** Immer erst den einzelnen Paketordner löschen. Den kompletten Cache nur leeren,
|
||||
wenn mehrere Pakete betroffen sind – er enthält nichts Kritisches, kostet aber Rebuild-Zeit.
|
||||
Executable
+927
@@ -0,0 +1,927 @@
|
||||
# SSR Migration Learnings: From Static Site to Server-Side Rendering
|
||||
|
||||
## Overview
|
||||
|
||||
This document captures the challenges, learnings, and solutions from migrating a Nuxt frontend application from static site generation (SSG) to server-side rendering (SSR) mode, particularly focusing on backend API communication in a Docker/containerized environment.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Background Context](#background-context)
|
||||
- [Key Challenges](#key-challenges)
|
||||
- [Core Concepts](#core-concepts)
|
||||
- [Detailed Problem Analysis & Solutions](#detailed-problem-analysis--solutions)
|
||||
- [Architecture Patterns](#architecture-patterns)
|
||||
- [Best Practices & Lessons Learned](#best-practices--lessons-learned)
|
||||
- [Future Reference](#future-reference)
|
||||
|
||||
---
|
||||
|
||||
## Background Context
|
||||
|
||||
### Initial State (Static Site Generation)
|
||||
- **Architecture**: Nuxt app built with `npm run generate` → static HTML/CSS/JS files
|
||||
- **Serving**: Nginx serving static files directly
|
||||
- **API Communication**: Browser → Nginx `/api/*` → Backend service
|
||||
- **Configuration**: `BACKEND_HOST` set at **build time** (baked into static files)
|
||||
|
||||
### Target State (Server-Side Rendering)
|
||||
- **Architecture**: Nuxt app running as Node.js server (Nitro)
|
||||
- **Serving**: Nginx → Nuxt SSR server (port 3000) → Backend service
|
||||
- **API Communication**: Browser → Nuxt Server (internal) → Backend service
|
||||
- **Configuration**: `BACKEND_HOST` set at **runtime** (environment variable)
|
||||
|
||||
### Why SSR?
|
||||
1. **Security**: Backend API completely hidden from browser
|
||||
2. **Architecture**: Frontend server acts as secure proxy/gateway
|
||||
3. **Flexibility**: Can add middleware, caching, request transformation
|
||||
4. **SEO**: Server-rendered HTML (bonus benefit)
|
||||
|
||||
---
|
||||
|
||||
## Key Challenges
|
||||
|
||||
### Challenge 1: "Network Error" on Login
|
||||
**Symptom**: Login attempts failed with generic "Network Error"
|
||||
|
||||
**Root Causes**:
|
||||
1. Environment variable name mismatch
|
||||
2. Missing API proxy routes in SSR server
|
||||
3. Client trying to access internal Docker network addresses
|
||||
|
||||
### Challenge 2: Hidden Default Values
|
||||
**Symptom**: Hard-coded `http://localhost:8000` defaults masked configuration errors
|
||||
|
||||
**Root Causes**:
|
||||
1. Fallback values in `nuxt.config.ts`
|
||||
2. Configuration errors failing silently
|
||||
3. Difficult to debug misconfiguration in production
|
||||
|
||||
### Challenge 3: Runtime vs Build-time Configuration
|
||||
**Symptom**: Environment variables not taking effect in SSR mode
|
||||
|
||||
**Root Causes**:
|
||||
1. Nuxt's runtime config requires specific environment variable naming
|
||||
2. Confusion between build-time and runtime configuration
|
||||
3. SSR hydration passing wrong values to client
|
||||
|
||||
---
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### 1. Nuxt Runtime Configuration
|
||||
|
||||
#### Build-time vs Runtime
|
||||
|
||||
**Build-time** (Static Generation):
|
||||
```typescript
|
||||
// nuxt.config.ts
|
||||
export default defineNuxtConfig({
|
||||
runtimeConfig: {
|
||||
public: {
|
||||
apiBase: process.env.BACKEND_HOST || 'http://localhost:8000'
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
- Value read **during `npm run build`**
|
||||
- Baked into compiled JavaScript
|
||||
- **Cannot change** without rebuilding
|
||||
|
||||
**Runtime** (SSR Mode):
|
||||
```typescript
|
||||
// nuxt.config.ts
|
||||
export default defineNuxtConfig({
|
||||
runtimeConfig: {
|
||||
public: {
|
||||
apiBase: process.env.NUXT_PUBLIC_API_BASE || process.env.BACKEND_HOST
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
- Value read **when server starts**
|
||||
- Can be overridden via environment variables
|
||||
- **Can change** without rebuilding (just restart container)
|
||||
|
||||
#### Nuxt Environment Variable Naming Convention
|
||||
|
||||
Nuxt automatically injects environment variables into runtime config if they follow specific patterns:
|
||||
|
||||
| Runtime Config Path | Auto-injected Env Var | Manual Env Var |
|
||||
|---------------------|----------------------|----------------|
|
||||
| `runtimeConfig.public.apiBase` | `NUXT_PUBLIC_API_BASE` | `process.env.BACKEND_HOST` |
|
||||
| `runtimeConfig.secret` | `NUXT_SECRET` | `process.env.SECRET` |
|
||||
| `runtimeConfig.public.foo.bar` | `NUXT_PUBLIC_FOO_BAR` | `process.env.FOO_BAR` |
|
||||
|
||||
**Key Insight**: Using `NUXT_PUBLIC_*` prefix enables automatic runtime override without code changes.
|
||||
|
||||
### 2. SSR Request Flow
|
||||
|
||||
#### Traditional SSG (Static Site)
|
||||
```
|
||||
┌─────────┐ ┌───────┐ ┌─────────┐
|
||||
│ Browser │─────▶│ Nginx │─────▶│ Backend │
|
||||
└─────────┘ └───────┘ └─────────┘
|
||||
/api/* → proxy
|
||||
```
|
||||
- Browser sees `/api` endpoints
|
||||
- Nginx proxies to backend
|
||||
- CORS required if different origins
|
||||
|
||||
#### Modern SSR Pattern
|
||||
```
|
||||
┌─────────┐ ┌───────┐ ┌────────────┐ ┌─────────┐
|
||||
│ Browser │─────▶│ Nginx │─────▶│ Nuxt SSR │─────▶│ Backend │
|
||||
└─────────┘ └───────┘ │ (Node.js) │ └─────────┘
|
||||
└────────────┘
|
||||
Proxy routes
|
||||
```
|
||||
- Browser never sees backend
|
||||
- Nuxt server makes backend calls
|
||||
- No CORS needed (server-to-server)
|
||||
|
||||
### 3. Client vs Server Context in SSR
|
||||
|
||||
In Nuxt SSR, code runs in **two contexts**:
|
||||
|
||||
#### Server Context
|
||||
- Runs on Node.js server
|
||||
- Has access to Docker internal network
|
||||
- Can reach `http://backend:8000`
|
||||
- No browser APIs (no `window`, `localStorage`, etc.)
|
||||
|
||||
#### Client Context
|
||||
- Runs in browser
|
||||
- Only sees public internet/nginx
|
||||
- **Cannot** reach `http://backend:8000` (internal Docker address)
|
||||
- Has browser APIs
|
||||
|
||||
**Critical Insight**: axios `baseURL` must be different for server vs client!
|
||||
|
||||
---
|
||||
|
||||
## Detailed Problem Analysis & Solutions
|
||||
|
||||
### Problem 1: Environment Variable Configuration
|
||||
|
||||
#### Issue: NUXT_PUBLIC_API_BASE vs BACKEND_HOST
|
||||
|
||||
**What Happened**:
|
||||
```yaml
|
||||
# docker-compose.test.yml (WRONG)
|
||||
environment:
|
||||
- BACKEND_HOST=http://backend:8000 # ❌ Not recognized by Nuxt at runtime
|
||||
```
|
||||
|
||||
```typescript
|
||||
// nuxt.config.ts
|
||||
runtimeConfig: {
|
||||
public: {
|
||||
apiBase: process.env.BACKEND_HOST // Read at build time, not runtime!
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Why It Failed**:
|
||||
1. Nuxt's runtime config injection only works with `NUXT_PUBLIC_*` prefix
|
||||
2. `process.env.BACKEND_HOST` was `undefined` during Docker runtime
|
||||
3. Config fell back to hardcoded default
|
||||
|
||||
**Solution Strategy** (Generalized):
|
||||
|
||||
When working with framework runtime configuration:
|
||||
1. **Check framework conventions** for environment variable naming
|
||||
2. **Support both patterns**: Framework convention + custom names
|
||||
3. **Fail fast** without defaults to catch configuration errors early
|
||||
|
||||
**Our Implementation**:
|
||||
|
||||
```typescript
|
||||
// nuxt.config.ts
|
||||
runtimeConfig: {
|
||||
public: {
|
||||
// NUXT_PUBLIC_API_BASE auto-injected by Nuxt
|
||||
// BACKEND_HOST read explicitly for local dev
|
||||
apiBase: process.env.NUXT_PUBLIC_API_BASE || process.env.BACKEND_HOST
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml (PRODUCTION)
|
||||
environment:
|
||||
- NUXT_PUBLIC_API_BASE=http://backend:8000 # ✅ Auto-injected by Nuxt
|
||||
```
|
||||
|
||||
```bash
|
||||
# .env (LOCAL DEVELOPMENT)
|
||||
BACKEND_HOST=http://localhost:8000 # ✅ Simpler name for developers
|
||||
```
|
||||
|
||||
**Key Takeaway**: Use framework conventions in production, but provide developer-friendly alternatives for local dev.
|
||||
|
||||
---
|
||||
|
||||
### Problem 2: Client-Side API Calls in SSR
|
||||
|
||||
#### Issue: Browser Cannot Reach Internal Docker Network
|
||||
|
||||
**What Happened**:
|
||||
```typescript
|
||||
// app/plugins/http.client.ts (WRONG)
|
||||
const http = axios.create({
|
||||
baseURL: config.public.apiBase // "http://backend:8000"
|
||||
})
|
||||
```
|
||||
|
||||
When browser tried to call APIs:
|
||||
```javascript
|
||||
// Browser console
|
||||
POST http://backend:8000/auth/token
|
||||
// ❌ DNS_PROBE_FINISHED_NXDOMAIN
|
||||
// Backend is a Docker service name, not resolvable from browser!
|
||||
```
|
||||
|
||||
**Root Cause Analysis**:
|
||||
|
||||
SSR hydration works like this:
|
||||
1. Server renders page with `config.public.apiBase = "http://backend:8000"`
|
||||
2. This config is serialized into HTML: `window.__NUXT__.config.public.apiBase`
|
||||
3. Browser hydrates with server config → tries to call `http://backend:8000`
|
||||
4. Browser DNS lookup fails (internal Docker name)
|
||||
|
||||
**Solution Strategy** (Generalized):
|
||||
|
||||
When building SSR applications with different network contexts:
|
||||
|
||||
1. **Identify the boundary**: Where does client context differ from server?
|
||||
2. **Use context detection**: `import.meta.server` vs `import.meta.client`
|
||||
3. **Configure per-context**: Different base URLs for different execution environments
|
||||
4. **Create proxy routes**: Let server handle external communication
|
||||
|
||||
**Our Implementation**:
|
||||
|
||||
#### Part 1: Context-Aware axios Configuration
|
||||
|
||||
```typescript
|
||||
// app/plugins/http.client.ts
|
||||
export default defineNuxtPlugin(() => {
|
||||
const config = useRuntimeConfig()
|
||||
|
||||
// Different baseURL based on execution context
|
||||
const apiBase = import.meta.server
|
||||
? config.public.apiBase // Server: "http://backend:8000"
|
||||
: '' // Client: "" (relative URLs)
|
||||
|
||||
const http = axios.create({
|
||||
baseURL: apiBase,
|
||||
withCredentials: false,
|
||||
})
|
||||
|
||||
return { provide: { http } }
|
||||
})
|
||||
```
|
||||
|
||||
#### Part 2: Server-Side API Proxy
|
||||
|
||||
```typescript
|
||||
// server/routes/auth/[...].ts
|
||||
// Catch-all route: matches /auth/*, /auth/token, /auth/me, etc.
|
||||
export default defineEventHandler(async (event) => {
|
||||
const config = useRuntimeConfig()
|
||||
|
||||
// event.path = "/auth/token"
|
||||
// backendUrl = "http://backend:8000/auth/token"
|
||||
const backendUrl = `${config.public.apiBase}${event.path}`
|
||||
|
||||
// Proxy request to backend
|
||||
return proxyRequest(event, backendUrl)
|
||||
})
|
||||
```
|
||||
|
||||
**Request Flow**:
|
||||
|
||||
1. **Browser**: `axios.post('/auth/token', data)` → relative URL
|
||||
2. **Nuxt Server**: Catches `/auth/token` via `server/routes/auth/[...].ts`
|
||||
3. **Proxy**: Forwards to `http://backend:8000/auth/token` (internal Docker network)
|
||||
4. **Backend**: Processes request, returns response
|
||||
5. **Nuxt Server**: Returns response to browser
|
||||
6. **Browser**: Receives response as if it came from same origin
|
||||
|
||||
**Key Insight**: In SSR, the client should **never** make external API calls directly. All external communication goes through the SSR server.
|
||||
|
||||
---
|
||||
|
||||
### Problem 3: Hardcoded Defaults Hiding Configuration Errors
|
||||
|
||||
#### Issue: Silent Failures
|
||||
|
||||
**What Happened**:
|
||||
```typescript
|
||||
// nuxt.config.ts (WRONG)
|
||||
runtimeConfig: {
|
||||
public: {
|
||||
apiBase: process.env.BACKEND_HOST || 'http://localhost:8000' // ❌ Silent fallback
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Why This Is Problematic**:
|
||||
|
||||
1. **Local dev masking**: Forgot to set `BACKEND_HOST`? No problem, silently uses `localhost:8000`
|
||||
2. **Production confusion**: Docker env var not set? Silently uses `localhost:8000` (wrong!)
|
||||
3. **Debugging nightmare**: App appears to work but calls wrong backend
|
||||
4. **No visibility**: Developers unaware of misconfiguration
|
||||
|
||||
**Real-World Scenario**:
|
||||
```bash
|
||||
# Developer forgot to copy .env file
|
||||
$ npm run dev
|
||||
# App starts fine, uses hardcoded localhost:8000
|
||||
# Works... but by accident!
|
||||
|
||||
# Later in production:
|
||||
$ docker-compose up
|
||||
# NUXT_PUBLIC_API_BASE not set in docker-compose
|
||||
# Falls back to localhost:8000
|
||||
# Frontend tries to call localhost inside container → fails
|
||||
# But error is unclear: "Network Error"
|
||||
```
|
||||
|
||||
**Solution Strategy** (Generalized):
|
||||
|
||||
**Fail Fast Principle**:
|
||||
1. **Explicit over implicit**: Require explicit configuration
|
||||
2. **Fail loudly**: Missing config should cause obvious errors
|
||||
3. **Clear error messages**: Tell user exactly what's missing
|
||||
4. **Documentation**: Example files with clear instructions
|
||||
|
||||
**Our Implementation**:
|
||||
|
||||
#### Remove Defaults
|
||||
```typescript
|
||||
// nuxt.config.ts (CORRECT)
|
||||
runtimeConfig: {
|
||||
public: {
|
||||
apiBase: process.env.NUXT_PUBLIC_API_BASE || process.env.BACKEND_HOST
|
||||
// No || 'http://localhost:8000' fallback!
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now if neither env var is set:
|
||||
```javascript
|
||||
config.public.apiBase = undefined
|
||||
```
|
||||
|
||||
When axios tries to use it:
|
||||
```javascript
|
||||
axios.create({ baseURL: undefined })
|
||||
// Makes requests to relative URLs
|
||||
// If proxy not configured: 404 errors (obvious!)
|
||||
```
|
||||
|
||||
#### Provide Example Configuration
|
||||
```bash
|
||||
# .env.example
|
||||
# REQUIRED: Backend API base URL
|
||||
#
|
||||
# For local development:
|
||||
# BACKEND_HOST=http://localhost:8000
|
||||
#
|
||||
# IMPORTANT: You must create a .env file:
|
||||
# cp .env.example .env
|
||||
#
|
||||
BACKEND_HOST=http://localhost:8000
|
||||
```
|
||||
|
||||
#### Update Documentation
|
||||
```markdown
|
||||
# README.md
|
||||
|
||||
**IMPORTANT:** `BACKEND_HOST` is **required** and must be set via `.env` file.
|
||||
There is no default value.
|
||||
|
||||
**Local development:**
|
||||
Create a `.env` file from the example:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
```
|
||||
|
||||
**Benefits**:
|
||||
- ✅ Configuration errors obvious immediately
|
||||
- ✅ Developers forced to understand configuration
|
||||
- ✅ Production deployments fail fast if misconfigured
|
||||
- ✅ Clear documentation guides proper setup
|
||||
|
||||
**Key Takeaway**: Defaults are tempting but dangerous. Explicit configuration prevents silent failures.
|
||||
|
||||
---
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
### Pattern 1: SSR API Proxy Gateway
|
||||
|
||||
**Use Case**: Frontend needs to call backend API, but backend should be hidden from browser
|
||||
|
||||
**Implementation**:
|
||||
|
||||
```typescript
|
||||
// server/routes/[api]/[...].ts
|
||||
// Generic catch-all for any API prefix
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const config = useRuntimeConfig()
|
||||
|
||||
// Extract path: /api/users/123 → /users/123
|
||||
const path = event.path.replace(/^\/api/, '')
|
||||
|
||||
// Build backend URL
|
||||
const backendUrl = `${config.public.apiBase}${path}`
|
||||
|
||||
// Forward everything: method, headers, body, query params
|
||||
return proxyRequest(event, backendUrl)
|
||||
})
|
||||
```
|
||||
|
||||
**Benefits**:
|
||||
- 🔒 Backend URL completely hidden from browser
|
||||
- 🛡️ Can add authentication, rate limiting, caching in proxy
|
||||
- 🔧 Easy to add request/response transformation
|
||||
- 📊 Centralized logging of all API calls
|
||||
|
||||
**Variations**:
|
||||
|
||||
1. **Multiple backends**:
|
||||
```typescript
|
||||
// Route different prefixes to different backends
|
||||
export default defineEventHandler(async (event) => {
|
||||
const config = useRuntimeConfig()
|
||||
|
||||
if (event.path.startsWith('/api/auth')) {
|
||||
return proxyRequest(event, `${config.authService}${event.path}`)
|
||||
} else if (event.path.startsWith('/api/data')) {
|
||||
return proxyRequest(event, `${config.dataService}${event.path}`)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
2. **With authentication injection**:
|
||||
```typescript
|
||||
export default defineEventHandler(async (event) => {
|
||||
const config = useRuntimeConfig()
|
||||
const backendUrl = `${config.public.apiBase}${event.path}`
|
||||
|
||||
// Add server-side auth token
|
||||
return proxyRequest(event, backendUrl, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${config.serverApiToken}`
|
||||
}
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### Pattern 2: Context-Aware Plugin Configuration
|
||||
|
||||
**Use Case**: Plugin behavior differs between server and client contexts
|
||||
|
||||
**Implementation**:
|
||||
|
||||
```typescript
|
||||
// plugins/http.client.ts
|
||||
export default defineNuxtPlugin(() => {
|
||||
const config = useRuntimeConfig()
|
||||
|
||||
// Server context: full backend URL (internal network)
|
||||
// Client context: empty (relative URLs to same origin)
|
||||
const baseURL = import.meta.server
|
||||
? config.public.apiBase
|
||||
: ''
|
||||
|
||||
const http = axios.create({ baseURL })
|
||||
|
||||
// Client-only: add auth from localStorage
|
||||
if (import.meta.client) {
|
||||
http.interceptors.request.use((req) => {
|
||||
const token = localStorage.getItem('access_token')
|
||||
if (token) {
|
||||
req.headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
return req
|
||||
})
|
||||
}
|
||||
|
||||
return { provide: { http } }
|
||||
})
|
||||
```
|
||||
|
||||
**Key Points**:
|
||||
- Use `import.meta.server` / `import.meta.client` for context detection
|
||||
- Server context: can access Docker internal network
|
||||
- Client context: browser APIs available (localStorage, etc.)
|
||||
|
||||
### Pattern 3: Environment Variable Layering
|
||||
|
||||
**Use Case**: Support multiple deployment environments with different naming conventions
|
||||
|
||||
**Strategy**:
|
||||
|
||||
```typescript
|
||||
// nuxt.config.ts
|
||||
export default defineNuxtConfig({
|
||||
runtimeConfig: {
|
||||
public: {
|
||||
// Priority order (first defined wins):
|
||||
// 1. NUXT_PUBLIC_API_BASE (Docker production, Nuxt convention)
|
||||
// 2. BACKEND_HOST (local dev, CI/CD, simpler name)
|
||||
// 3. undefined (fail fast)
|
||||
apiBase: process.env.NUXT_PUBLIC_API_BASE || process.env.BACKEND_HOST
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
**Usage Patterns**:
|
||||
|
||||
| Environment | Variable Used | Reason |
|
||||
|-------------|---------------|--------|
|
||||
| Local Dev | `BACKEND_HOST=http://localhost:8000` | Simpler for developers |
|
||||
| Docker Compose | `NUXT_PUBLIC_API_BASE=http://backend:8000` | Nuxt convention, runtime override |
|
||||
| CI/CD Build | `BACKEND_HOST=http://mock:8000` | Test environment |
|
||||
| Production | `NUXT_PUBLIC_API_BASE=http://api-service:8000` | Kubernetes service name |
|
||||
|
||||
---
|
||||
|
||||
## Best Practices & Lessons Learned
|
||||
|
||||
### 1. Configuration Management
|
||||
|
||||
#### ✅ Do's
|
||||
|
||||
**Always fail fast without defaults**
|
||||
```typescript
|
||||
// Good
|
||||
apiBase: process.env.BACKEND_HOST // undefined if not set
|
||||
|
||||
// Bad
|
||||
apiBase: process.env.BACKEND_HOST || 'http://localhost:8000' // Silent fallback
|
||||
```
|
||||
|
||||
**Provide clear example files**
|
||||
```bash
|
||||
# .env.example with EXTENSIVE comments
|
||||
# Explain why each variable is needed
|
||||
# Show example values for different environments
|
||||
BACKEND_HOST=http://localhost:8000 # Local dev
|
||||
# BACKEND_HOST=http://backend:8000 # Docker
|
||||
```
|
||||
|
||||
**Document required vs optional**
|
||||
```markdown
|
||||
## Required Environment Variables
|
||||
|
||||
- `BACKEND_HOST`: Backend API base URL (REQUIRED)
|
||||
- `DATABASE_URL`: Database connection string (REQUIRED)
|
||||
|
||||
## Optional Environment Variables
|
||||
|
||||
- `LOG_LEVEL`: Logging verbosity (default: 'info')
|
||||
```
|
||||
|
||||
#### ❌ Don'ts
|
||||
|
||||
**Don't hide configuration in code**
|
||||
```typescript
|
||||
// Bad: Magic values scattered in code
|
||||
const apiUrl = 'http://localhost:8000'
|
||||
```
|
||||
|
||||
**Don't use different names for same concept**
|
||||
```typescript
|
||||
// Bad: Confusing naming
|
||||
BACKEND_URL=...
|
||||
API_ENDPOINT=...
|
||||
SERVER_ADDRESS=...
|
||||
|
||||
// Good: Consistent naming
|
||||
BACKEND_HOST=...
|
||||
```
|
||||
|
||||
### 2. SSR Development
|
||||
|
||||
#### ✅ Do's
|
||||
|
||||
**Always check execution context**
|
||||
```typescript
|
||||
// Server-only code
|
||||
if (import.meta.server) {
|
||||
// Database queries, file system access
|
||||
}
|
||||
|
||||
// Client-only code
|
||||
if (import.meta.client) {
|
||||
// localStorage, window APIs, browser events
|
||||
}
|
||||
```
|
||||
|
||||
**Use relative URLs in client**
|
||||
```typescript
|
||||
// Good: Let SSR server handle routing
|
||||
axios.get('/api/users')
|
||||
|
||||
// Bad: Absolute URLs bypass SSR benefits
|
||||
axios.get('http://backend:8000/api/users')
|
||||
```
|
||||
|
||||
**Create comprehensive proxy routes**
|
||||
```typescript
|
||||
// server/routes/auth/[...].ts - Handles /auth/*
|
||||
// server/routes/api/[...].ts - Handles /api/*
|
||||
// server/routes/data/[...].ts - Handles /data/*
|
||||
```
|
||||
|
||||
#### ❌ Don'ts
|
||||
|
||||
**Don't access browser APIs in server context**
|
||||
```typescript
|
||||
// Bad: Crashes on server
|
||||
const token = localStorage.getItem('token')
|
||||
|
||||
// Good: Guard with context check
|
||||
const token = import.meta.client
|
||||
? localStorage.getItem('token')
|
||||
: null
|
||||
```
|
||||
|
||||
**Don't expose internal URLs to client**
|
||||
```typescript
|
||||
// Bad: Client gets internal Docker URL
|
||||
const config = {
|
||||
apiBase: 'http://backend:8000' // Browser can't resolve this!
|
||||
}
|
||||
|
||||
// Good: Client uses relative URLs
|
||||
const apiBase = import.meta.server
|
||||
? 'http://backend:8000'
|
||||
: ''
|
||||
```
|
||||
|
||||
### 3. Docker & Containerization
|
||||
|
||||
#### ✅ Do's
|
||||
|
||||
**Use service names for internal communication**
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
frontend:
|
||||
environment:
|
||||
- NUXT_PUBLIC_API_BASE=http://backend:8000 # ✅ Service name
|
||||
backend:
|
||||
# Backend service
|
||||
```
|
||||
|
||||
**Separate build-time and runtime config**
|
||||
```dockerfile
|
||||
# Build stage - no environment variables needed
|
||||
FROM node:25-alpine AS build
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# Runtime stage - environment variables matter here
|
||||
FROM node:25-alpine AS runtime
|
||||
ENV NODE_ENV=production
|
||||
CMD ["node", "server/index.mjs"]
|
||||
```
|
||||
|
||||
**Expose only what's necessary**
|
||||
```yaml
|
||||
services:
|
||||
backend:
|
||||
expose:
|
||||
- "8000" # ✅ Only internal Docker network
|
||||
# NO ports: section - not accessible from host
|
||||
|
||||
frontend:
|
||||
expose:
|
||||
- "3000" # ✅ Only to nginx
|
||||
# NO ports: section
|
||||
|
||||
nginx:
|
||||
ports:
|
||||
- "80:80" # ✅ Only nginx exposed to host
|
||||
```
|
||||
|
||||
#### ❌ Don'ts
|
||||
|
||||
**Don't expose internal services to host**
|
||||
```yaml
|
||||
# Bad: Backend directly accessible
|
||||
backend:
|
||||
ports:
|
||||
- "8000:8000" # ❌ Defeats purpose of SSR proxy
|
||||
```
|
||||
|
||||
**Don't use localhost in containers**
|
||||
```yaml
|
||||
# Bad: localhost inside container is the container itself
|
||||
environment:
|
||||
- BACKEND_HOST=http://localhost:8000 # ❌ Wrong!
|
||||
|
||||
# Good: Use service names
|
||||
environment:
|
||||
- BACKEND_HOST=http://backend:8000 # ✅ Correct
|
||||
```
|
||||
|
||||
### 4. Debugging SSR Issues
|
||||
|
||||
#### Diagnostic Checklist
|
||||
|
||||
When facing "Network Error" or similar issues:
|
||||
|
||||
1. **Check environment variables**
|
||||
```bash
|
||||
docker exec container_name env | grep BACKEND
|
||||
docker exec container_name env | grep NUXT
|
||||
```
|
||||
|
||||
2. **Verify network connectivity**
|
||||
```bash
|
||||
# From frontend to backend
|
||||
docker exec frontend_container wget -O- http://backend:8000/health
|
||||
|
||||
# Check if backend is running
|
||||
docker logs backend_container
|
||||
```
|
||||
|
||||
3. **Check Nuxt runtime config**
|
||||
```bash
|
||||
# Add temporary logging in nuxt.config.ts
|
||||
console.log('API Base:', process.env.NUXT_PUBLIC_API_BASE)
|
||||
```
|
||||
|
||||
4. **Inspect rendered HTML**
|
||||
```bash
|
||||
curl http://localhost:8080/login | grep apiBase
|
||||
# Look for: window.__NUXT__.config
|
||||
```
|
||||
|
||||
5. **Check axios requests in browser DevTools**
|
||||
```
|
||||
Network tab → Look at request URLs
|
||||
- Relative URLs (e.g., /auth/token) → ✅ Good
|
||||
- Internal URLs (e.g., http://backend:8000) → ❌ Problem
|
||||
```
|
||||
|
||||
6. **Verify proxy routes are built**
|
||||
```bash
|
||||
# Check Nuxt build output
|
||||
ls -la .output/server/chunks/routes/
|
||||
# Should see auth/_..._.mjs or similar
|
||||
```
|
||||
|
||||
#### Common Error Patterns
|
||||
|
||||
| Error | Likely Cause | Solution |
|
||||
|-------|--------------|----------|
|
||||
| `DNS_PROBE_FINISHED_NXDOMAIN` | Client trying to reach internal Docker name | Check axios baseURL, add proxy route |
|
||||
| `Network Error` (generic) | Multiple possible causes | Check all diagnostics above |
|
||||
| `ECONNREFUSED` | Service not running or wrong port | Verify backend is up, check ports |
|
||||
| `Not authenticated` (401) | Proxy working, auth issue | Check credentials, token handling |
|
||||
| `Cannot find module` | Build issue | Rebuild without cache |
|
||||
|
||||
---
|
||||
|
||||
## Future Reference
|
||||
|
||||
### Quick Decision Tree
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Need backend API in frontend?] -->|Yes| B[SSR or SSG?]
|
||||
B -->|SSR| C[Use proxy pattern]
|
||||
B -->|SSG| D[Direct calls with CORS]
|
||||
C --> E[Create server/routes proxy]
|
||||
C --> F[Use empty baseURL in client]
|
||||
C --> G[Use internal URL in server]
|
||||
D --> H[Configure CORS on backend]
|
||||
D --> I[Use full backend URL everywhere]
|
||||
```
|
||||
|
||||
### SSR vs SSG Decision Matrix
|
||||
|
||||
| Factor | SSR | SSG |
|
||||
|--------|-----|-----|
|
||||
| **Backend Hidden** | ✅ Yes | ❌ No (exposed to browser) |
|
||||
| **Server Resources** | Higher (Node.js) | Lower (static files) |
|
||||
| **Configuration** | Runtime env vars | Build-time vars |
|
||||
| **SEO** | ✅ Excellent | ✅ Excellent |
|
||||
| **Dynamic Content** | ✅ Real-time | ❌ Build-time only |
|
||||
| **Deploy Complexity** | Medium (Node.js server) | Low (just files) |
|
||||
| **Security** | ✅ Backend completely hidden | ⚠️ Backend URL exposed |
|
||||
| **Caching** | Complex (server-side) | Simple (CDN) |
|
||||
|
||||
**Choose SSR when**:
|
||||
- Backend must be hidden from browser
|
||||
- Need server-side request transformation
|
||||
- Real-time content crucial
|
||||
- Middleware/authentication needed
|
||||
|
||||
**Choose SSG when**:
|
||||
- Content mostly static
|
||||
- Backend can be public (with CORS)
|
||||
- Want simplest deployment
|
||||
- Need maximum performance (CDN)
|
||||
|
||||
### Environment Variable Naming Conventions
|
||||
|
||||
| Framework | Public Runtime Config | Private Runtime Config |
|
||||
|-----------|----------------------|------------------------|
|
||||
| **Nuxt 3/4** | `NUXT_PUBLIC_*` | `NUXT_*` |
|
||||
| **Next.js** | `NEXT_PUBLIC_*` | (none - server-side only) |
|
||||
| **Vite** | `VITE_*` | (none - build-time only) |
|
||||
| **Create React App** | `REACT_APP_*` | (none - build-time only) |
|
||||
|
||||
**Key Point**: Most frameworks require prefixes for public runtime config auto-injection.
|
||||
|
||||
### File Structure Reference
|
||||
|
||||
```
|
||||
project/
|
||||
├── app/
|
||||
│ ├── plugins/
|
||||
│ │ └── http.client.ts # Context-aware axios setup
|
||||
│ ├── composables/
|
||||
│ │ └── useAuth.ts # Uses $http from plugin
|
||||
│ └── pages/
|
||||
│ └── login.vue # Makes API calls
|
||||
├── server/
|
||||
│ └── routes/
|
||||
│ └── auth/
|
||||
│ └── [...].ts # Proxy for /auth/* endpoints
|
||||
├── .env.example # Template with docs
|
||||
├── .env # Local config (gitignored)
|
||||
├── nuxt.config.ts # Runtime config setup
|
||||
├── docker-compose.yml # Production config
|
||||
└── tests/deployment/
|
||||
├── docker-compose.test.yml # Test deployment
|
||||
└── nginx.test.conf # Nginx config
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
### Critical Success Factors
|
||||
|
||||
1. **Understand SSR dual execution contexts** (server vs client)
|
||||
2. **Use framework conventions** for environment variables
|
||||
3. **Fail fast** without defaults - explicit configuration
|
||||
4. **Create proxy routes** for all backend APIs
|
||||
5. **Context-aware base URLs** (full URL server, empty client)
|
||||
6. **Document everything** - future you will thank you
|
||||
|
||||
### Final Checklist for SSR Migration
|
||||
|
||||
- [ ] Remove all hardcoded defaults from config
|
||||
- [ ] Support both framework and custom env var names
|
||||
- [ ] Create server proxy routes for all API endpoints
|
||||
- [ ] Configure axios baseURL based on execution context
|
||||
- [ ] Update docker-compose with proper env vars
|
||||
- [ ] Test both client-side and server-side API calls
|
||||
- [ ] Document required environment variables
|
||||
- [ ] Provide .env.example with clear instructions
|
||||
- [ ] Update README with SSR-specific instructions
|
||||
- [ ] Verify backend is not exposed to browser (network tab)
|
||||
|
||||
### Key Learnings
|
||||
|
||||
> **The most important insight**: In SSR, the frontend runs in TWO places (server and browser), and each place has different network access. Configuration must account for both contexts.
|
||||
|
||||
> **The second most important insight**: Explicit configuration with no defaults prevents entire classes of bugs. The inconvenience of setup is far outweighed by the clarity and reliability gained.
|
||||
|
||||
> **The third most important insight**: Framework conventions exist for good reasons. Use `NUXT_PUBLIC_*` for Nuxt, `NEXT_PUBLIC_*` for Next.js, etc. Don't fight the framework - learn its patterns.
|
||||
|
||||
---
|
||||
|
||||
## Additional Resources
|
||||
|
||||
### Documentation Links
|
||||
|
||||
- [Nuxt 3 Runtime Config](https://nuxt.com/docs/guide/going-further/runtime-config)
|
||||
- [Nuxt 3 Server Routes](https://nuxt.com/docs/guide/directory-structure/server)
|
||||
- [h3 Event Handlers](https://h3.unjs.io/guide/event-handler)
|
||||
- [Docker Compose Environment Variables](https://docs.docker.com/compose/environment-variables/)
|
||||
|
||||
### Related Patterns
|
||||
|
||||
- API Gateway Pattern
|
||||
- Backend for Frontend (BFF)
|
||||
- Proxy Pattern
|
||||
- Configuration as Code
|
||||
|
||||
---
|
||||
|
||||
*Document created: 2026-04-16*
|
||||
*Last updated: 2026-04-16*
|
||||
*Context: SSR migration from static site to server-side rendering*
|
||||
@@ -1,4 +1,4 @@
|
||||
## 1. Die Basis: Modi & Navigation
|
||||
j## 1. Die Basis: Modi & Navigation
|
||||
Vim basiert auf dem Konzept von Modi. Um Befehle auszuführen, musst du fast immer im **Normal Mode** sein.
|
||||
|
||||
### Modi-Wechsel
|
||||
@@ -159,3 +159,17 @@ set smartcase " ...außer du tippst einen Großbuchstaben
|
||||
|
||||
### Profi-Tipp: Befehlsbuffer
|
||||
Wenn du einen komplexen Ex-Befehl (mit `:`) getippt hast und ihn bearbeiten willst, drücke im Normal-Modus `q:`. Es öffnet sich ein Fenster mit der Historie deiner Befehle, die du wie normalen Text bearbeiten und mit `Enter` neu ausführen kannst.
|
||||
|
||||
## Notizzettel
|
||||
- `:noh`: clear search highlighting
|
||||
- `s`: delete and insert
|
||||
- `s` Delete character under cursor, enter Insert mode
|
||||
- `S` Delete entire current line, enter Insert mode (equivalent to cc)
|
||||
- `{count}s` Delete count characters, enter Insert mode
|
||||
- Use f (find) followed by the character you want to jump to.
|
||||
- `f{char}` Jump to next occurrence of {char} on the current line
|
||||
- `F{char}` Jump to previous occurrence of {char} on the current line
|
||||
- `t{char}` Jump up to (one before) next occurrence of {char}
|
||||
- `T{char}` Jump up to previous occurrence of {char}
|
||||
- `;` Repeat last f/F/t/T forward
|
||||
- `,` Repeat last f/F/t/T backward
|
||||
@@ -1 +1 @@
|
||||
#❗
|
||||
- [ ] #❗
|
||||
@@ -1,4 +1,4 @@
|
||||
[[Navidrome]]
|
||||
[[IT-Know-How/Linux/Navidrome]]
|
||||
## 🧩 **Option 1: Über die Web-Oberfläche**
|
||||
|
||||
Wenn du nur die Bibliothek neu scannen willst:
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
```bash
|
||||
# /etc/fstab: static file system information.
|
||||
#
|
||||
# Use 'blkid' to print the universally unique identifier for a
|
||||
# device; this may be used with UUID= as a more robust way to name devices
|
||||
# that works even if disks are added and removed. See fstab(5).
|
||||
#
|
||||
# <file system> <mount point> <type> <options> <dump> <pass>
|
||||
# / was on /dev/nvme0n1p2 during installation
|
||||
UUID=4d4554dc-e3fc-499c-991c-074655585d11 / ext4 errors=remount-ro 0 1
|
||||
# /boot/efi was on /dev/nvme0n1p1 during installation
|
||||
UUID=FCBD-00BE /boot/efi vfat umask=0077 0 1
|
||||
/swapfile none swap sw 0 0
|
||||
UUID=04F6962EF6961FCA /mnt/anbau ntfs-3g defaults,umask=000,uid=1000,gid=1000 0 0
|
||||
UUID=A8F0EC77F0EC4D5E /mnt/bilder ntfs-3g defaults,umask=000,uid=1000,gid=1000 0 0
|
||||
UUID=5a603e70-aa52-405a-b86c-6b4def8d438f /mnt/spielplatz ext4 defaults 0 0
|
||||
UUID=a642b8a8-2cdd-4635-a094-e408073a236d /mnt/mathieu ext4 defaults 0 2
|
||||
#//192.168.0.14/Mathias /mnt/nas/mathias cifs credentials=/etc/secret.mathias.nas.smb,iocharset=utf8,uid=1000,gid=1000 0 0
|
||||
#//192.168.0.14/Gemeinsam /mnt/nas/gemeinsam cifs credentials=/etc/secret.mathias.nas.smb,iocharset=utf8,uid=1000,gid=1000 0 0
|
||||
192.168.0.14:/volume1/Mathias /mnt/nas/mathias nfs nfsvers=3,rw,_netdev,noac,actimeo=0 0 0
|
||||
192.168.0.14:/volume1/Gemeinsam /mnt/nas/gemeinsam nfs nfsvers=3,rw,_netdev,noac,actimeo=0 0 0
|
||||
mathias2784@sftp.hidrive.strato.com:/users/mathias2784 /mnt/hidrive fuse.sshfs defaults,_netdev,IdentityFile=/home/mathias/.ssh/id_ed25519,allow_other 0 0
|
||||
root@schneiderserver.site:/root /mnt/strato_vm fuse.sshfs _netdev,IdentityFile=/home/mathias/.ssh/id_ed25519_strato_vm,allow_other 0 0
|
||||
```
|
||||
@@ -14,7 +14,7 @@ tip
|
||||
|
||||
Get **enhanced capabilities**, including **custom theming and branding**, **Service Level Agreement (SLA) support**, **Long-Term Support (LTS) versions**, and **more!**
|
||||
|
||||
## Quick Start with [[Docker]] 🐳
|
||||
## Quick Start with [[IT-Know-How/verschiedene/Docker]] 🐳
|
||||
|
||||
info
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
Ein UAT ist ein User Acceptance Test (auf Deutsch: Abnahmetest oder Benutzerakzeptanztest).
|
||||
Kernidee:
|
||||
- UAT ist die letzte Testphase vor dem Go-Live eines Systems/Produkts.
|
||||
- Er wird von Fachbereichen / Endanwendern durchgeführt, nicht (nur) von Entwicklern oder Testern.
|
||||
- Ziel: Zu prüfen, ob die Lösung die fachlichen Anforderungen und Geschäftsprozesse in der Praxis wirklich unterstützt – also „passt das für unseren Alltag?“.
|
||||
Typische Merkmale:
|
||||
- Basis sind Anforderungen / User Stories und oft ein Akzeptanzkriterien-Katalog.
|
||||
- Es werden realitätsnahe Szenarien und Testdaten verwendet.
|
||||
- Ergebnis ist meist eine formale Abnahme („go“ oder „no go“) oder Abnahme mit Auflagen.
|
||||
Beispiel: Ein neues Buchungssystem ist technisch fertig. Im UAT prüfen Mitarbeitende aus dem Fachbereich z. B.:
|
||||
- Kann ich eine Buchung anlegen, ändern, stornieren wie beschrieben?
|
||||
- Stimmen Preise, Steuern, Rabatte in allen relevanten Fällen?
|
||||
- Sind Masken, Workflows und Reports so nutzbar wie im Fachkonzept definiert
|
||||
Reference in New Issue
Block a user