Categories
Development

React Projekt aufsetzen

## Ausgangslage Ubuntu 22.04.5 LTS mit node v20.17.0 und npm 10.8.2 ## React-Projekt einrichten 1. Terminal öffnen und in das Verzeichnis navigieren, in dem das Verzeichnis für das Projekt erstellt werden soll. 2. Erstelle ein neues Vite-Projekt mit React (Vite ist ein moderner Build-Tool, der schneller als Create React App ist):
npm create vite@latest my-react-app -- --template react
3. Wechsle in das neue Projektverzeichnis und installiere die Abhängigkeiten:
cd my-react-app && npm install
4: Starte den Entwicklungsserver:
npm run dev
Jetzt kanns im Browser unter http://localhost:5173 die React-Anwendung aufgerufen werden. ## Projektstruktur
my-react-app/
├── node_modules/
├── public/
├── src/
│   ├── assets/
│   ├── App.jsx
│   ├── App.css
│   ├── index.css
│   └── main.jsx
├── .gitignore
├── index.html
├── package.json
├── package-lock.json
└── vite.config.js
Wichtige Dateien: * src/App.jsx: Deine Hauptkomponente * src/main.jsx: Der Einstiegspunkt deiner Anwendung * index.html: Die HTML-Vorlage * package.json: Projektkonfiguration und Abhängigkeiten Nützliche npm Befehle: * npm run dev: Startet den Entwicklungsserver * npm run build: Erstellt eine optimierte Produktionsversion * npm run preview: Zeigt die Produktionsversion lokal an ## Wichtige Tools ### Tailwind CSS Tailwind CSS ist ein Utility-First-CSS-Framework, das eine Sammlung von vordefinierten CSS-Klassen bereitstellt, die man direkt in deinem HTML (oder JSX) verwenden kannst. Anstatt vordefinierte Komponenten (wie Buttons oder Karten) anzubieten, bietet Tailwind kleine, atomare Utility-Klassen, die man kombinieren kann, um benutzerdefinierte Designs zu erstellen. #### Utility-First-Ansatz Der Utility-First-Ansatz bedeutet, dass man Stile durch das Kombinieren von kleinen, spezifischen Klassen anwendest. Jede Klasse entspricht einer CSS-Eigenschaft. Beispiel:
<button class="bg-blue-500 text-white font-bold py-2 px-4 rounded">
  Klick mich
</button>
* ```bg-blue-500```: Hintergrundfarbe (blau, 500er Stufe). * ```text-white```: Textfarbe (weiß). * ```font-bold```:Schriftstärke (fett). * ```py-2```: Padding oben und unten (2 Einheiten). * ```px-4```: Padding links und rechts (4 Einheiten). * ```rounded```: Abgerundete Ecken. #### Warum werden PostCSS und Autoprefixer mit Tailwind CSS verwendet? Tailwind CSS ist ein Utility-First-Framework, das stark auf PostCSS angewiesen ist, um: * Utility-Klassen zu generieren: Tailwind verwendet PostCSS, um die Utility-Klassen (z. B. ```mt-4```, ```text-center```) in normales CSS umzuwandeln. * CSS zu optimieren: PostCSS entfernt ungenutzte CSS-Klassen (mit dem ```purge```-Feature), um die Bundle-Größe zu reduzieren. * Browser-Präfixe hinzuzufügen: Autoprefixer stellt sicher, dass das generierte CSS in allen Browsern funktioniert. ### PostCSS PostCSS ist ein Tool zur Transformation von CSS mit JavaScript. Es fungiert als eine Art "CSS-Compiler" und ermöglicht es, CSS durch Plugins zu erweitern und zu optimieren. Wofür braucht man PostCSS? * Tailwind CSS: Tailwind verwendet PostCSS, um seine Utility-Klassen in normales CSS umzuwandeln. * CSS-Modernisierung: PostCSS kann modernes CSS (z. B. CSS-Variablen, verschachtelte Regeln) in browserkompatibles CSS umwandeln. * Plugin-Ökosystem: Es gibt zahlreiche PostCSS-Plugins, die zusätzliche Funktionen bieten, z. B.: * Autoprefixer (für Browser-Präfixe) * CSS-Nano (für CSS-Minifizierung) * CSS-Modules (für lokale Scope-CSS) ### Autoprefixer Autoprefixer ist ein PostCSS-Plugin, das automatisch Browser-Präfixe (Vendor-Prefixes) zu deinem CSS hinzufügt. Dies stellt sicher, dass dein CSS in allen Browsern korrekt funktioniert. Wofür braucht man Autoprefixer? * Browser-Kompatibilität: Einige CSS-Eigenschaften (z. B. ```flexbox```, ```grid```, ```transform```) benötigen browser-spezifische Präfixe wie ```-webkit-```, ```-moz-```, ```-ms-``` usw. * Automatisierung: Autoprefixer fügt diese Präfixe automatisch hinzu, basierend auf den Browsern, die du unterstützen möchtest. Du musst dich nicht mehr manuell um Präfixe kümmern. * Zukunftssicherheit: Autoprefixer entfernt auch veraltete Präfixe, die nicht mehr benötigt werden. ### Lucide Lucide ist eine Sammlung von einfachen, eleganten und konsistenten Icons, die als Open Source verfügbar sind. Es ist der Nachfolger von Feather Icons und bietet eine große Auswahl an Icons für Web- und Mobile-Anwendungen. ```lucide-react``` ist das offizielle React-Paket, das die Lucide-Icons für die Verwendung in React-Projekten bereitstellt. * Icon-Sammlung: Lucide bietet über 1.000 Icons in einem einheitlichen Designstil. * Open Source: Die Icons sind kostenlos und unter der MIT-Lizenz verfügbar. * Einfach und minimalistisch: Die Icons sind schlicht und eignen sich gut für moderne Benutzeroberflächen. * Skalierbar: Die Icons sind als SVG verfügbar und können in jeder Größe verwendet werden. ## Installation und Einrichtung Installation und Einrichtung:
# Installation
npm install -D tailwindcss postcss autoprefixer lucide-react

# Tailwind und PostCSS Config erstellen
npx tailwindcss init -p
Die erzeugte ```tailwind.config.js```anpassen:
/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
Tailwind in das Projekt einbinden: In der Datei src/App.css folgenden Inhalt hinzufügen:
@tailwind base;
@tailwind components;
@tailwind utilities;
Den Entwicklungsserver starten:
npm run dev
Categories
Linux

Docker Setup with Traefik, Apache, and Portainer

## Requirements

### Software
- Docker and Docker Compose
- Apache HTTPD 2.4
- Traefik v3.2
- Portainer CE

### Domain Configuration
Base domain: kabango.eu
Required subdomains:
- www.kabango.eu (main website)
- kabango.eu (redirects to www)
- traefik.kabango.eu (Traefik dashboard)
- portainer.kabango.eu (Portainer interface)

### Features
- Automatic HTTPS with Let's Encrypt
- HTTP to HTTPS redirect
- Secure management interfaces
- Path-based routing for special section
- Shared Docker network
- Container management via web interface

## Directory Structure
```
/data/docker/
├── traefik/
│ ├── docker-compose.yml
│ ├── traefik.yml
│ └── config/
│ └── users.txt
├── apache1/
│ ├── docker-compose.yml
│ └── html/
│ └── index.html
├── apache2/
│ ├── docker-compose.yml
│ └── html/
│ └── index.html
└── portainer/
├── docker-compose.yml
└── data/
```

## Configuration Files

### Traefik Static Configuration
```yaml
# /data/docker/traefik/traefik.yml
api:
dashboard: true

entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"

providers:
docker:
exposedByDefault: false
network: traefik-net

certificatesResolvers:
letsencrypt:
acme:
email: admin@kabango.eu
storage: /etc/traefik/acme/acme.json
httpChallenge:
entryPoint: web

log:
level: INFO
```

### Traefik Docker Compose
```yaml
# /data/docker/traefik/docker-compose.yml
services:
traefik:
image: traefik:v3.2
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- traefik-net
ports:
- 80:80
- 443:443
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/etc/traefik/traefik.yml:ro
- ./config:/etc/traefik/config
- acme:/etc/traefik/acme
labels:
- traefik.enable=true
- traefik.http.routers.dashboard.rule=Host(`traefik.kabango.eu`)
- traefik.http.routers.dashboard.service=api@internal
- traefik.http.routers.dashboard.middlewares=auth
- traefik.http.routers.dashboard.entrypoints=websecure
- traefik.http.routers.dashboard.tls.certresolver=letsencrypt
- traefik.http.middlewares.auth.basicauth.usersfile=/etc/traefik/config/users.txt

volumes:
acme:

networks:
traefik-net:
external: true
```

### Apache1 Docker Compose (Main Website)
```yaml
# /data/docker/apache1/docker-compose.yml
services:
apache1:
image: httpd:2.4
container_name: apache1
restart: unless-stopped
networks:
- traefik-net
volumes:
- ./html:/usr/local/apache2/htdocs
labels:
- traefik.enable=true
- traefik.http.routers.apache1.rule=Host(`kabango.eu`) || Host(`www.kabango.eu`)
- traefik.http.routers.apache1.entrypoints=websecure
- traefik.http.routers.apache1.tls.certresolver=letsencrypt
- traefik.http.services.apache1.loadbalancer.server.port=80
- traefik.http.middlewares.www-redirect.redirectregex.regex=^https://kabango.eu/(.*)
- traefik.http.middlewares.www-redirect.redirectregex.replacement=https://www.kabango.eu/$${1}
- traefik.http.routers.apache1.middlewares=www-redirect

networks:
traefik-net:
external: true
```

### Apache2 Docker Compose (Special Section)
```yaml
# /data/docker/apache2/docker-compose.yml
services:
apache2:
image: httpd:2.4
container_name: apache2
restart: unless-stopped
networks:
- traefik-net
volumes:
- ./html:/usr/local/apache2/htdocs
labels:
- traefik.enable=true
- traefik.http.routers.apache2.rule=Host(`kabango.eu`) && PathPrefix(`/special`) || Host(`www.kabango.eu`) && PathPrefix(`/special`)
- traefik.http.routers.apache2.entrypoints=websecure
- traefik.http.routers.apache2.tls.certresolver=letsencrypt
- traefik.http.services.apache2.loadbalancer.server.port=80
- traefik.http.middlewares.strip-special.stripprefix.prefixes=/special
- traefik.http.routers.apache2.middlewares=strip-special

networks:
traefik-net:
external: true
```

### Portainer Docker Compose
```yaml
# /data/docker/portainer/docker-compose.yml
services:
portainer:
image: portainer/portainer-ce:latest
container_name: portainer
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- traefik-net
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data:/data
labels:
- traefik.enable=true
- traefik.http.routers.portainer.rule=Host(`portainer.kabango.eu`)
- traefik.http.routers.portainer.entrypoints=websecure
- traefik.http.routers.portainer.tls.certresolver=letsencrypt
- traefik.http.services.portainer.loadbalancer.server.port=9000

networks:
traefik-net:
external: true
```

### Sample HTML Files

Main Website (apache1):
```html




Welcome to Kabango.eu

Welcome to Kabango.eu

This is the main website.

Visit our special section.



```

Special Section (apache2):
```html




Special Section - Kabango.eu

Special Section

This is the special section of Kabango.eu

Back to main page



```

## Installation Steps

1. Create Docker network:
```bash
docker network create traefik-net
```

2. Create required directories:
```bash
mkdir -p /data/docker/{traefik/config,apache1/html,apache2/html,portainer,portainer/data}
```

3. Create Traefik basic auth credentials:
```bash
htpasswd -nb admin secure_password > /data/docker/traefik/config/users.txt
```

4. Create configuration files:
- Copy all configuration files to their respective locations as shown above
- Ensure correct file permissions

5. Configure DNS:
Point these domains to your server's IP:
- kabango.eu
- www.kabango.eu
- traefik.kabango.eu
- portainer.kabango.eu

6. Start services in order:
```bash
cd /data/docker/traefik && docker compose up -d
cd /data/docker/apache1 && docker compose up -d
cd /data/docker/apache2 && docker compose up -d
cd /data/docker/portainer && docker compose up -d
```

## Access Points

After setup, the following services will be available:

- Main website: https://www.kabango.eu
- Special section: https://www.kabango.eu/special
- Traefik dashboard: https://traefik.kabango.eu (login: admin/secure_password)
- Portainer: https://portainer.kabango.eu (create admin account on first access)

## Security Notes

1. Docker Socket:
- The Docker socket (`/var/run/docker.sock`) is only mounted in containers that require it:
- Traefik: For container discovery
- Portainer: For Docker management
- Other containers don't need and shouldn't have access to the Docker socket

2. Authentication:
- Traefik dashboard is protected with basic authentication
- Portainer requires setting up an admin account on first access
- All management interfaces are only accessible via HTTPS

3. Network Security:
- Services communicate through an isolated Docker network
- Only necessary ports (80, 443) are exposed on the host
- Automatic redirection from HTTP to HTTPS

## Maintenance

### Updating Services
To update any service to the latest version:
```bash
cd /data/docker/
docker compose pull
docker compose up -d
```

### Viewing Logs
To view logs for any service:
```bash
cd /data/docker/
docker compose logs
```

Add `-f` flag to follow the logs:
```bash
docker compose logs -f
```

### Backup
Important directories to backup:
- `/data/docker/traefik/config` - Traefik configuration
- `/data/docker/apache1/html` - Main website content
- `/data/docker/apache2/html` - Special section content
- Portainer data volume - Container configurations

## Troubleshooting

1. Certificate Issues:
- Check Traefik logs for Let's Encrypt errors
- Verify DNS records are correct
- Ensure ports 80 and 443 are accessible

2. Routing Problems:
- Verify Traefik router rules in docker-compose labels
- Check if containers are in the correct network
- Inspect Traefik dashboard for routing status

3. Container Access:
- Use `docker compose ps` to check container status
- Verify network connectivity with `docker network inspect traefik-net`
- Check container logs for errors

Categories
Development Linux

Apache HTTP in den Container

# Aufgabe
Ich möchte die nativen Dienste auf meinem Server zur besseren Verwaltung und als Vorbereitung für eine kommende Migration auf Docker umstellen.
Als Vorbereitung für diese Aufgabe habe ich in [Lokaler virtueller Server](https://ingo.kaulbach.de/lokaler-virtueller-server/) bereits ein grundlegendes Setup lokal evaluiert.
Heute möchte ich den Apache HTTP Server, der auch als Reverse Proxy dient, in einen Container stecken.

# Vorbereitung
## Docker deinstallieren
Auf dem Server ist bereits eine alte Docker Installation vorhanden. Diese habe ich als erstes rückstandslos entfernt.

## Docker installieren
Hier nur kurz die Befehle, aus [Lokaler virtueller Server](https://ingo.kaulbach.de/lokaler-virtueller-server/) übernommen:
```bash
sudo apt update
sudo apt upgrade -y

# Docker-Repository hinzufügen
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Docker installieren:
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

sudo systemctl enable docker
sudo systemctl start docker

# Rechte für den aktuellen Benutzer konfigurieren
sudo usermod -aG docker $USER
newgrp docker
```

## Ordnerstrukur
Die Dateien der Docker Dienste sollen in ```/data/docker/``` liegen.
Ein symbolischer Link von ```/home/docker``` soll auf das Verzeichnis zeigen.
```bash
sudo mkdir -p /data/docker
sudo ln -s /data/docker /home/docker

sudo chown :docker /data/docker
sudo chmod g+w /data/docker
```

# Apache HTTP Container
## Ordnerstruktur
```bash
mkdir /data/docker/apache
mkdir /data/docker/apache/config \
/data/docker/apache/html \
/data/docker/apache/logs
```

## Daten kopieren
```bash
sudo cp -r /etc/apache2/* /data/docker/apache/config
sudo cp -r /var/www/html/* /data/docker/apache/html
sudo cp -r /var/log/apache2 /data/docker/apache

sudo chown -R :docker /data/docker/apache
sudo chmod -R g+w /data/docker/apache

mv /data/docker/apache/apache2/* /data/docker/apache/logs
rm -rf /data/docker/apache/apache2
```

## Docker Compose Datei
```docker-compose.yml``` für Apache HTTP im Verzeichnis ```/data/docker/apache```:

```yaml
services:
apache:
image: httpd:2.4
container_name: apache
restart: always
ports:
- 80:80
- 443:443
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./config:/usr/local/apache2/conf
- ./html:/usr/local/apache2/htdocs
- ./logs:/usr/local/apache2/logs
```

## erster Start
Auf dem Server Apache HTTP stoppen:
```bash
# Service finden
systemctl list-unit-files --type service
# Service stoppen
sudo systemctl stop apache2
```
Container-Apache starten:
```bash
cd /data/docker/apache
docker compose up
```
Ausgabe:
```
[+] Building 0.0s (0/0)
Attaching to apache
apache | httpd: Could not open configuration file /usr/local/apache2/conf/httpd.conf: No such file or directory
apache exited with code 0
```
Das hat also schon mal so gar nicht geklappt. Woran kann es liegen? Zur Analyse interaktiv in dem Container agieren:
```bash
docker compose run -it --entrypoint /bin/bash apache
```
Ich kann im Container sehen, dass die Konfigurations-Dateien vorhanden sind, d.h. die Docker-Compose-Konfig ist an der Stelle korrekt.
Allerdings fehlt die geforderte httpd.conf.
Bei Ubuntu heißt die Datei apache2.conf, der Docker Container erwartet aber eine httpd.conf. Als Workaround lege ich eine ```httpd.conf```an, die auf die apache2.conf verweist:
```bash
Include /usr/local/apache2/conf/apache2.conf
```

Jetzt bekomme ich beim Starten des Containers andere Fehlermeldungen.

## Aufräumen
Das entwickelt sich nicht wie gewünscht, ich breche ab und räume auf:
```bash
docker compose down -v
sudo rm -rf /data/docker/apache
```

# Kleiner Apache
Um einen minimalen Teilerfolg feiern zu können, setzte ich einen Apache im Container auf, der die HTML-Seiten auf Port 9080 ausliefert.

```bash
mkdir /data/docker/apache
mkdir /data/docker/apache/logs

cd /data/docker/apache
vim docker-compose.yml

docker compose up -d
docker logs apache
```

```yaml
services:
apache:
image: httpd:2.4
container_name: apache
restart: always
ports:
- 9080:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /var/www/html:/usr/local/apache2/htdocs
- ./logs:/usr/local/apache2/logs
```

# Fazit
Der naive "Lift and Shift" Ansatz hat mal wieder nicht funktioniert.
Die Pfade sind bei der nativen Ubuntu Installation und dem Container Apache unterschiedlich. Der simple Workaround mit der httpd.conf-Datei war ein erster Schritt, danach hätten noch Umgebungsvariablen wie ```APACHE_RUN_DIR``` gesetzt werden müssen.
Dann hätte ich noch einige Pfade vom Server in den Container mappen müssen.
Und dann ist da noch der Let's encrypt Certbot, der doch mehr mit der Apache Installation verdrahtet ist, als ich am Anfang dachte. Den hätte ich auch noch im Container installieren müssen.
Sicherlich alles machbar, aber für eine Interimslösung zu aufwändig. Am Ende soll ja Traefik SSL und Reverse Proxy übernehmen. Daher belasse ich es hier erstmal.

Categories
AI

Accessing LM Studio Server from WSL Linux

## Problem

When using LM Studio on Windows 11, accessing the server from WSL (Windows Subsystem for Linux) is not straightforward, even though the server is accessible locally. This issue occurs because LM Studio defaults to starting the server on `127.0.0.1` (localhost), which makes it accessible only to applications running directly on the Windows host. Requests from WSL or other hosts (e.g., using the Windows IP address) are blocked.

While LM Studio's interface allows configuring the port, it does not provide an option to modify the network interface (`networkInterface`) the server listens on.

## Solution

To make the server accessible from WSL, the network interface must be changed from `127.0.0.1` to `0.0.0.0`, allowing the server to listen on all network interfaces.

### Steps to Resolve:

1. **Start LM Studio:** Open LM Studio and ensure the server is running as usual.

2. **Edit the Configuration File:**
- Navigate to the directory containing the internal configuration file:
```
%userprofile%\.cache\lm-studio\.internal
```
- Open the file `http-server-config.json` in a text editor.

3. **Modify the Entry:**
- Locate the `"networkInterface"` entry and change its value from `"127.0.0.1"` to `"0.0.0.0"`.
- Example:
```json
{
"networkInterface": "0.0.0.0",
"port": 1234
}
```

4. **Restart LM Studio Server:** Stop and restart LM Studio Server in Developer Tab for the changes to take effect.

5. **Test the Access:**
- Determine the local IP address of the Windows host (e.g., using `ipconfig`).
- Test the server access from WSL with the following command:
```bash
curl http://<windows-ip>:1234/v1/models
```
- The server should now be accessible.

## Note

Changing the network interface to `0.0.0.0` theoretically makes the server accessible to other devices on the network. If this is not desirable, ensure that the Windows Firewall restricts access to localhost or specific IP ranges.

## Conclusion

By modifying the `http-server-config.json` file, the LM Studio server can be accessed from WSL Linux. This solution is simple and effective for integrating local development environments into hybrid workflows.

Categories
Linux

Lokaler virtueller Server

## Motivation
Ich habe schon seit langer Zeit einen virtuellen Server gemietet, auf dem ich verschiedene Dienste, wie zB Webseite und Mail, laufen lasse. Die Anwendungen laufen direkt auf dem Server und ich will sie schon seit langem in Container stecken. Das Betriebssystem ist mit Ubuntu 18.04 LTS hoffnungslos veraltet, aktuell ist 24.04 LTS.
Ein Upgrade von Ubuntu 18 auf 24 ist mit Risiko und vermutlich hohem Aufwand verbunden, da erfahrungsgemäß irgendetwas irgendwie anders funktioniert und mühevoll angepasst werden muss. Grade bei einer Upgradekette 18->20->22->24 kann so einiges schief gehen.
Den Server miete ich seit ein paar Jahren und inzwischen gibt es für das gleiche Geld bessere (virtuelle) Hardware.
Aus diesen Gründen plane ich, einen neuen virtuellen Server zu mieten und auf diesen umzuziehen.

## Wie es auf dem Neuen laufen soll
Auf dem neuen Server soll Ubuntu 24.04 LTS laufen.
Auf dem Linux System soll Docker installiert werden.
Die Docker Container sollen mit Portainer verwaltet werden.
Die Webseite der Portainer Verwaltung und die weiteren Dienste sollen über einen Reverse Proxy, beispielsweise Traefik, erreichbar sein.
Der Reverse Proxy soll den Zugriff ausschließlich verschlüsselt über HTTPS erlauben und entsprechend konfiguriert sein.
Das HTTPS Zertifikat soll von [Let's Encrypt](https://letsencrypt.org/) kommen.

## lokaler virtueller Server
Zuerst möchte ich einen lokalen virtuellen Server einrichten um auf diesem die Migration vorbereiten zu können. Dazu werde ich [Virtual Box](https://www.virtualbox.org/) von Oracle verwenden.

graph TD G[Portainer Webinterface] --> F H[Website: Nginx] --> F I[Mailserver: Postfix/Dovecot] --> F F[Traefik] --> E E[Portainer] --> D D[Docker] --> C C[Ubuntu 24.04 LTS] --> B B[VirtualBox] --> A A[Host System: PC]

Vom Host System (also mein PC, auf dem Virtual Box läuft) aus soll der Zugriff auf die Webseite per Domain Name funktionieren, nicht nur über die IP. Idealerweise sollte die Verschlüsselung mit Let's Encrypt vorgenommen werden, um so realistisch wie möglich das spätere System vorzubauen.
Leider ist das nicht (mit vertretbarem Aufwand) möglich, daher werde ich alles ohne HTTPS aufsetzen.

### virtuellen Server aufsetzen
1. Oracle VirtualBox installieren
2. Neue virtuelle Maschine erzeugen
* 8 GB RAM
* 4 CPUs
* ISO: [Ubuntu 24.04.1 LTS](https://ubuntu.com/download/server)
* Unbeaufsichtigte Installation:
* Benutzername und Passwort
* Hostname: kaulbach
* Domain Name: local
3. In den Netzwerkadapter-Einstellungen der virtuellen Maschine auf "Bridged Adapter" (Brückenadapter) umstellen
4. nach der Installation einloggen und mittels ```ip a``` die IP-Adresse der VM identifizieren (192.168.178.47)
5. Auf dem Host System in der Datei ```C:\Windows\System32\drivers\etc\hosts``` hinzufügen:
192.168.178.47 kaulbach.local
192.168.178.47 traefik.kaulbach.local
192.168.178.47 portainer.kaulbach.local
6. Test auf dem Host System:
* ping 192.168.178.47
* ping kaulbach.local

### virtuellen Server einrichten
```bash
sudo apt update
sudo apt upgrade -y

# Spracheinstellungen ändern
sudo locale-gen de_DE.UTF-8
sudo update-locale LANG=de_DE.UTF-8

# Tastaturbelegung ändern
sudo dpkg-reconfigure keyboard-configuration

# Zeitzone festlegen
sudo timedatectl set-timezone Europe/Berlin

# SSH Server installieren
sudo apt install -y openssh-server
sudo systemctl start ssh
sudo systemctl enable ssh
```

## Installation von Docker, Traefik, Portainer

### 1. Docker installieren
1. **Paketliste aktualisieren**:
```bash
sudo apt update
sudo apt upgrade -y
```

2. **Abhängigkeiten installieren**:
```bash
sudo apt install -y ca-certificates curl gnupg
```

3. **Docker-Repository hinzufügen**:
```bash
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
```

4. **Docker installieren**:
```bash
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
```

5. **Docker-Dienst aktivieren**:
```bash
sudo systemctl enable docker
sudo systemctl start docker
```

6. **Rechte für den aktuellen Benutzer konfigurieren**:
```bash
sudo usermod -aG docker $USER
newgrp docker
```

### 2. Docker Compose installieren
Docker Compose ist bei neueren Docker-Versionen bereits als Plugin enthalten. Es kann direkt über den Docker-CLI-Befehl `docker compose` genutzt werden.

**Installation testen**:
```bash
docker compose version
```

### 3.0 Traefik Netzwerk anlegen
Alle mit dem Traefik Dienst verbundenen Container sollen im selben Netzwerk liegen:
```bash
docker network create traefik-net
```

### 3. Traefik installieren
1. **Arbeitsverzeichnis erstellen**:
```bash
mkdir ~/traefik && cd ~/traefik
```

2. **`docker-compose.yml` für Traefik erstellen**:
```bash
vim docker-compose.yml
```
Inhalt:
```yaml
services:
traefik:
image: traefik:v3.2
container_name: traefik
restart: always
ports:
- "80:80"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./traefik.yml:/etc/traefik/traefik.yml:ro"
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`traefik.kaulbach.local`)"
- "traefik.http.routers.traefik.entrypoints=web"
- "traefik.http.services.traefik.loadbalancer.server.port=8080"

networks:
default:
name: traefik-net
external: true
```

3. **Traefik-Konfigurationsdatei erstellen**:
```bash
vim traefik.yml
```
Inhalt:
```yaml
entryPoints:
web:
address: ":80"

providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false

api:
dashboard: true
insecure: true
```

4. **Container starten**:
```bash
docker compose up -d
# Log Files checken
docker logs traefik
```

5. **Subdomain eintragen**
Auf dem Host System in der Datei ```C:\Windows\System32\drivers\etc\hosts``` den Eintrag für die Subdomain "traefik.kaulbach.local" hinzufügen:
192.168.178.47 traefik.kaulbach.local

6. **Dashboard aufrufen**:
Das Traefik-Dashboard ist unter `http://traefik.kaulbach.local` erreichbar.

### 4. Webserver installieren
1. **Arbeitsverzeichnis erstellen**:
```bash
mkdir ~/web && cd ~/web
```

2. **Beispielseite erstellen**:
```bash
mkdir ~/web/html
echo "<h1>Hello, World! (c) DerIngo</h1>" > ~/web/html/index.html
```

3. **`docker-compose.yml` für den Webserver erstellen**:
```bash
vim docker-compose.yml
```
Inhalt:
```yaml
services:
nginx:
image: nginx
container_name: nginx
restart: always
labels:
- "traefik.enable=true"
- "traefik.http.routers.nginx.rule=Host(`kaulbach.local`)"
- "traefik.http.routers.nginx.entrypoints=web"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./html:/usr/share/nginx/html:ro"

networks:
default:
name: traefik-net
external: true
```

4. **Traefik-Labels nutzen**:
- Die Labels im obigen Beispiel sorgen dafür, dass Traefik den Webserver unter `http://kaulbach.local` bereitstellt.

5. **Container starten**:
```bash
docker compose up -d
# Log Files checken
docker logs web
```

6. **Webseite aufrufen**:
Die Webseite ist unter `http://kaulbach.local` erreichbar.

### 5. Portainer installieren
1. **Arbeitsverzeichnis erstellen**:
```bash
mkdir ~/portainer && cd ~/portainer
```

2. **`docker-compose.yml` für Portainer erstellen**:
```bash
vim docker-compose.yml
```
Inhalt:
```yaml
services:
portainer:
image: portainer/portainer-ce:latest
container_name: portainer
restart: always
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./data:/data"
labels:
- "traefik.enable=true"
- "traefik.http.routers.portainer.rule=Host(`portainer.kaulbach.local`)"
- "traefik.http.routers.portainer.entrypoints=web"
- "traefik.http.services.portainer.loadbalancer.server.port=9000"

networks:
default:
name: traefik-net
external: true
```

3. **Traefik-Labels nutzen**:
- Die Labels im obigen Beispiel sorgen dafür, dass Traefik das Portainer Dashboard unter `http://portainer.kaulbach.local` bereitstellt.

4. **Container starten**:
```bash
docker compose up -d
# Log Files checken
docker logs portainer
```

5. **Subdomain eintragen**
Auf dem Host System in der Datei ```C:\Windows\System32\drivers\etc\hosts``` den Eintrag für die Subdomain "portainer.kaulbach.local" hinzufügen:
192.168.178.47 portainer.kaulbach.local

6. **Dashboard aufrufen**:
Das Traefik-Dashboard ist unter `http://portainer.kaulbach.local` erreichbar.

7. **Portainer konfigurieren**
* Passwort für den User "admin" festlegen: "adminpassword".
* Environment "local" ist bereits angelegt

### 6. ein weiterer Webserver
1. **Webserver anlegen und starten**:
```bash
mkdir -p ~/web2/html
echo "<h1>Hello vom geheimnisvollen 2. Server</h1>" > ~/web2/html/index.html
touch ~/web2/docker-compose.yml # mit Inhalt s.u. befüllen
cd ~/web2
docker compose up -d
```

2. **`docker-compose.yml` für den Webserver erstellen**:
```yaml
services:
nginx:
image: nginx
container_name: nginx2
restart: always
labels:
- "traefik.enable=true"
- "traefik.http.routers.nginx2.rule=PathPrefix(`/derzweite`)"
- "traefik.http.routers.nginx2.entrypoints=web"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./html:/usr/share/nginx/html:ro"

networks:
default:
name: traefik-net
external: true
```

3. **`docker-compose.yml` des ersten Webservers anpassen**:
Der Router des ersten Webservers mit dem Host(`kaulbach.local`) wird auch auf /derzweite matchen.
Daher müssen wir die Regel für den Router des ersten Servers anpassen:
```- "traefik.http.routers.nginx.rule=PathPrefix(`/`) && !PathPrefix(`/derzweite`)"```

4. **Webseite aufrufen**:
Die Webseite ist unter `http://kaulbach.local/derzweite` erreichbar.

## Abschluß
Das Fundament ist gelegt, darauf aufbauend kann ich die Migration der einzelnen Anwendungen erarbeiten.
Der Code-Editor, bzw. die Anzeige des Codes, des "Markup Markdown"-Editors ist ziehmlich kaputt. Und das was man sieht, sieht hässlich aus. Ich habe auch schon ein Ticket erstellt, ob und wie man andere Code-Editoren wie CodeMirror Blocks einbinden kann.
Die Dateien habe ich in [GitHub](https://github.com/DerIngo/localvirtualserver) eingecheckt.

Categories
AI Development

LoRA von meinem Gesicht

Ich arbeite mich grade durch einen Kurs "ChatGPT, Machine learning, DeepLearning, Neuronale Netze, OpenAI API, GPTs, Assistant API, Gemini, LLMs u. deine Modelle" auf [Udemy Business](https://quinscape.udemy.com/course/ki-komplett-erstelle-eigene-modelle-apps-mit-gpts-mehr) durch und einen Abschnitt wollte ich mir nicht nur anhören, sondern auch nach arbeiten.
Es geht um den Abschnitt "67. Der einfachste & schnellste Weg zu deinem Lora & Bilder mit deinem Gesicht" und das Video ist nur 10 Minuten lang.
Es hörte sich so einfach an: Ein paar Selfies aufnehmen, zurechtschneiden und ein Jupyter Notebook auf Google Colab ausführen. Fertig ist das LoRA des eigenen Gesichts.

#### Was ist ein LoRA?

LoRAs (Low-Rank Adaptations) sind kleinere Modelle, die man mit bestehenden Stable Diffusion Modellen kombinieren kannst. Sie erlauben es ein Bestehendes Modell «fine zu tunen». So kann man neue "Konzepte", wie mein Gesicht, den generierten Bildern hinzufügen.

#### Selfies machen

Zuerst also ein paar Selfies aufnehmen, dabei darauf achten, dass im Hintergrund nicht zu viele Gegenstände ablenken, ich wählte eine weiße Wand und ein paar nahm ich noch vor einem schwarzen Hintergrund auf.
Zum Trainieren an den Daten müssen die Bilder auf das Format 512x512 Pixel zurechtgeschnitten werden.
Da war auch schon das erste Problem: Die Bilder meines iPhones legen im HEIC-Format vor:

#### Was eine HEIC-Datei ist
Die Abkürzung ist auch als HEIF bekannt und steht für High Efficiency Image Format.
* Es handelt sich dabei um ein Bild-Format zum platzsparenden Speichern von Bildern auf Mobil-Geräten.
* iOS-Geräte speichern Bilder in HEIC-Dateien, auf Android-Geräten finden Sie in der Regel HEIF-Bilder.
* Der Vorteil dieses Bild-Formats ist eine kleine Dateigröße bei JPEG-Qualität oder sogar noch besserer Qualität.

#### Das Problem mit HEIC-Dateien
Es ist ein propritäres Format und kann nicht ohne weiteres verwendet werden.
Ich verwende Windows 11 und konnte die Bilder betrachten, allerdings nicht bearbeiten. Vermutlich hätte ich eine Erweiterung im MS Store kaufen müssen, dann hätte ich es mit Programmen wie [IrfanView](https://www.irfanview.de/) bearbeiten können.
Gelöst habe ich es statt dessen mit einem [Python-Programm](https://github.com/DerIngo/dreambooth/blob/main/convert_heic_to_png.py), dass die Bilder von HEIC nach JPEG umwandelt und auf 512x512 zurecht schneidet.

#### LoRA trainieren
Das Training des LoRAs soll in einem Jupyther Notebook auf Google Colab erfolgen. [Link](https://github.com/ShivamShrirao/diffusers/blob/main/examples/dreambooth)
Leider konnte ich es nicht ausführen, der Python Code funktioniert nicht. Kleinere Anpassungen halfen nicht weiter, daher kopierte ich das Jupyther Notebook und die erforderlichen Scripte in ein eigenes [GitHub Repository](https://github.com/DerIngo/dreambooth) und passte so lange Notebook und Scripte an, bis sie liefen.
Das [Stable Diffusion DreamBooth Notebook](https://github.com/DerIngo/dreambooth/blob/main/DreamBooth_Stable_Diffusion.ipynb) kann unter diesem [Link](https://colab.research.google.com/github/DerIngo/dreambooth/blob/main/DreamBooth_Stable_Diffusion.ipynb) in Google Colab geöffnet werden.