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.
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. jqzum 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.

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 IPscompute: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:
umask 077
cat > ~/.eos.env <<'EOF'
export EOS_CLIENT_ID=DEINE_CLIENT_ID
export EOS_CLIENT_SECRET=DEIN_CLIENT_SECRET
EOFumask 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:
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/nullDann die Paketquelle eintragen und das Paket installieren:
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 eosctlSigned-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:
source ~/.eos.env
eosctl loginClient 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:
export NO_COLOR=1
eosctl compute vm image list -o json | jq -r '.[].name'Alpine Edge
Alpine Edge Cloud
Arch Linux
Arch Linux Cloud
Debian 13
Debian 13 Cloud
Ubuntu 26.04
Ubuntu 26.04 CloudDie Produkte zeigen, was die Oberfläche verschweigt:
eosctl compute product list -o json \
| jq -r '.[] | select(.kind=="vm") | [.name, .active, .product_data.cpu_count, .product_data.ram_size] | @tsv'vServer Mini true 1 2048
vServer Small true 2 4096
vServer Medium true 4 8192
vServer Large false 8 16384Eine 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:
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.
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:
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:
until [ "$(eosctl compute vm get "$vm_id" -o template -t '{{.agent_ready}}')" = "true" ]; do
sleep 3
done5. 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:
eosctl compute vm exec "$vm_id" "bash -c \"hostname; whoami\""cli-demo
rootDie 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:
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:
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:
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 versionOpenTofu v1.13.1Den 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:
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:
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:
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:
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:
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:
source ~/.eos.env
tofu init- 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:
tofu plan -var meine_ip=DEINE_IPPlan: 6 to add, 0 to change, 0 to destroy.Sieht der Plan richtig aus, baust du auf:
tofu apply -var meine_ip=DEINE_IPNach der Rückfrage (yes) legt OpenTofu die Ressourcen in der richtigen Reihenfolge an:
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:
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:
destination_ports = ["22", "80"]tofu apply -var meine_ip=DEINE_IP # 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:
tofu destroy -var meine_ip=DEINE_IPDestroy 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.tfstateenthä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 inuser_datalandet 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 -upgradeholt die neueste erlaubte Version. Solange der Provider unter 1.0 ist, lies vor jedem Sprung auf eine neue Unterversion die Änderungen und prüfe mittofu plan, dass nichts unerwartet ersetzt wird. eosctlmit apt aktuell halten. Es kommt mitapt upgrade. Weil die Dokumentation hinterherläuft, isteosctl <befehl> --helpdie verlässlichere Quelle.- Abräumen nicht vergessen. Abgerechnet wird minutengenau, und eine öffentliche IP kostet
auch ohne VM.
tofu destroyerwischt alles, was in der Datei steht – Ressourcen aus der Konsole oder pereosctlmusst 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.
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.
💶 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
Feedback per E-Mail: feedback@serverkueche.de
Das könnte dir auch schmecken

Wann reicht der kleine Server nicht mehr?

100 Tage netcup: was dir vorher niemand sagt
