true, 'vhost.http2_push' => false, // WP-config toggles 'wp.debug' => false, 'wp.cache' => true, 'wp.disallow_file_edit' => true, 'wp.auto_updater_off' => false, 'wp.force_ssl_admin' => true, // WP general 'wp.search_visible' => true, 'wp.registration' => false, // PHP toggles 'php.display_errors' => false, 'php.opcache_enable' => true, 'php.log_errors' => true, 'php.allow_url_fopen' => true, // SSL 'ssl.ocsp' => true, 'ssl.auto_renew' => true, 'ssl.caa_check' => true, 'ssl.ct_log' => true, // SSH/FTP 'access.password_auth' => true, // password-auth DISABLED toggle 'access.no_root' => true, 'access.fail2ban' => true, 'access.ip_allowlist' => false, 'access.ssh_2fa' => false, // Plugins 'wp.auto.security' => true, 'wp.auto.minor' => true, 'wp.auto.major' => false, 'wp.auto.snapshot' => true, 'wp.auto.staging_first' => false, // Redirects new-rule form 'redirect.keep_qs' => true, 'redirect.case_insens' => false, // Staging 'staging.robots_block' => true, 'staging.email_sandbox' => true, 'staging.payments_test' => true, // Plugin auto-update flags (per slug) 'plugin.wordpress-seo.auto' => true, 'plugin.woocommerce.auto' => false, 'plugin.wp-rocket.auto' => true, 'plugin.wordfence.auto' => true, 'plugin.advanced-custom-fields.auto' => false, 'plugin.contact-form-7.auto' => true, 'plugin.akismet.auto' => true, 'plugin.updraftplus.auto' => false, ]; public function toggleSetting(string $key): void { $this->settings[$key] = ! ($this->settings[$key] ?? false); } public function isOn(string $key): bool { return (bool) ($this->settings[$key] ?? false); } /** Plugin / theme registry — mocked, would come from WP-API in prod. */ public function getPluginsProperty(): array { return [ ['name' => 'Yoast SEO', 'slug' => 'wordpress-seo', 'version' => '22.5', 'latest' => '22.5', 'status' => 'active', 'auto' => true, 'updates' => false], ['name' => 'WooCommerce', 'slug' => 'woocommerce', 'version' => '8.9.2', 'latest' => '9.0.1', 'status' => 'active', 'auto' => false, 'updates' => true], ['name' => 'WP Rocket', 'slug' => 'wp-rocket', 'version' => '3.16.0', 'latest' => '3.16.0', 'status' => 'active', 'auto' => true, 'updates' => false], ['name' => 'Wordfence Security', 'slug' => 'wordfence', 'version' => '7.11.4', 'latest' => '7.11.6', 'status' => 'active', 'auto' => true, 'updates' => true], ['name' => 'Advanced Custom Fields', 'slug' => 'advanced-custom-fields', 'version' => '6.2.10', 'latest' => '6.3.1', 'status' => 'active', 'auto' => false, 'updates' => true], ['name' => 'Contact Form 7', 'slug' => 'contact-form-7', 'version' => '5.9.6', 'latest' => '5.9.6', 'status' => 'inactive', 'auto' => true, 'updates' => false], ['name' => 'Akismet Anti-Spam', 'slug' => 'akismet', 'version' => '5.3.2', 'latest' => '5.3.3', 'status' => 'active', 'auto' => true, 'updates' => true], ['name' => 'UpdraftPlus', 'slug' => 'updraftplus', 'version' => '1.24.0', 'latest' => '1.24.0', 'status' => 'inactive', 'auto' => false, 'updates' => false], ]; } public function getThemesProperty(): array { return [ ['name' => 'Storefront', 'version' => '4.6.0', 'latest' => '4.6.0', 'status' => 'parent'], ['name' => 'Storefront Child', 'version' => '1.2.1', 'latest' => '1.2.1', 'status' => 'active'], ['name' => 'Twenty Twenty-Four','version' => '1.2', 'latest' => '1.2', 'status' => 'inactive'], ]; } public function getRedirectsProperty(): array { return [ ['from' => '/alte-kategorie/', 'to' => '/produkte/kaffee/', 'code' => 301, 'hits' => 4218, 'last' => 'vor 12 min'], ['from' => '/2024-aktion', 'to' => '/aktuelle-angebote/', 'code' => 301, 'hits' => 2104, 'last' => 'vor 38 min'], ['from' => '/sale', 'to' => '/aktuelle-angebote/', 'code' => 302, 'hits' => 18642,'last' => 'vor 2 min'], ['from' => '/checkout-old', 'to' => '/warenkorb/', 'code' => 301, 'hits' => 12, 'last' => 'gestern'], ['from' => '/feed/atom', 'to' => '/feed/', 'code' => 301, 'hits' => 891, 'last' => 'vor 7 min'], ['from' => '/wp-content/uploads/2022/(.*)', 'to' => '/wp-content/uploads/legacy/$1', 'code' => 301, 'hits' => 56, 'last' => 'vor 4 std'], ]; } public function mount(Site $site): void { $this->site = $site->load(['server', 'certificate', 'crons']); } public function setTab(string $t): void { $this->tab = $t; } public function setActiveFile(string $path): void { $this->activeFile = $path; } public function setLog(string $type): void { $this->currentLog = $type; } public function toggleDir(string $path): void { if (in_array($path, $this->openDirs, true)) { $this->openDirs = array_values(array_diff($this->openDirs, [$path])); } else { $this->openDirs[] = $path; } } public function toggleMaintenance(): void { $this->site->maintenance_mode = ! $this->site->maintenance_mode; $this->site->save(); } public function toggleCache(): void { $this->site->cache_enabled = ! $this->site->cache_enabled; $this->site->save(); } public function toggleCdn(): void { $this->site->cdn_enabled = ! $this->site->cdn_enabled; $this->site->save(); } /* File tree (nested) — verbatim from templates/akutell/sitedetails.js */ public function getFileTreeProperty(): array { return [ [ 'name' => 'htdocs', 'type' => 'dir', 'open' => true, 'children' => [ ['name' => 'wp-admin', 'type' => 'dir', 'children' => []], [ 'name' => 'wp-content', 'type' => 'dir', 'open' => true, 'children' => [ [ 'name' => 'themes', 'type' => 'dir', 'open' => true, 'children' => [ [ 'name' => 'storefront-child', 'type' => 'dir', 'open' => true, 'children' => [ ['name' => 'functions.php', 'type' => 'file', 'lang' => 'PHP', 'path' => 'htdocs/wp-content/themes/storefront-child/functions.php'], ['name' => 'style.css', 'type' => 'file', 'lang' => 'CSS', 'path' => 'htdocs/wp-content/themes/storefront-child/style.css'], ], ], ], ], ['name' => 'plugins', 'type' => 'dir', 'children' => []], ['name' => 'uploads', 'type' => 'dir', 'children' => []], ], ], ['name' => 'wp-includes', 'type' => 'dir', 'children' => []], ['name' => '.htaccess', 'type' => 'file', 'lang' => 'APACHE', 'path' => 'htdocs/.htaccess'], ['name' => 'index.php', 'type' => 'file', 'lang' => 'PHP', 'path' => 'htdocs/index.php'], ['name' => 'robots.txt', 'type' => 'file', 'lang' => 'TEXT', 'path' => 'htdocs/robots.txt'], ['name' => 'wp-config.php','type' => 'file', 'lang' => 'PHP', 'path' => 'htdocs/wp-config.php'], ], ], ['name' => 'php.ini', 'type' => 'file', 'lang' => 'INI', 'path' => 'php.ini'], [ 'name' => 'logs', 'type' => 'dir', 'open' => true, 'children' => [ ['name' => 'access.log', 'type' => 'file', 'lang' => 'LOG', 'path' => 'logs/access.log'], ['name' => 'error.log', 'type' => 'file', 'lang' => 'LOG', 'path' => 'logs/error.log'], ], ], ]; } /* fileContents from sitedetails.js verbatim */ public function getFileContentsProperty(): array { return [ 'htdocs/wp-config.php' => <<<'PHP' <<<'TXT' # BEGIN WordPress RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] # END WordPress Header set X-Content-Type-Options nosniff Header set X-Frame-Options SAMEORIGIN Header set Referrer-Policy strict-origin-when-cross-origin TXT, 'htdocs/robots.txt' => <<<'TXT' User-agent: * Disallow: /wp-admin/ Disallow: /warenkorb/ Disallow: /checkout/ Allow: /wp-admin/admin-ajax.php Sitemap: https://shop.bergmann-coffee.com/sitemap_index.xml TXT, 'htdocs/index.php' => <<<'PHP' <<<'PHP' array_merge($s, ['interval' => 60])); PHP, 'htdocs/wp-content/themes/storefront-child/style.css' => <<<'CSS' /* Theme Name: Storefront Child — Bergmann Template: storefront */ :root { --brand: #15a06a; --brand-dark: #0d6c4a; } .button.alt { background: var(--brand); border-color: var(--brand); } .button.alt:hover { background: var(--brand-dark); } CSS, 'php.ini' => <<<'INI' ; bergmann-coffee · php-fpm pool memory_limit = 256M max_execution_time = 60 max_input_time = 60 upload_max_filesize = 64M post_max_size = 64M date.timezone = Europe/Berlin opcache.enable = 1 opcache.memory_consumption = 256 opcache.max_accelerated_files = 20000 opcache.validate_timestamps = 0 INI, 'logs/access.log' => <<<'LOG' 192.0.2.41 - - [12/Mai/2026:09:12:04 +0200] "GET /shop/ HTTP/2.0" 200 18421 203.0.113.7 - - [12/Mai/2026:09:12:05 +0200] "GET /wp-json/wc/store/cart HTTP/2.0" 200 842 192.0.2.41 - - [12/Mai/2026:09:12:09 +0200] "POST /?wc-ajax=add_to_cart HTTP/2.0" 200 311 LOG, 'logs/error.log' => "[error] PHP Notice: Undefined index 'shipping_zone' in cart.php:88\n[error] Uncaught TypeError: count(): Argument must be array in class-wc-cart.php:412\n", ]; } /* Log entries per type (xterm renders these client-side) */ public function getLogDataProperty(): array { return [ 'access' => [ ['09:12:04', 'INFO', '192.0.2.41 "GET /shop/" 200 18421 — 142ms'], ['09:12:05', 'INFO', '203.0.113.7 "GET /wp-json/wc/store/cart" 200 842 — 38ms'], ['09:12:09', 'INFO', '192.0.2.41 "POST /?wc-ajax=add_to_cart" 200 311 — 96ms'], ['09:12:14', 'INFO', '198.51.100.2 "GET /produkt/espresso-blend/" 200 21044 — 158ms'], ['09:12:21', 'WARN', '45.155.* "GET /wp-login.php" 403 — rate-limit'], ['09:12:33', 'INFO', '192.0.2.88 "GET /warenkorb/" 200 9920 — 71ms'], ['09:12:40', 'INFO', 'Googlebot "GET /sitemap_index.xml" 200 4210 — 22ms'], ['09:12:48', 'INFO', '192.0.2.41 "POST /checkout/" 302 0 — 210ms'], ], 'error' => [ ['09:05:11', 'WARN', 'PHP Notice: Undefined index "shipping_zone" in cart.php:88'], ['09:07:42', 'ERROR', 'Uncaught TypeError: count(): Argument must be array — class-wc-cart.php:412'], ['09:09:03', 'INFO', 'Cache geleert: object-cache (redis) — 18421 keys'], ['08:58:19', 'WARN', 'Slow query (2,1s): wp_bg_postmeta — SELECT meta_value …'], ], 'php' => [ ['09:00:01', 'OK', 'php-fpm pool "bergmann" reloaded — 8 worker'], ['09:03:55', 'INFO', 'OPcache: 4218 scripts cached, 99.2% hit rate'], ['09:08:12', 'WARN', 'Worker 3: memory peak 214M / 256M'], ['09:11:40', 'INFO', 'request /checkout/ — 210ms, mem 41M'], ], 'wp' => [ ['09:01:00', 'DEBUG', 'WC_Cart::calculate_totals() — 12 items'], ['09:04:22', 'DEBUG', 'do_action("woocommerce_payment_complete", 48211)'], ['09:06:30', 'WARN', 'Plugin "Smart Coupons" deprecated hook: woocommerce_add_to_cart'], ['09:10:05', 'DEBUG', 'wp_mail() → kunde@example.com — Bestellbestätigung #48211'], ], ]; } public function getCurrentFileContentProperty(): string { return $this->fileContents[$this->activeFile] ?? ''; } }; ?> @php /** Recursive file tree renderer (folder toggle via Livewire). */ if (! function_exists('clu_render_tree')) { function clu_render_tree(array $items, string $activeFile, array $openDirs, string $base = ''): string { $out = ''; foreach ($items as $node) { $isDir = ($node['type'] ?? '') === 'dir'; $myPath = ltrim($base . '/' . $node['name'], '/'); $isOpen = $isDir && in_array($myPath, $openDirs, true); $isActive = ! $isDir && ($node['path'] ?? null) === $activeFile; $rowClass = 'clu-tree-item' . ($isDir ? ' dir' : '') . ($isOpen ? ' open' : '') . ($isActive ? ' active' : ''); $click = $isDir ? 'wire:click="toggleDir(\''.addslashes($myPath).'\')"' : 'wire:click="setActiveFile(\''.addslashes($node['path']).'\')"'; $ico = $isDir ? '' : ''; $chev = $isDir ? '' : ''; $out .= '
'.$chev.$ico.''.htmlspecialchars($node['name']).'
'; if ($isDir && ! empty($node['children'])) { $hidden = $isOpen ? '' : ' collapsed'; $out .= '
'.clu_render_tree($node['children'], $activeFile, $openDirs, $myPath).'
'; } } return $out; } } @endphp
{{-- ── Topbar ── --}}
{{ mb_strtoupper(mb_substr($site->domain, 0, 1)) }}

{{ $site->domain }}

{{ $site->server->name }} · wp {{ $site->wp_version }} · php {{ $site->php_version }} · ssl ✓
online
Besuchen
{{-- ── Tab bar ── --}}
@foreach (['overview' => ['Übersicht', ''], 'wp' => ['WordPress', ''], 'plugins' => ['Plugins', ''], 'redirects' => ['Redirects', ''], 'staging' => ['Staging', ''], 'vhost' => ['vHost', ''], 'ssl' => ['SSL / TLS', ''], 'access' => ['SSH / FTP', ''], 'php' => ['PHP / ini', ''], 'files' => ['Datei-Manager', ''], 'cron' => ['Cronjobs', ''], 'logs' => ['Logs', '']] as $key => [$label, $svg]) @endforeach
{{-- ────── OVERVIEW ────── --}} @if ($tab === 'overview')
Besucher / 24h
{{ number_format($site->visitors_24h, 0, ',', '.') }}
↑ 9.2% vs. gestern
Speicher
14.2/40 GB
36% genutzt
PageSpeed
{{ $site->pagespeed_score }}/100
Core Web Vitals OK
Updates
{{ $site->updates_pending }}
{{ $site->updates_pending > 0 ? 'verfügbar' : 'aktuell' }}

Installation

Domain{{ $site->domain }}
Server{{ $site->server->name }} · {{ $site->server->region }}
WordPress{{ $site->wp_version }}
PHP{{ $site->php_version }}
SSLLet's Encrypt
DB-Größe412 MB
Letztes Deployvor 4h

Schnellaktionen

Wartungsmodus
site für besucher sperren
Objekt-Cache (Redis)
datenbankabfragen zwischenspeichern
Edge-CDN
statische inhalte global cachen
HTTPS erzwingen
alle anfragen auf ssl umleiten
@endif {{-- ────── FILES ────── --}} @if ($tab === 'files')

Datei-Manager

/var/www/bergmann
{!! clu_render_tree($this->fileTree, $activeFile, $openDirs) !!}
{{ implode(' / ', array_slice(explode('/', $activeFile), 0, -1)) }} / {{ basename($activeFile) }}
{{ strtoupper(pathinfo($activeFile, PATHINFO_EXTENSION)) ?: 'TEXT' }}
@php $lines = max(1, substr_count($this->currentFileContent, "\n") + 1); @endphp
@for ($i = 1; $i <= $lines; $i++)
{{ $i }}
@endfor
✓ geladen · {{ $lines }} Zeilen
@endif {{-- ────── CRON ────── --}} @if ($tab === 'cron')

Cronjobs

Geplante Aufgaben {{ $site->crons->count() }}

@forelse ($site->crons as $c) @empty @endforelse
NameZeitplanBefehlLetzter LaufStatus
{{ $c->name }} {{ $c->expression }} {{ $c->command }} {{ $c->last_run_at?->diffForHumans() ?? '—' }} @if ($c->status === 'ok')ok @elseif ($c->status === 'failing')failing @elsepaused@endif
Noch keine Cronjobs.
@endif {{-- ────── LOGS (xterm.js) ────── --}} @if ($tab === 'logs')

Logs · {{ $currentLog }}.log

@foreach (['access', 'error', 'php', 'wp'] as $log) @endforeach
@push('scripts') @endpush
@endif {{-- ────── PLUGINS (Plugin- + Theme-Manager) ────── --}} @if ($tab === 'plugins')
@php $totalPlugins = count($this->plugins); $activePlugins = count(array_filter($this->plugins, fn($p) => $p['status'] === 'active')); $updatesPending = count(array_filter($this->plugins, fn($p) => $p['updates'])); $autoUpdate = count(array_filter($this->plugins, fn($p) => $p['auto'])); @endphp
Plugins gesamt
{{ $totalPlugins }}
{{ $activePlugins }} aktiv
Updates verfügbar
{{ $updatesPending }}
{{ $updatesPending > 0 ? 'jetzt aktualisieren' : 'alles aktuell' }}
Auto-Update aktiv
{{ $autoUpdate }}/{{ $totalPlugins }}
automatisch gepflegt
Themes
{{ count($this->themes) }}
1 aktiv (child)

Plugins

@foreach ($this->plugins as $p) @endforeach
PluginVersionStatusAuto-Update
{{ mb_strtoupper(mb_substr($p['name'], 0, 1)) }}
{{ $p['name'] }} {{ $p['slug'] }}
@if ($p['updates']) {{ $p['version'] }} → {{ $p['latest'] }} @else {{ $p['version'] }} @endif @if ($p['status'] === 'active')aktiv @else inaktiv@endif
@if ($p['updates']) @endif
@if ($updatesPending > 0)
{{ $updatesPending }} Updates verfügbar. Bulk-Update führt vorher automatisch einen Snapshot durch.
@endif

Themes

@foreach ($this->themes as $t) @endforeach
ThemeVersionStatus
{{ $t['name'] }} {{ $t['version'] }} @if ($t['status'] === 'active')aktiv @elseif ($t['status'] === 'parent')parent @else inaktiv@endif

Update-Policy

Auto-Update: Security-Patches
kritische sicherheits-updates automatisch einspielen
Auto-Update: Minor-Versionen
8.9.2 → 8.9.4 automatisch (gleiche major)
Auto-Update: Major-Versionen
8.x → 9.x — manuell empfohlen, breaking changes möglich
Snapshot vor jedem Update
automatisches backup vor plugin-update, rollback bei fehler
Staging-Test vor Production
update zuerst auf staging, smoke-test, dann auf prod
@endif {{-- ────── REDIRECTS ────── --}} @if ($tab === 'redirects')
@php $totalRedirects = count($this->redirects); $totalHits = array_sum(array_column($this->redirects, 'hits')); @endphp
Aktive Regeln
{{ $totalRedirects }}
301 + 302
Treffer / 24h
{{ number_format($totalHits, 0, ',', '.') }}
erfolgreich weitergeleitet
404-Quellen
7
potenzielle redirect-targets
Loop-Detection
0
keine zirkelschlüsse

Neue Redirect-Regel

Regex erlaubt mit Capture-Groups ($1, $2).
Externe URLs (https://...) erlaubt.
Query-String beibehalten
?utm_source=… überträgt sich auf target
Case-insensitive Match
/PRODUKT und /produkt matchen gleich

Aktive Regeln {{ $totalRedirects }}

nach hits sortiert
@foreach ($this->redirects as $r) @endforeach
VonNachCodeHits 24hLetzter Treffer
{{ $r['from'] }} {{ $r['to'] }} {{ $r['code'] }} {{ number_format($r['hits'], 0, ',', '.') }} {{ $r['last'] }}
@endif {{-- ────── STAGING ────── --}} @if ($tab === 'staging')

Staging-Environment

@if ($stagingActive) aktiv @else nicht angelegt @endif
.{{ $site->domain }}
URL: {{ $stagingSubdomain }}.{{ $site->domain }}
Staging auf gleichem Server spart Ressourcen — Lasttests ggf. eigenen Server.
HTTP-Basic-Auth
staging-zugriff per username + passwort schützen (verhindert google-indexierung)
robots.txt blockt alle Crawler
User-agent: * / Disallow: /
Media-Dateien beim Sync ausschließen
spart bandwidth, lädt /uploads lazy on-demand
Email-Sandbox (DISALLOW_OUTGOING_MAIL)
keine kunden-mails von staging versenden
Payment-Gateways auf Test-Mode
stripe + paypal automatisch im sandbox-mode
@if ($stagingActive) @endif
{{-- Sync actions --}}

Production → Staging

CLONE

Vollständiger Clone von Production: DB + Files + Uploads. URLs werden automatisch auf staging.{{ $site->domain }} umgeschrieben.

Schätzung~4 min · 2.8 GB
Letzter Lauf{{ $stagingLastSync }}

Staging → Production

PUSH

Selektive Übernahme: Code, DB-Tabellen oder beides. Auto-Snapshot von Production vor dem Push.

✓ Plugins ✓ Themes ✓ wp_options ✗ wp_posts ✗ wp_users
{{-- Recent activity --}}

Letzte Sync-Operationen

Push: Plugins + Themes nach Production · 142 MB übertragen
heute, 14:22 · Marie Weber · 3m 18s
Clone: Production → Staging · 2.8 GB · automatisch
heute, 06:00 · Scheduler · 4m 02s
Push abgebrochen: WP-Version-Mismatch (6.6 ↔ 6.4)
gestern, 18:14 · Marie Weber
Clone: Production → Staging · WooCommerce-Update testen
gestern, 11:42 · Marie Weber · 3m 56s
@endif {{-- ────── VHOST ────── --}} @if ($tab === 'vhost')

Virtual Host

{{ $site->domain }} · nginx
{{-- HTTP version --}}
@foreach (['http1' => 'HTTP/1.1', 'http2' => 'HTTP/2', 'http3' => 'HTTP/3 (QUIC)'] as $v => $lbl) @endforeach
HTTP/3 nutzt QUIC über UDP — schneller bei verlustbehafteten Verbindungen.
M
sek
HTTP → HTTPS Redirect
alle :80 anfragen mit 301 auf https umleiten
HSTS (Strict-Transport-Security)
browser merkt sich https-only für {{ number_format($hstsMaxAge / 86400, 0, ',', '.') }} tage
Brotli + gzip Kompression
text-assets vor auslieferung komprimieren
server_tokens off
nginx-version aus header entfernen
HTTP/2 Server Push
kritische assets im voraus an client streamen

Custom Headers

X-Frame-OptionsSAMEORIGIN
X-Content-Type-Optionsnosniff
Referrer-Policystrict-origin
Permissions-Policycamera=(), mic=()

Rate Limit

aktiv
Zone-Größe10 MB
/wp-login.php5 req / min
/xmlrpc.phpgeblockt
Burst20
@endif {{-- ────── SSL / TLS ────── --}} @if ($tab === 'ssl')

SSL / TLS Zertifikat

gültig · 54 tage
@foreach (['letsencrypt' => "Let's Encrypt", 'cloudflare' => 'Cloudflare Origin', 'custom' => 'Custom Upload'] as $v => $lbl) @endforeach
@foreach (['1.2' => 'TLS 1.2', '1.3' => 'TLS 1.3'] as $v => $lbl) @endforeach
OCSP Stapling
cert-revocation-status mit response cachen
Auto-Renewal
erneuerung 30 tage vor ablauf
CAA-Record-Check
vor neuausstellung dns-caa prüfen
Certificate Transparency Log
cert in öffentliches ct-log eintragen

Cert Details

AusstellerLet's Encrypt R3
SignaturECDSA P-256
Schlüsselgröße256 bit
Ausgestellt am2026-03-22
Läuft ab am2026-06-20
SSL-Labs RatingA+

Bisherige Zertifikate

AusgestelltAbgelaufenStatus
2026-03-222026-06-20aktuell
2025-12-212026-03-21ersetzt
2025-09-222025-12-21ersetzt
@endif {{-- ────── SSH / FTP ────── --}} @if ($tab === 'access')
{{-- SSH-Users --}}

SSH-Benutzer

key-only · password-auth aus
UsernamePublic KeyShellLetzter LoginScope
deployssh-ed25519 AAAAC3NzaC1l…7Q deploy@bergmann/bin/bashvor 14 min/var/www/bergmann
m.weberssh-ed25519 AAAAC3NzaC1l…1F m.weber@laptop/bin/bashheute, 09:42/var/www/bergmann
ci-botssh-rsa AAAAB3NzaC1y…XY github-actions/usr/bin/rrsyncvor 2hdeploy only
{{-- SFTP / FTP-Users --}}

SFTP / FTP-Benutzer

chroot · explicit-tls erzwungen
UsernameChrootProtokollQuotaLetzter Upload
redakteur/uploads/2026SFTP2.4 / 5 GBheute, 11:02
backup-puller/backupsSFTP128 GBheute, 03:00
{{-- Security policy --}}

Zugriffs-Policy

Password-Auth deaktiviert
SSH nur über Public-Key zulassen
Root-Login verbieten
PermitRootLogin no
fail2ban (3 Versuche → 1h Ban)
automatische IP-Sperre nach fehlversuchen
IP-Allowlist
SSH nur aus 10.10.0.0/16 + büro-WAN
2FA für SSH (Google Authenticator)
zusätzlich zum public key
@endif {{-- ────── WP + PHP (kompakte Hardcoded-Konfig nach Template) ────── --}} @if ($tab === 'wp')
{{-- wp-config.php card --}}

wp-config.php

/htdocs/wp-config.php
MB
MB
sek
WP_DEBUG
debug-modus & fehlerprotokoll
WP_CACHE
persistentes caching aktiv
DISALLOW_FILE_EDIT
datei-editor im wp-admin sperren
AUTOMATIC_UPDATER_DISABLED
automatische core-updates deaktiviert
FORCE_SSL_ADMIN
wp-admin nur über https
{{-- Datenbank + Salts side-by-side --}}

Datenbank

verbunden
{{ $showDbPassword ? 'verbergen' : 'anzeigen' }}

Sicherheits-Schlüssel (Salts)

AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY, NONCE_KEY & zugehörige Salts. Neu generieren meldet alle Benutzer ab.

Zuletzt rotiert14.03.2026
Schlüssel-Länge64 zeichen
Statusstark
{{-- Allgemeine WP-Einstellungen --}}

Allgemeine WordPress-Einstellungen

Suchmaschinen-Sichtbarkeit
von google & co. indexieren lassen
Registrierung erlauben
neue benutzer können sich registrieren
@endif @if ($tab === 'php')
{{-- php.ini main card --}}

php.ini

php {{ $site->php_version }} · fpm pool: bergmann
M
sek
M
M
sek
display_errors
php-fehler im browser anzeigen (nur dev)
opcache.enable
bytecode-cache aktiv
log_errors
fehler in error.log schreiben
allow_url_fopen
externe urls als datei öffnen
{{-- OPcache + Extensions --}}

OPcache

aktiv
Trefferquote99,2%
Speicher142 / 256 MB
Zwischengesp. Skripte4.218
opcache.revalidate_freq60 s

Aktive Erweiterungen

28 module
@foreach (['curl', 'gd', 'imagick', 'intl', 'mbstring', 'mysqli', 'opcache', 'redis', 'soap', 'zip', 'bcmath', 'exif'] as $ext) {{ $ext }} @endforeach + 16
@endif