Categories
Linux

Lokaler virtueller Server

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

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

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

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

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

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

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

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

# Tastaturbelegung ändern
sudo dpkg-reconfigure keyboard-configuration

# Zeitzone festlegen
sudo timedatectl set-timezone Europe/Berlin

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

## Installation von Docker, Traefik, Portainer

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

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

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

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

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

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

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

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

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

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

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

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

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

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

api:
dashboard: true
insecure: true
```

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Categories
Linux

Upgrade Ubuntu 20.04 to 22.04 on WSL

Check current version:

lsb_release -a

Make 20.04 installation is up-to-date:

sudo apt update && sudo apt full-upgrade

Close Ubuntu on WSL terminal, and open PowerShell terminal:

wsl -l -v 
## Confirm the distribution name and adjust below if needed
wsl --terminate Ubuntu

Open new Ubuntu on WSL terminal:

sudo do-release-upgrade
##
sudo apt update && sudo apt upgrade -y
sudo apt autoremove

Check current version:

lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.3 LTS
Release:        22.04
Codename:       jammy

Categories
Development Linux

Dart Sass WSL

Install Sass on WSL

Install Dart Sass instead of Ruby Sass on WSL.

I am following this instructions: https://www.geeksforgeeks.org/how-to-install-dart-sass-in-linux/

At the end it was supereasy with previousliy installed Node Package Manager (npm):

# install sass with npm
npm i -g sass

# check version
sass --version
1.55.0 compiled with dart2js 2.18.1

Sass

Homepage

Latest Sass Release on GitHub

Categories
Development Linux

Docker Compose und Ubuntu 18

Docker Compose Datei vom Entwicklungsrechner auf den Server kopieren, kleinere Anpassungen vornehmen und ausführen. So einfach habe ich es mir vorgestellt, aber es gab dann leider doch noch Herausforderungen zu bewältigen:

Docker Compose Updaten

Ich habe einen Server mit dem nicht mehr ganz taufrischen Ubuntu 18 am laufen und wollte dort ein Docker Compose Skript ausführen.

Das Skript läuft auf meinem Entwicklungsrechner, aber auf dem Server wurde lediglich eine Fehlermeldung ausgegeben:

dockeruser@myServer:~/myproject$ docker-compose up
ERROR: Version in "./docker-compose.yml" is unsupported. You might be seeing this error because you're using the wrong Compose file version. Either specify a supported version (e.g "2.2" or "3.3") and place your service definitions under the `services` key, or omit the `version` key and place your service definitions at the root of the file to use version 1.
For more on the Compose file format versions, see https://docs.docker.com/compose/compose-file/

Wie sich herausstellte, war für Ubuntu 18 bei Docker Compose 1.17.1 Schluss und ich muss händisch upgraden:

Docker Compose entfernen:

sudo apt-get remove docker-compose

Die aktuelle Docker Compose Version ermitteln (heute: 2.2.3): https://github.com/docker/compose/releases

Auf dieser Seite kann man auch den direkten Link zum Download finden, falls es beim ausführen des nächsten Befehls zu Problemen kommt.

Beispielsweise ist die Versionsnummer v2.2.3, also mit einem kleinen "v" am Anfang und wenn das fehlt, schlägt der Download fehl.

So lautet der Link für mein Ubuntu:
https://github.com/docker/compose/releases/download/v2.2.3/docker-compose-linux-x86_64

Der Befehl zum Download:

sudo curl -L https://github.com/docker/compose/releases/download/v2.2.3/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

Rechte setzen:

sudo chmod +x /usr/local/bin/docker-compose

Installation und Version checken:

docker-compose --version
# Output:
Docker Compose version v2.2.3

Docker Compose ohne GUI

Mit der neuesten Docker Compose Version gibt es einen neuen Fehler:

error getting credentials - err: exit status 1, out: `Cannot autolaunch D-Bus without X11 $DISPLAY`

Die Erklärung lautet:

Looks like this is because it defaults to use the secretservice executable which seems to have some sort of X11 dependency for some reason. If you install and configure pass docker will use that instead which seems to solve the problem.

Zu erst muss die aktuelle Version des Docker Credential Helpers ermittelt werden: v0.6.4

Install the Docker Credential Helper for pass:

# substitute with the latest version
url=https://github.com/docker/docker-credential-helpers/releases/download/v0.6.4/docker-credential-pass-v0.6.4-amd64.tar.gz

# download and untar the binary
wget $url
tar -xzvf $(basename $url)

# move the binary to a dir in your $PATH
sudo mv docker-credential-pass /usr/local/bin

# verify it works
docker-credential-pass list

# cleanup
rm docker-credential-pass-v0.6.4-amd64.tar.gz

Install and configure pass:

sudo apt install pass

# create a gpg2 key
gpg2 --gen-key

Und der nächste Fehler:

gpg: agent_genkey failed: Keine Berechtigung
Schlüsselerzeugung fehlgeschlagen: Keine Berechtigung

Und eine Erklärung mit Lösungsvorschlag findet sich hier:

Expected behavior. Here's why.
At the point of failure, gen-key is about to ask the user for a passphrase. For security purposes, rather than using stdin/stdout, it wants to directly open the controlling terminal for the session and use that handle to write the prompt and receive the passphrase. When you use su to switch to some other user, the owner of the controlling terminal device file does not change; it remains associated with the user who actually logged in (i.e. received a real terminal from getty or got a pty from telnet or ssh or whatever). That device file is protected mode 600, so it can't be opened by anyone else.

The solution is to sudo-chown the device file to the user-who-needs-to-gen-the-key before su'ing to that user. Create the key within the su'd environment, then exit back to the original environment. Then, finally, sudo-chown the terminal back to yourself.

Glücklicherweise geht es auch einfacher, indem man einfach das Programm tmux verwendet. 🙂

tmux

# create a gpg2 key
gpg2 --gen-key

# list key information
gpg2 -k

# Copy the key id (from the line labelled [uid]) and do
pass init "whatever key id you have"

Jetzt sollte der Docker Login funktionieren, aber:

docker login
# Output:
Error saving credentials: error storing credentials - err: fork/exec /usr/local/bin/docker-credential-pass: permission denied, out: ``

Auch wieder kein neues Problem, dass zB bereits hier und hier diskutiert wurde.

mkdir ~/.docker
touch ~/.docker/config.json
# brachte jeweils keine Änderung


/usr/local/bin/docker-credential-pass
# Output:
-bash: /usr/local/bin/docker-credential-pass: Keine Berechtigung


# Erfolg kam mit diesem Befehl:
sudo chmod +x /usr/local/bin/docker-credential-pass

#Zumindest funktioniert dieser Aufruf:
docker-credential-pass list


# Ein weiterer Fehler ließ sich beheben durch:
export GPG_TTY=$(tty)

Ich musste die einzelnen Images per docker pull imagename ziehen, erst danach konnte ich docker-compose ausführen.