Zum Inhalt springen
Serverküche
Suche

Die Suche wird geladen …

netcup Schwierigkeit: Fortgeschritten

netcup eos automatisieren: eosctl und OpenTofu

netcup eos ohne Klicks: Client Credentials mit knappen Rechten, VMs per eosctl und ein komplettes Setup aus Netz, ACL und VM mit OpenTofu.

· Zuletzt aktualisiert: · 13 Min. Lesezeit ·Dauer: ca. 30 Minuten
Inhaltsverzeichnis

eos ist für Leute gebaut, die Server nicht per Klick anlegen wollen. Im zweiten Teil steuern wir netcups neue Cloud deshalb von der Kommandozeile – erst mit dem Werkzeug eosctl, dann mit OpenTofu als Infrastruktur-als-Code. Die Konsole brauchst du nur noch für den Zugang selbst.

Wie im ersten Teil gilt: Das ist der Stand der Preview, die netcup am 13. November 2026 abbaut. Öffentlich startet eos 2027. Schon vorher, noch 2026, kann jeder netcup-Kunde die Plattform im Friends-&-Family-Launch kostenlos nutzen, auf produktiver Hardware und ohne späteren Reset. Befehle und Provider sind noch vor Version 1.0 und können sich ändern.

Was bauen wir?

Wir legen einen Zugang für Programme an, der nur Netze und VMs verwalten darf. Mit eosctl erzeugen wir eine VM, führen darin einen Befehl aus und löschen sie wieder. Danach beschreiben wir ein vollständiges Setup in einer OpenTofu-Datei: eigenes Netz, Firewall-Regel, Debian-VM mit Cloud-Init und öffentlicher IPv4. Ein tofu apply baut alles in unter einer Minute auf, ein tofu destroy räumt es genauso schnell wieder ab.

Eingesetzt werden eosctl 0.16.0, OpenTofu 1.13.1 und der eos-Provider 0.10.1. OpenTofu ist der quelloffene Ableger von Terraform und versteht dieselbe Konfigurationssprache.

Voraussetzungen

  • Ein Zugang zu eos und Grundkenntnisse der Konsole – Organisation, Realm, ACL und öffentliche IP erklärt netcup eos in der Preview.
  • Ein Rechner mit Debian 13 für die Werkzeuge. Das kann dein Laptop sein oder ein kleiner Server; wir haben eine eos-VM dafür genommen.
  • Ein SSH-Schlüssel (ssh-keygen -t ed25519), siehe SSH absichern.
  • jq zum Auswerten von JSON: sudo apt install jq.

Schritt für Schritt

1. Client Credentials mit knappen Rechten

Programme melden sich bei eos nicht mit deinem Konto an, sondern mit Client Credentials – einer Client-ID und einem Secret. Du legst sie in der Konsole unter Realms → dein Realm → Client Credentials → Create credential an. Die Seite beschreibt sie als „organization level“; angelegt werden sie trotzdem für den Realm, in dem du gerade bist.

Der Dialog für neue Client Credentials mit Name, Ablaufdatum und den Rollen Network Manager und VM Manager
Client Credentials: Basisrecht ist Lesen, alles Weitere kommt als Rolle dazu

Jeder Zugang darf grundsätzlich alles lesen. Schreibrechte kommen als Rollen dazu: Compute Network Manager, VM Manager, Volume Manager, Object Storage Manager und Realm Admin. Für dieses Tutorial genügen zwei:

  • compute:network-manager – Netze, ACLs und öffentliche IPs
  • compute:vm-manager – VMs anlegen, schalten, löschen

Setze außerdem ein Ablaufdatum. Ein Zugang für Experimente braucht keine Laufzeit von einem Jahr, und ein vergessener Schlüssel verfällt dann von selbst.

Nach dem Speichern zeigt eos das Secret genau einmal. Kopiere beides sofort in eine Datei, die nur du lesen darfst:

Terminal
umask 077
cat > ~/.eos.env <<'EOF'
export EOS_CLIENT_ID=DEINE_CLIENT_ID
export EOS_CLIENT_SECRET=DEIN_CLIENT_SECRET
EOF

umask 077 sorgt dafür, dass die Datei mit den Rechten 600 entsteht. Sowohl eosctl als auch der OpenTofu-Provider lesen genau diese beiden Variablen – das Secret muss also nie in einer Konfigurationsdatei stehen.

2. eosctl installieren

netcup bietet eosctl als Debian-Paket aus einem eigenen Repository an. Zuerst den Signaturschlüssel holen, damit apt nur Pakete akzeptiert, die netcup signiert hat:

Terminal
sudo apt-get install -y ca-certificates curl
curl -sSL https://dl.eoscloud.io/debian.gpg | sudo tee /usr/share/keyrings/eoscloud-public.gpg > /dev/null

Dann die Paketquelle eintragen und das Paket installieren:

Terminal
sudo tee /etc/apt/sources.list.d/eos.sources > /dev/null <<'EOF'
Types: deb
URIs: https://dl.eoscloud.io/debian
Suites: trixie
Components: main
Signed-By: /usr/share/keyrings/eoscloud-public.gpg
EOF
sudo apt-get update && sudo apt-get install -y eosctl

Signed-By bindet den Schlüssel nur an diese eine Quelle – er gilt nicht für Debians eigene Pakete. Updates kommen künftig mit apt upgrade. Die eos-Dokumentation nannte zu diesem Zeitpunkt noch Version 0.12.1, das Repository lieferte bereits 0.16.0.

3. Anmelden und die Ausgabe zähmen

Lade die Zugangsdaten und melde dich an:

Terminal
source ~/.eos.env
eosctl login
Ausgabe
Client credentials flow is configured. To logout, run: 'eosctl logout'

WARNING: storing token insecure in file.
Consider installing keyring software like gnome-keyring if possible.

Die Warnung kommt auf jedem Server ohne Schlüsselbund: eosctl legt das Zugriffstoken als Datei in deinem Home-Verzeichnis ab. Auf einem Rechner, den nur du nutzt, ist das in Ordnung; auf einem geteilten System meldest du dich nach der Arbeit mit eosctl logout ab.

Standardmäßig gibt eosctl bunte Tabellen aus. Für Skripte gibt es -o json, -o yaml und -o template; die Farben schaltest du mit NO_COLOR=1 ab. So listest du die verfügbaren Images:

Terminal
export NO_COLOR=1
eosctl compute vm image list -o json | jq -r '.[].name'
Ausgabe
Alpine Edge
Alpine Edge Cloud
Arch Linux
Arch Linux Cloud
Debian 13
Debian 13 Cloud
Ubuntu 26.04
Ubuntu 26.04 Cloud

Die Produkte zeigen, was die Oberfläche verschweigt:

Terminal
eosctl compute product list -o json \
  | jq -r '.[] | select(.kind=="vm") | [.name, .active, .product_data.cpu_count, .product_data.ram_size] | @tsv'
Ausgabe
vServer Mini	true	1	2048
vServer Small	true	2	4096
vServer Medium	true	4	8192
vServer Large	false	8	16384

Eine vierte Größe mit 8 Kernen und 16 GB ist also schon angelegt, nur noch nicht freigeschaltet. Ebenso kennt die API einen zweiten Block (at-preview1-db) neben dem aus der Konsole.

4. Eine VM per eosctl anlegen

Eine VM braucht vier IDs: Block, Produkt, Image und Netz. Statt sie abzuschreiben, holst du sie per jq anhand des Namens:

Terminal
block_id=$(eosctl compute block list -o json | jq -r '.[] | select(.name=="at-preview1-da") | .id')
product_id=$(eosctl compute product list -o json | jq -r '.[] | select(.name=="vServer Mini") | .id')
image_id=$(eosctl compute vm image list -o json | jq -r '.[] | select(.name=="Debian 13 Cloud") | .id')
network_id=$(eosctl compute network list -o json | jq -r '.[0].id')

.[0] nimmt das erste Netz im Realm – hast du mehrere, wähle es wie die anderen per Name aus. Als Cloud-Init-Datei nimmst du die user-data.yaml aus dem ersten Teil: Sie legt einen Benutzer mit deinem Schlüssel an und installiert den SSH-Server, der den Cloud-Images fehlt.

Terminal
vm_id=$(eosctl compute vm create \
  -B "$block_id" -P "$product_id" -I "$image_id" -N "$network_id" \
  -S 10000 --name cli-demo \
  -U "$(cat user-data.yaml)" \
  -o template -t '{{.id}}')
echo "$vm_id"

-S ist die Plattengröße in Megabyte, 10000 also 10 GB – das Minimum. -U erwartet den Inhalt der Datei, nicht ihren Pfad. Mit -o template -t '{{.id}}' gibt der Befehl nur die ID der neuen VM aus, die du gleich weiterverwendest.

Ob sie läuft, fragst du mit demselben Template-Trick ab:

Terminal
until [ "$(eosctl compute vm get "$vm_id" -o template -t '{{.power_state}}')" = "started" ]; do
  sleep 3
done
echo "läuft"

Nach gut 20 Sekunden war die VM gestartet. started heißt aber nur, dass sie läuft. Für den nächsten Schritt muss zusätzlich der Agent in der VM bereit sein, und das dauert noch etwa eine halbe Minute:

Terminal
until [ "$(eosctl compute vm get "$vm_id" -o template -t '{{.agent_ready}}')" = "true" ]; do
  sleep 3
done

5. Befehle in der VM ausführen

eosctl compute vm exec führt einen Befehl direkt in der VM aus, ohne SSH, ohne öffentliche IP und ohne ACL-Regel. Mehrere Befehle verpackst du in bash -c:

Terminal
eosctl compute vm exec "$vm_id" "bash -c \"hostname; whoami\""
Ausgabe
cli-demo
root

Die inneren Anführungszeichen müssen maskierte doppelte sein (\"). Mit einfachen kam nur die Ausgabe des ersten Befehls zurück.

Der Befehl läuft als root. Das ist dieselbe Hintertür wie die Web-Konsole aus dem ersten Teil, nur skriptbar – und der Grund, warum der Zugang mit der Rolle vm-manager so sorgfältig verwahrt werden muss wie ein Root-Passwort.

6. VM löschen: erst ausschalten

Der naheliegende Befehl tut bei einer laufenden VM nichts:

Terminal
eosctl compute vm delete "$vm_id"

Es kommt keine Fehlermeldung, und die VM läuft einfach weiter. eos löscht nur ausgeschaltete VMs. Die richtige Reihenfolge ist also ausschalten, warten, löschen:

Terminal
eosctl compute vm power-off "$vm_id"
until [ "$(eosctl compute vm get "$vm_id" -o template -t '{{.power_state}}')" = "stopped" ]; do
  sleep 3
done
eosctl compute vm delete "$vm_id"

Das Root-Volume verschwindet mit der VM. Prüfe mit eosctl compute vm list, dass sie weg ist – in Skripten ist ein stilles Nichtstun gefährlicher als ein Fehler.

7. OpenTofu installieren

Für alles, was über eine einzelne VM hinausgeht, ist eine deklarative Beschreibung bequemer: Du schreibst auf, was existieren soll, und OpenTofu rechnet aus, was dafür anzulegen, zu ändern oder zu löschen ist. OpenTofu gibt es als .deb auf GitHub:

Terminal
curl -sSLo /tmp/tofu.deb https://github.com/opentofu/opentofu/releases/download/v1.13.1/tofu_1.13.1_amd64.deb
sudo apt-get install -y /tmp/tofu.deb && rm /tmp/tofu.deb
tofu version
Ausgabe
OpenTofu v1.13.1

Den eos-Provider musst du nicht installieren – den lädt OpenTofu im nächsten Schritt selbst.

8. Das Setup als Code

Lege ein Verzeichnis an und kopiere die user-data.yaml aus dem ersten Teil hinein:

Terminal
mkdir ~/eos-tf && cd ~/eos-tf
cp ~/user-data.yaml .

Dann die Datei main.tf. Wir gehen sie in Abschnitten durch; zusammen ergeben sie eine Datei. Zuerst Provider und Eingabe:

HCL
terraform {
  required_providers {
    eoscloud = {
      source  = "dl.eoscloud.io/eos/eoscloud"
      version = "~> 0.10.0"
    }
  }
}

# Zugangsdaten kommen aus EOS_CLIENT_ID / EOS_CLIENT_SECRET.
provider "eoscloud" {}

variable "meine_ip" {
  description = "Öffentliche IPv4, von der aus SSH erlaubt ist"
  type        = string
}

Der Provider kommt nicht aus der OpenTofu-Registry, sondern direkt von netcups Server dl.eoscloud.io. ~> 0.10.0 erlaubt Fehlerkorrekturen innerhalb von 0.10, aber keinen Sprung auf 0.11 – vor Version 1.0 darf jede Unterversion Bestehendes umwerfen. Der leere provider-Block ist Absicht: Die Zugangsdaten liest er aus den Umgebungsvariablen.

Statt IDs fest einzutragen, sucht die Konfiguration Block, Größe und Image per Name:

HCL
data "eoscloud_blocks" "alle" {}
data "eoscloud_products" "alle" {}
data "eoscloud_vm_images" "alle" {}

locals {
  block_id   = [for b in data.eoscloud_blocks.alle.blocks : b.id if b.name == "at-preview1-da"][0]
  product_id = [for p in data.eoscloud_products.alle.products : p.id if p.active && p.kind == "vm" && p.name == "vServer Mini"][0]
  image_id   = [for i in data.eoscloud_vm_images.alle.vm_images : i.id if i.name == "Debian 13 Cloud"][0]
}

Jetzt die Firewall und das Netz. Die ACL bekommt eine einzige Regel, SSH von deiner Adresse; alles andere bleibt wie bei eos üblich gesperrt:

HCL
resource "eoscloud_acl" "web" {
  block_id = local.block_id
  name     = "web-acl"
}

resource "eoscloud_acl_rule" "ssh" {
  acl_id            = eoscloud_acl.web.id
  action            = "allow"
  protocol          = "tcp"
  sources           = ["${var.meine_ip}/32"]
  destination_ports = ["22"]
}

resource "eoscloud_network" "web" {
  block_id  = local.block_id
  name      = "web-netz"
  v4_prefix = "10.10.0.0/24"
  acl_ids   = [eoscloud_acl.web.id]
}

Anders als in der Konsole braucht die Regel hier kein Ziel: Sie gilt für das ganze Netz, an das die ACL gehängt ist. Das Netz bekommt einen eigenen privaten Adressbereich.

Zum Schluss VM, öffentliche IP und deren Verknüpfung:

HCL
resource "eoscloud_vm" "web" {
  block_id   = local.block_id
  product_id = local.product_id
  network_id = eoscloud_network.web.id
  image_id   = local.image_id
  name       = "web"
  disk_size  = 10000 # MB
  user_data  = file("${path.module}/user-data.yaml")
}

resource "eoscloud_public_ip" "web" {
  network_id = eoscloud_network.web.id
  ip_family  = 4
}

resource "eoscloud_public_ip_attachment" "web" {
  public_ip_id = eoscloud_public_ip.web.id
  vm_id        = eoscloud_vm.web.id
}

output "oeffentliche_ip" {
  value = eoscloud_public_ip.web.ip
}

IP und Anhängen sind zwei Ressourcen, genau wie die zwei Schritte in der Konsole. So kannst du eine Adresse behalten, während die VM dahinter ausgetauscht wird.

9. init, plan, apply

tofu init lädt den Provider und prüft seine Signatur:

Terminal
source ~/.eos.env
tofu init
Ausgabe
- Installing dl.eoscloud.io/eos/eoscloud v0.10.1...
- Installed dl.eoscloud.io/eos/eoscloud v0.10.1 (signed, key ID 4650503580F8B221)
...
OpenTofu has been successfully initialized!

Dabei entsteht .terraform.lock.hcl mit der exakten Version und ihren Prüfsummen. Diese Datei gehört ins Git-Repository – so bekommt jeder, der das Setup ausrollt, denselben Provider.

Deine öffentliche IPv4 übergibst du als Variable. tofu plan zeigt, was passieren würde, ohne etwas anzulegen:

Terminal
tofu plan -var meine_ip=DEINE_IP
Ausgabe
Plan: 6 to add, 0 to change, 0 to destroy.

Sieht der Plan richtig aus, baust du auf:

Terminal
tofu apply -var meine_ip=DEINE_IP

Nach der Rückfrage (yes) legt OpenTofu die Ressourcen in der richtigen Reihenfolge an:

Ausgabe
eoscloud_acl.web: Creation complete after 6s
eoscloud_acl_rule.ssh: Creation complete after 5s
eoscloud_network.web: Creation complete after 5s
eoscloud_public_ip.web: Creation complete after 5s
eoscloud_vm.web: Creation complete after 20s
eoscloud_public_ip_attachment.web: Creation complete after 6s

Apply complete! Resources: 6 added, 0 changed, 0 destroyed.

Outputs:

oeffentliche_ip = "203.0.113.20"

Rund 40 Sekunden für ein vollständiges Setup. Cloud-Init braucht danach noch etwa eine Minute, um den SSH-Server zu installieren – die ersten Verbindungsversuche laufen deshalb ins Leere. Dann:

Terminal
ssh koch@$(tofu output -raw oeffentliche_ip)

Die VM hat die Adresse 10.10.0.2 aus dem eigenen Netz, und sudo sshd -T bestätigt passwordauthentication no und permitrootlogin no aus der Cloud-Init-Datei.

10. Ändern und abreißen

Ein zweites tofu plan ohne Änderung muss No changes. melden – sonst weicht die Wirklichkeit von deiner Datei ab. Jetzt eine echte Änderung: Port 80 soll zusätzlich offen sein. In main.tf:

HCL
  destination_ports = ["22", "80"]
Terminal
tofu apply -var meine_ip=DEINE_IP
Ausgabe
  # eoscloud_acl_rule.ssh will be updated in-place
...
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.

Die Regel wird an Ort und Stelle geändert, die VM bleibt unberührt – nach 6 Sekunden war das erledigt. Anders bei user_data: Cloud-Init läuft nur beim ersten Start, deshalb ersetzt OpenTofu die VM, sobald du die Datei änderst. Achte im Plan auf must be replaced, bevor du yes tippst.

Zum Abräumen:

Terminal
tofu destroy -var meine_ip=DEINE_IP
Ausgabe
Destroy complete! Resources: 6 destroyed.

Das dauerte knapp eine Minute, den Großteil davon die VM. Anders als eosctl schaltet der Provider sie vor dem Löschen selbst aus.

Wenn es nicht funktioniert

eosctl compute vm delete meldet nichts, die VM läuft weiter. eos löscht nur ausgeschaltete VMs und sagt das nicht. Erst eosctl compute vm power-off, warten bis power_state auf stopped steht, dann löschen (Schritt 6).

exec klappt direkt nach dem Anlegen nicht. started heißt nur, dass die VM läuft. Der Agent, über den exec arbeitet, braucht eine halbe Minute länger – warte, bis agent_ready auf true steht (Schritt 4).

Von mehreren Befehlen kommt nur die erste Ausgabe zurück. Die inneren Anführungszeichen in bash -c sind einfache. Nimm maskierte doppelte, wie in Schritt 5.

OpenTofu bricht beim Anlegen mit einem Berechtigungsfehler ab. Lesen darf jeder Zugang, schreiben nur mit Rolle. Für dieses Setup braucht er compute:network-manager und compute:vm-manager. Prüfe außerdem in der Liste der Client Credentials, ob er abgelaufen ist, und lege notfalls einen neuen an.

tofu init findet den Provider nicht. Die source muss den Hostnamen enthalten: dl.eoscloud.io/eos/eoscloud. Ohne ihn sucht OpenTofu in seiner eigenen Registry, wo der Provider nicht liegt.

Dein Problem ist nicht dabei? Alle Fehlermeldungen durchsuchen →

Wartung & Backups

  • Den State schützen. terraform.tfstate enthält alle IDs, die IP-Adressen und den Inhalt deiner Cloud-Init-Datei im Klartext. Er gehört nicht in ein öffentliches Repository. Für ein Team lohnt ein Remote-Backend, etwa ein S3-Bucket – eos bringt S3 mit; sperr den Zugriff darauf aber genauso ein wie die Zugangsdaten. Geht der State verloren, weiß OpenTofu nicht mehr, was es angelegt hat, und du räumst von Hand auf.
  • Geheimnisse bleiben draußen. Client-ID und Secret stehen in ~/.eos.env, nie in .tf-Dateien. Ein Passwort in user_data landet im State – Cloud-Init-Dateien also nur mit Schlüsseln.
  • Zugänge rotieren. Setze jedem Client-Credential ein Ablaufdatum und lege rechtzeitig einen neuen an. Einer pro Zweck (CI, Laptop, Experimente) lässt sich einzeln widerrufen.
  • Provider-Updates bewusst einspielen. tofu init -upgrade holt die neueste erlaubte Version. Solange der Provider unter 1.0 ist, lies vor jedem Sprung auf eine neue Unterversion die Änderungen und prüfe mit tofu plan, dass nichts unerwartet ersetzt wird.
  • eosctl mit apt aktuell halten. Es kommt mit apt upgrade. Weil die Dokumentation hinterherläuft, ist eosctl <befehl> --help die verlässlichere Quelle.
  • Abräumen nicht vergessen. Abgerechnet wird minutengenau, und eine öffentliche IP kostet auch ohne VM. tofu destroy erwischt alles, was in der Datei steht – Ressourcen aus der Konsole oder per eosctl musst du selbst löschen.

Unser Eindruck: Hier spielt eos seine Stärke aus. Alles, was wir in der Konsole gebraucht haben, geht auch per eosctl und OpenTofu, der Provider ist signiert und ein komplettes Setup steht in unter einer Minute. Die Kanten sind die einer Preview – ein stilles delete, eine Dokumentation, die der Software hinterherläuft. Wer heute schon Server für den Betrieb braucht, nimmt einen netcup-VPS oder Root-Server; wer seine Infrastruktur als Code verwalten will, findet in eos ab dem Friends-&-Family-Launch eine Plattform, die genau dafür gebaut ist.

🍳 Empfehlung Anzeige

VPS 1000 G12.5

4 vCore · 8 GB RAM · 128 GB SSD

ab 14,50 €/Monat

Für den Betrieb heute die sichere Wahl: der klassische netcup-VPS.

Zu netcup →

💶 1 Monat gratis:

Einmal einlösbar, gilt für VPS 1000 G12.5. Im Warenkorb einlösen →

💶 5,95 € Gutschein für netcup-Neukunden: immer gültig · nicht für Domains und VPS Lite

Alle netcup-Gutscheine →

Feedback per E-Mail: feedback@serverkueche.de

Das könnte dir auch schmecken