Webunit

Was ist Webunit

Webunit ist eine schlanke, Docker-basierte Webhosting-Plattform. Sie richtet sich an Agenturen, Reseller und technisch versierte Betreiber, die mehrere Websites, Shops oder Anwendungen auf eigenen Servern hosten wollen — ohne die Komplexitaet, die Sicherheitsbedenken und den Ressourcenhunger klassischer Panels wie Plesk oder cPanel.

Der Grundgedanke

Jede Website (bei uns Subscription genannt) laeuft in ihrem eigenen Container. Das gibt saubere Trennung: eine kompromittierte Site kann keine andere angreifen, PHP-Versionen und Extensions werden pro Sub konfiguriert, und Ressourcen (RAM, CPU) sind pro Container hart begrenzt und weich reserviert (Plesk-Modell). Ausfall einer Site zieht keine andere mit.

Der Kunde bekommt SSH-/SFTP-Zugang zu seinem Container, eine eigene MariaDB und optional phpMyAdmin. Er kann per CLI-Befehlen (z.B. webunit-password ssh, pma-link) selbstaendig Dinge tun, fuer die er sonst ein Ticket schreiben muesste.

Warum ich das entwickelt habe

Ich betreibe seit Jahren Webhosting fuer Kunden. Die grossen Panels sind entweder teuer, ueberladen oder beides — und sie geben mir zu wenig Kontrolle darueber, was auf meinen Servern laeuft. Genauso wichtig war mir das Thema Sicherheit: bei klassischem Shared-Hosting laufen alle Kunden auf demselben System, unter denselben Kernel-Prozessen, mit denselben PHP-Bibliotheken. Eine Sicherheitsluecke in einem Kunden-Skript kann im schlimmsten Fall andere Kunden treffen, jedes Panel-Update ist ein Risiko fuer alle gleichzeitig, und ein einzelner kompromittierter Zugang wird schnell zum Problem fuer die ganze Node.

Webunit ist mein Versuch, mit deutlich weniger Code und weniger Komplexitaet denselben Job zu machen — mit sauberer Container-Isolation pro Kunde als Grundprinzip, und nur den Features drin, die ich tatsaechlich brauche.

Ziele beim Bau:

Was drin ist

Fuer wen es nicht ist

Webunit ist bewusst kein Massen-Panel. Wer ein Klick-und-fertig-Hosting sucht mit Chat-Support und tausend eingebauten One-Click-Installern, ist bei einem anderen Anbieter besser aufgehoben. Wer aber die volle Kontrolle ueber seine Server behalten will, technisch fit ist und lieber Container als PHP-Bibliotheken managt, findet hier ein schlankes, verstaendliches System.

Anleitungen

Anleitungen

Hintergrund-Prozesse (Supervisor)

Hintergrund-Prozesse via Supervisor

Wenn dein Projekt einen Prozess braucht, der dauerhaft im Hintergrund laeuft (z.B. Symfony Messenger, Laravel Queue-Worker, ein Node.js-Daemon, ein eigener Watcher), kannst du ihn per Supervisor starten lassen. Der Prozess startet dann automatisch mit dem Container und wird bei Absturz neu gestartet — du musst nichts weiter tun.

Cron vs. Supervisor — Cron startet einen Prozess zu festen Zeitpunkten und laesst ihn nach getaner Arbeit sterben. Supervisor startet einen Prozess einmal und haelt ihn dauerhaft am Leben. Fuer Job-Queues (Messenger, Sidekiq, RQ etc.) willst du Supervisor.


Wo liegen die Config-Dateien?

Per SSH in deinen Container einloggen und dann:

cd ~/.webunit/supervisor.d/

Dieses Verzeichnis gehoert dir und ist vor Web-Zugriff geschuetzt (https://deine-domain/.webunit/... liefert 403).

Pro Prozess legst du eine <name>.conf-Datei an. Der Dateiname ist egal, die Endung .conf ist Pflicht.


Erstes Beispiel: Symfony Messenger

Datei: ~/.webunit/supervisor.d/messenger.conf

[program:messenger-consume]
command=/usr/local/bin/php /var/www/current/bin/console messenger:consume async --time-limit=3600 --memory-limit=256M
autostart=true
autorestart=true
stdout_logfile=~/.webunit/logs/messenger.log
stderr_logfile=~/.webunit/logs/messenger.err

Aktivieren:

webunit-supervisor reload

Status pruefen:

webunit-supervisor status

Ausgabe:

apache2                          RUNNING   pid 56, uptime 0:01:38
sshd                             RUNNING   pid 57, uptime 0:01:38
messenger-consume                RUNNING   pid 129, uptime 0:00:05

Fertig — der Worker laeuft, wird bei Container-Restart automatisch gestartet und bei Absturz neu gestartet.


Weitere Beispiele

Laravel Queue-Worker

[program:laravel-queue]
command=/usr/local/bin/php /var/www/artisan queue:work --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stdout_logfile=~/.webunit/logs/queue.log
stderr_logfile=~/.webunit/logs/queue.err

Node.js-Daemon

[program:my-node-daemon]
command=/usr/bin/node /var/www/current/daemon.js
directory=/var/www/current
environment=NODE_ENV="production",PORT="4000"
autostart=true
autorestart=true
stdout_logfile=~/.webunit/logs/node.log
stderr_logfile=~/.webunit/logs/node.err

Mehrere Worker parallel

Manche Queue-Systeme profitieren von mehreren parallelen Workern. Supervisor kennt dafuer numprocs:

[program:messenger-consume]
command=/usr/local/bin/php /var/www/current/bin/console messenger:consume async --time-limit=3600
numprocs=3
process_name=%(program_name)s_%(process_num)02d
autostart=true
autorestart=true
stdout_logfile=~/.webunit/logs/messenger_%(process_num)02d.log
stderr_logfile=~/.webunit/logs/messenger_%(process_num)02d.err

Das startet 3 Instanzen: messenger-consume_00, _01, _02.

Einfacher Bash-Loop (zum Testen)

[program:testworker]
command=/bin/bash -c "while true; do date; sleep 5; done"
autostart=true
autorestart=true
stdout_logfile=~/.webunit/logs/testworker.log
stderr_logfile=~/.webunit/logs/testworker.err

Kommandos

Alle Kommandos rufst du im Container-SSH ohne sudo auf.

Kommando Was es macht
webunit-supervisor reload Liest *.conf neu ein und startet neue/geaenderte Programme. Sanitize-Check laeuft vorher.
webunit-supervisor status Zeigt Status aller Programme (deine + apache2 + sshd).
webunit-supervisor restart <name> Startet ein Programm neu.
webunit-supervisor tail <name> Zeigt letzte Zeilen von stdout.
webunit-supervisor tail-err <name> Zeigt letzte Zeilen von stderr.
webunit-supervisor validate Prueft nur die Configs, ohne Reload.
webunit-supervisor help Alle Kommandos.

restart und tail auf apache2 oder sshd werden abgelehnt — das sind System-Prozesse.


Config-Format (Kurz-Referenz)

Wichtige Direktiven fuer [program:...]:

Direktive Bedeutung
command= Vollstaendiger Pfad zum Binary + Argumente. Kein sudo.
directory= Arbeitsverzeichnis vor dem Start.
environment=KEY="value",KEY2="value2" Zusaetzliche Umgebungsvariablen.
autostart=true Beim Container-Start automatisch starten.
autorestart=true Nach Absturz neu starten.
startsecs=1 Sekunden Wartezeit, bis der Start als erfolgreich gilt.
startretries=3 Nach so vielen Fehl-Starts aufgeben und FATAL markieren.
stopsignal=TERM Signal zum Stoppen (TERM, INT, KILL).
stopwaitsecs=10 Wartezeit auf sauberes Beenden, bevor KILL.
stdout_logfile=<pfad> Datei fuer stdout. Standard sind Dateien unter ~/.webunit/logs/.
stderr_logfile=<pfad> Datei fuer stderr.
stdout_logfile_maxbytes=50MB Rotate nach 50 MB (Standard).
stdout_logfile_backups=10 Anzahl rotierter Backups (Standard 10).
numprocs=N N parallele Instanzen des Programms.
process_name=%(program_name)s_%(process_num)02d Namensschema bei numprocs>1.

Vollstaendige Referenz: http://supervisord.org/configuration.html#program-x-section-values


Was NICHT erlaubt ist

Der Sanitize-Check beim reload blockt:

Bei Fehlern zeigt webunit-supervisor validate (oder reload) genau welche Zeile in welcher Datei das Problem ist:

FEHLER: ~/.webunit/supervisor.d/messenger.conf:3 — user=root ist nicht erlaubt (nur Container-User)

Logs


Was passiert bei Container-Neubau?

Deine ~/.webunit/supervisor.d/-Configs bleiben erhalten (liegen im /var/www-Volume). Nach dem Neubau starten sie automatisch mit dem Container.

Die generierte README.txt im Verzeichnis kommt nur einmal beim allerersten Container-Start rein — wenn du sie loeschst, wird sie nicht neu geschrieben.


Troubleshooting

Prozess ist im Status FATAL

webunit-supervisor status zeigt FATAL. Das heisst Supervisor hat den Prozess mehrfach versucht zu starten und aufgegeben. Ursache findest du in stderr:

webunit-supervisor tail-err <name>

Typische Fehler:

Fix, dann:

webunit-supervisor restart <name>

Prozess ist im Status EXITED

Er ist normal beendet (Exit-Code 0), Supervisor startet ihn aber nicht neu. Vermutlich hast du autorestart=false oder der Command endet tatsaechlich (z.B. time-limit bei Messenger). Bei Messenger ist das gewollt — autorestart=true startet ihn dann wieder.

webunit-supervisor: command not found

Das kann eigentlich nicht passieren — das Binary liegt im PATH. Wenn doch, ist entweder dein Container aelter als 2026-09-03 (dann sag uns Bescheid, wir rebuilden) oder der PATH ist in deinem .bashrc ueberschrieben.

Config aendert sich nicht

Nach dem Editieren einer .conf musst du explizit reload fahren. Supervisor sieht Datei-Aenderungen nicht von allein.

webunit-supervisor reload

"Sanitize-Check fehlgeschlagen — Reload abgebrochen"

Der Reload wird abgebrochen wenn irgendeine deiner .conf einen Fehler hat. Fix die betroffene Datei (die genaue Zeile steht in der Fehlermeldung), dann nochmal reload.

Anleitungen

PHP-Tuning (Custom-INI)

PHP-Tuning per Custom-INI

Die haeufigsten PHP-Werte (Memory, OPcache, APCu) sind pro Hostname konfigurierbar. Manche haben eigene Formularfelder, den Rest setzt du im Custom-INI-Textblock.

Wo?

Admin-Panel → Subscription → Bearbeiten → Tab Hostnames → beim gewuenschten Hostname aufklappen.

Direkte Formularfelder (kein Custom-INI noetig):

Alles andere → Custom-INI-Textblock.

Copy-&-Paste-Snippets

Grosse Symfony/Shopware/Laravel-Anwendung

memory_limit = 1024M
opcache.memory_consumption = 256
opcache.max_accelerated_files = 20000
opcache.revalidate_freq = 0
opcache.validate_timestamps = 1
apcu.shm_size = 128M
realpath_cache_size = 4096K
realpath_cache_ttl = 600

WordPress mit vielen Plugins

memory_limit = 512M
opcache.memory_consumption = 192
opcache.max_accelerated_files = 15000
apcu.shm_size = 64M

Produktion (Deploy-basiert, kein File-Watcher noetig)

opcache.validate_timestamps = 0
opcache.enable_cli = 1

validate_timestamps = 0 heisst: nach Code-Aenderungen musst du PHP neu laden (docker compose exec app apache2ctl graceful — oder wir exponieren dafuer noch einen Button im Admin). Bringt spuerbar Performance.

Sessions in APCu statt Dateien (kleine Latenz, kein Disk-IO)

session.save_handler = files
session.save_path = /tmp
; ODER (schneller, braucht apcu):
; session.save_handler = apcu

Whitelist — was ist erlaubt?

Der Custom-INI-Block wird beim Speichern gefiltert. Erlaubt sind unter anderem:

Alles andere wird verworfen (mit Hinweis im Speicher-Feedback).

Was kann ich abfragen?

phpinfo() in einem PHP-File — zeigt alle aktiven Werte. Aber:

Achtung: phpinfo()-Ausgabe niemals oeffentlich stehen lassen (nur kurz aufrufen, dann sofort loeschen oder mit .htaccess blocken). Sie enthaelt viele interne Umgebungs-Details.

Anleitungen

Protokollierung / Logging

Protokollierung / Logging

Was wird protokolliert, wo landen die Logs, und was ist geplant.

Aktueller Stand

Logs im Container

Jeder Sub-Container schreibt lokal:

Log Pfad im Container Inhalt Persistent?
Apache Access /var/log/apache2/<vhost>-access.log (auch per ~/logs/ erreichbar) HTTP-Requests pro vhost Ja — Bind-Mount + im Restic-Backup
Apache Error /var/log/apache2/<vhost>-error.log Apache-Fehler + PHP-Fehler (via log_errors = On) Ja — Bind-Mount + im Restic-Backup
PHP Errors in Apache Error (nicht separat) fatal/warning/notice — steuerbar per error_reporting in Custom-INI siehe Apache Error
msmtp /var/log/msmtp.log ausgehende Mails (Sender, Empfaenger, Ergebnis) Ja — Bind-Mount + im Restic-Backup
Supervisor-Kunden-Prozesse ~/.webunit/logs/*.log stdout/stderr eigener [program:...]-Configs Ja — Home-Volume + im Restic-Backup
Container stdout/stderr via docker logs Apache-Startup + Supervisor-Events + PHP error_log() ohne Datei Nein — Docker-Default (10 MB, 3 Files), Debug-only
SSH-Logins in den Container /var/log/auth.log (Container-intern) SSH-Sessions dieses Kunden Nein — Redundant zu Node-ssh-proxy-Log
SSH-Routing (alle Kunden) Node: ssh-proxy Container-Log + /var/log/hosting-sshpiper.log SSH-Verbindungen aller Subs auf der Node, Fail2Ban-Quelle Ja — Node-persistent

Container-Logs ueberleben Container-Recreate + Image-Rebuild (Bind-Mount ins Host-/srv/hosting/subscriptions/<cid>/logs/) und sind im taeglichen Restic- Backup enthalten — auch nach Node-Umzug also verfuegbar.

Logs auf der Node (ausserhalb Container)

Log Pfad Inhalt
Hosting-API journalctl -u hosting-api Node-API-Requests, Rebuilds, Sync-Runs
Backup /srv/hosting/backup-state.json + /var/log/hosting-backup-*.log Zeitpunkte, Erfolg/Fehler, Dauer, letzte 50 Events pro Sub
SSH-Piper Container-Logs ssh-proxy SSH-Routing-Entscheidungen (welcher User, welcher Sub)
Rebuild-Images /var/log/hosting-rebuild-images.log Image-Build-Output, Sub-Recreate
Self-Update /var/log/hosting-self-update.log Node zieht Binary + Templates vom Admin

Logs im Admin-Panel

Log Ort Inhalt
Aktivitaets-Log pro Sub subscription_events-Tabelle, sichtbar auf Subscription-Show Create/Update/Delete, Hostname/DB/Mail-Aenderungen, Backup-Trigger, Install, Restore — wer, wann, was
Access-Tokens fuer Kunden pro Sub sichtbar Erzeugung + Verwendung von Zugangs-Links
Logs-Viewer pro Sub subscriptions/{id}/logs Live-Tail Apache Access / Error / Container stdout (letzte 50 Zeilen)
Monitoring pro Sub + pro Node 5-Min-Samples: CPU/RAM/Storage/Load, letzte 31 Tage

Zugriff fuer den Kunden

Geplant / in Arbeit

Datenschutz-Hinweis

Access-Logs enthalten IP-Adressen der Website-Besucher. Diese werden nach DSGVO-Standard 30 Tage aufbewahrt (per Docker-Log-Rotation faktisch weniger). Wenn Sie kuerzere Aufbewahrung brauchen: sagen Sie Bescheid, wir konfigurieren Log-Rotation entsprechend.

Fragen?

Bei Fragen zu Log-Zugriff / Retention / Exports einfach melden — die meisten Punkte oben sind Config-Aenderungen, keine Software-Aenderungen.

Anleitungen

MariaDB-Tuning (Custom-Config)

MariaDB-Tuning per Custom-Config

Fuer jede Datenbank kannst du eigene MariaDB-Einstellungen setzen — analog zum PHP-Custom-INI. Die Werte ueberschreiben die Webunit-Defaults.

Wo?

Admin-Panel → Subscription → Bearbeiten → Tab Datenbanken → pro Datenbank ein Feld Custom MariaDB-Config.

Webunit-Defaults (bereits aktiv fuer alle DBs)

[mysqld]
max_allowed_packet = 64M
wait_timeout        = 600
interactive_timeout = 600
max_connections     = 200

Alles was du ins Custom-Feld schreibst, ueberschreibt diese Werte.

Copy-&-Paste-Snippets

Grosse Import-/Export-Operationen (grosse Bloetter, PDF-Anhaenge in DB)

max_allowed_packet = 256M

Shopware / grosser Katalog mit vielen Produkten

max_allowed_packet = 128M
innodb_buffer_pool_size = 512M
innodb_log_file_size = 128M
tmp_table_size = 128M
max_heap_table_size = 128M
sort_buffer_size = 8M
join_buffer_size = 8M

WordPress mit vielen Plugins

max_allowed_packet = 64M
innodb_buffer_pool_size = 256M
tmp_table_size = 64M
max_heap_table_size = 64M

Slow-Query-Log fuer Performance-Analyse

slow_query_log = 1
long_query_time = 1
log_queries_not_using_indexes = 1

Slow-Log landet im DB-Container unter /var/lib/mysql/*-slow.log und ist per SSH oder docker exec einsehbar.

Utf8mb4 mit korrekter Collation (Emojis in Kunden-Kommentaren)

character-set-server = utf8mb4
collation-server     = utf8mb4_unicode_ci

Strikter SQL-Mode fuer neue Projekte

sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

Whitelist — was ist erlaubt?

Erlaubt sind gaengige Tuning-Parameter fuer:

Nicht-erlaubte Keys werden still verworfen — landen als Kommentar in der generierten 99-webunit-custom.cnf (im DB-Container unter /etc/mysql/mariadb.conf.d/). Verworfen werden aus Sicherheitsgruenden z.B. secure_file_priv, plugin_dir, log_bin, datadir — die wuerden den Container-Betrieb kompromittieren.

Konfigurations-Format

Was passiert nach dem Speichern?

  1. Werte werden gegen die Whitelist geprueft (Verwerfen bei Verstoss).
  2. Neue 99-webunit-custom.cnf wird auf der Node erzeugt.
  3. Der DB-Container wird noch nicht automatisch neu gestartet — du siehst den neuen Wert erst nach einem Restart:
    Admin-Panel → Subscription → Container → "DB-Container neustarten"
    
    (oder wir bauen das noch als Auto-Restart bei Config-Aenderung — im Zweifel: uns ansprechen).

Aktuelle Werte pruefen

Per SSH ins Sub-Container:

mariadb -u <username> -p<pass> -e "SHOW VARIABLES LIKE 'max_allowed_packet'"

Oder via phpMyAdmin (Zahnrad-Icon rechts oben, dann "Server-Variablen").

Wichtige Anmerkungen

Anleitungen

CLI-Befehle im Container

CLI-Befehle im Container

Diese Befehle stehen im SSH-Zugang deines Containers zur Verfuegung. Alle laufen als dein Container-User (kein sudo noetig, kein Root-Zugriff).

webunit-supervisor — Hintergrund-Prozesse

Verwaltung von Symfony-Messenger-Workern, Queue-Workern, Node-Daemons.

webunit-supervisor reload         # ~/.webunit/supervisor.d/*.conf einlesen
webunit-supervisor status         # Status aller Programme
webunit-supervisor restart <name> # Ein Programm neu starten
webunit-supervisor tail <name>    # Log-Zeilen (stdout)
webunit-supervisor tail-err <name># Log-Zeilen (stderr)
webunit-supervisor validate       # Syntax-Check ohne Reload
webunit-supervisor help

Details siehe Hintergrund-Prozesse (Supervisor).


webunit-ssh — SSH-Auth-Verwaltung

webunit-ssh status                    # Aktueller PW-Auth-Modus + Key-Anzahl
webunit-ssh list-keys                 # Aktive SSH-Keys auflisten
webunit-ssh add-key '<pubkey>'        # SSH-Public-Key hinzufuegen
webunit-ssh remove-key <fingerprint>  # SSH-Key loeschen (fp aus list-keys)
webunit-ssh password-auth on|off      # Passwort-Login erlauben / sperren
webunit-ssh help

Beispiel-Ausgabe:

== SSH-Auth-Konfiguration ==
Passwort-Login:   DEAKTIVIERT (nur Key)
Aktive Keys:      3
Verwaltet in:     /etc/webunit/sshpiper_pub.key (managed — nicht editieren)
Key hinzufuegen:  webunit-ssh add-key '<public-key>'

Wichtig zu ~/.ssh/authorized_keys: Diese Datei wird von unserer Infrastruktur IGNORIERT. Eintraege dort haben keine Wirkung. Die Datei enthaelt bewusst nur einen Hinweis-Text und ist read-only — sshd im Container liest ausschliesslich /etc/webunit/sshpiper_pub.key, was vom Admin-System zentral verwaltet wird.

Keys hinzufuegen: webunit-ssh add-key '<public-key>' (siehe unten) oder im Admin-Panel unter „SSH-Keys".

Keys auflisten:

$ webunit-ssh list-keys
== Aktive SSH-Keys (3) ==
  SHA256:HkkktzVstpsuXhuWUej/qTQ24CL+6CB8YkUMhnjZ+ow
     Label:    Vom Container 05.09.2026 10:20 — eddsa-key-20260905
     Angelegt: 2026-09-05 10:20:20   Laeuft ab: -

  SHA256:...
     ...

Loeschen: webunit-ssh remove-key <fingerprint>

Key loeschen (Fingerprint aus list-keys kopieren):

$ webunit-ssh remove-key SHA256:HkkktzVstpsuXhuWUej/qTQ24CL+6CB8YkUMhnjZ+ow
Loesche Key SHA256:... — dies ist SOFORT wirksam.
Fortfahren? [j/N] j
Key geloescht — SHA256:... (Vom Container 05.09.2026 10:20 — eddsa-key-20260905)
In wenigen Sekunden verweigert sshpiper Logins mit diesem Key.

Nach Loeschung: ein spaeteres webunit-ssh add-key mit demselben Public-Key stellt den Key wieder her (gleicher DB-Eintrag, restored) statt neu anzulegen. Doppel-Adds sind idempotent (already_known).

Passwort-Login-Toggle: webunit-ssh password-auth on|off oder im Admin-Panel.


webunit-password — Passwoerter selbst rotieren

webunit-password ssh              SSH-/SFTP-Passwort neu setzen
webunit-password db <label>       Datenbank-Passwort neu setzen
webunit-password help

Detaillierte Anleitung inkl. Sicherheits-Hinweisen: siehe Passwoerter selbst aendern.


webunit-opcache-reset — OPcache leeren (Deployer-freundlich)

Leert den PHP-OPcache im Apache-Prozess ohne Restart, ohne Downtime. Zusaetzlich werden der realpath-Cache und (falls aktiv) APCu geleert — zusammen sind das exakt die Caches, die nach einem Symlink-Umbiegen (current -> releases/N) noch auf die alte Release zeigen wuerden.

webunit-opcache-reset

Beispiel-Ausgabe:

OPcache geleert.
Vorher: 4231 Scripts im Cache, 84318720 Bytes belegt.

Warum es dieses CLI gibt: Die uebliche Empfehlung cachetool.phar opcache:reset --fcgi=/run/php-fpm.sock funktioniert bei uns NICHT — unser Image faehrt Apache mit mod_php (kein PHP-FPM, kein .sock). Fuer denselben Zweck gibt es genau dieses CLI.

Wenn du in einem Deployer-Task ohne SSH-Sitzung arbeiten willst, bleibt auch Cachetool im --web-Adapter moeglich:

php cachetool.phar opcache:reset \
    --web=curl --web-path=./public --web-url=https://deine.domain

Cachetool legt dazu kurz eine Adapter-PHP-Datei ins Public, ruft sie per HTTP an und loescht sie wieder. Das erwischt denselben mod_php-OPcache. Vorteil webunit-opcache-reset: kein Public-Endpoint, kein Aufraeumen, zusaetzlich realpath+apcu.


Gibt eine URL aus, die dich einmalig fuer 12 Stunden zu phpMyAdmin auf deiner Node lotst. Die URL ist ein signierter Tageslink — ohne den ist das PMA-Login-Formular von aussen nicht mal erreichbar.

Beispiel:

PMA-Zugang (12h gueltig ab jetzt, Tages-Grenze 04:00 Berlin):

  https://pma.<node>.webunit.cloud/pma-open?daykey=...&cid=...&node=...

Link im Browser oeffnen — Admin validiert und leitet weiter zu PMA.

Wichtig: die URL ist nur einen "Arbeitstag" gueltig. Tages-Grenze ist 04:00 Berlin — falls du morgens frueh anfaengst, laeuft dein Cookie ab 04:00 ab und du brauchst einen neuen Link. Nachts arbeitende Kunden haben von 04:00 an denselben Link 24 Stunden minus 12 Cookie-Timeout.

Wer die URL kennt, kommt zu PMA — nicht in oeffentlichen Chats posten.


Was du KEIN CLI dafuer brauchst


Bash-Zusatzausstattung im Container

Beim ersten Login findest du in deinem Home:

Zusaetzlich vorinstalliert: composer, wp (WP-CLI), node, npm, git, curl, mariadb, msmtp (Mail via /usr/sbin/sendmail), nano, zstd.

Fehlendes Tool? Kurz per Support melden — wir installieren pauschal ins Image, alle Kunden bekommen es.

Anleitungen

Passwoerter selbst aendern

Passwoerter selbst aendern

Du kannst SSH-/SFTP- und Datenbank-Passwoerter jederzeit selbst rotieren — direkt aus deinem Container per CLI. Kein Ticket, keine Wartezeit.

Der Befehl ist webunit-password. Rotation ist sofort wirksam und das neue Passwort wird einmalig angezeigt — kopieren und speichern.

SSH-/SFTP-Passwort

$ webunit-password ssh
Das aktuelle SSH-Passwort wird sofort ungueltig. Bestehende Sitzungen
bleiben offen, aber neue Logins brauchen das neue Passwort.

  Wichtig: vorher eine zweite SSH-Sitzung mit dem neuen Passwort
  aufmachen und pruefen, dass Login klappt, BEVOR diese Sitzung
  geschlossen wird. So kommst du nicht versehentlich aus.

Fortfahren? [j/N] j

Neues SSH-Passwort:
  8f3aK2q7mZpxN4Rtv9LcJhBw

Jetzt in einer zweiten Sitzung testen. Erst wenn Login mit dem
neuen Passwort klappt, diese Sitzung schliessen.

Wichtig: deine aktuelle SSH-Sitzung laeuft nach der Rotation weiter, SSH prueft das Passwort nur beim Login. Bevor du die Sitzung schliesst, oeffne eine zweite SSH-Verbindung mit dem neuen Passwort und pruefe, dass Login klappt. Erst dann die erste Sitzung beenden. Sonst kannst du dich aussperren.

Datenbank-Passwort

Das Label ist der Datenbank-Name aus dem Admin-Panel (meist main oder ein Kunden-Name — im Zweifel: Datenbank-Kachel in der Subscription-Ansicht).

$ webunit-password db main
Das aktuelle Datenbank-Passwort fuer 'main' wird sofort ungueltig.
Deine Anwendung wird die Datenbank nicht mehr erreichen, bis du das neue
Passwort in deiner Config eingetragen und die Anwendung neu geladen hast.

Fortfahren? [j/N] j

Neues Datenbank-Passwort (Label: main):
  Q7pX2mkV9fLcNhZa8Bwry3Ju

Trage das Passwort in die Config-Datei deiner Anwendung ein und
starte die Anwendung neu.

Wichtig: das alte Passwort ist mit der Rotation weg — keine Uebergangsphase. Ab dem Moment schlaegt jeder DB-Zugriff mit dem alten Passwort fehl. Direkt danach das neue Passwort in die Konfigurations- Datei deiner Anwendung eintragen und die Anwendung neu laden.

Wo genau das Passwort in deiner Anwendung eingetragen wird, weisst du selbst am besten — je nach Anwendung eine Config-Datei, eine Environment-Variable oder ein Secret-Manager. Nach dem Eintragen die Anwendung neu starten oder ihre Konfiguration neu einlesen lassen.

Was passiert im Hintergrund

Die CLI ruft unseren Node-Dienst auf, der:

  1. ein neues Zufalls-Passwort erzeugt (24 Zeichen),
  2. es lokal setzt (SSH: chpasswd; DB: ALTER USER ... IDENTIFIED BY),
  3. es an unser Admin-Panel meldet, damit es dauerhaft ist und beim naechsten Sync nicht ueberschrieben wird,
  4. es dir einmalig ausgibt.

Das neue Passwort landet nirgends in Logs. Wenn du es verlierst, musst du erneut rotieren.

Alternative: SSH-Key statt Passwort

Sicherer als Passwort-Rotation ist ein SSH-Key. Public-Key einmalig in ~/.ssh/authorized_keys deines Containers ablegen, danach kannst du den Passwort-Login im Admin-Panel komplett abschalten. Keys ueberleben Container-Recreate automatisch (werden von uns synchronisiert).