Alle Konfigurationen sind auf die Zeitzone
Europe/Zurich abgestimmt.
1. Vorbereitung & System
Einloggen als ubuntu-User (Standard bei Ubuntu-Servern). System updaten und Zeitzone setzen:
sudo apt update && sudo apt upgrade -y
sudo timedatectl set-timezone Europe/Zurich
2. WordPress mit Podman (rootless, Dateien unter /srv)
WordPress und MariaDB laufen in einem gemeinsamen Pod. Die Web-Dateien liegen unter /srv/wordpress, die DB-Daten unter /srv/wp-db.
# Verzeichnisse anlegen und Berechtigungen setzen
sudo mkdir -p /srv/wp-db /srv/wordpress
sudo chown -R $USER:$USER /srv/wp-db /srv/wordpress
# Pod erstellen (rootless), WordPress intern auf Port 80, extern 8080
podman pod create --name wp -p 8080:80
# MariaDB starten (persistente Daten in /srv/wp-db)
podman run -d --pod wp --name wp-db \
-e MYSQL_ROOT_PASSWORD=geheim \
-e MYSQL_DATABASE=wordpress \
-e MYSQL_USER=wpuser \
-e MYSQL_PASSWORD=wppass \
-v /srv/wp-db:/var/lib/mysql \
mariadb:10.11
# WordPress starten (Code/Uploads in /srv/wordpress)
podman run -d --pod wp --name wordpress \
-e WORDPRESS_DB_HOST=127.0.0.1 \
-e WORDPRESS_DB_USER=wpuser \
-e WORDPRESS_DB_PASSWORD=wppass \
-e WORDPRESS_DB_NAME=wordpress \
-v /srv/wordpress:/var/www/html \
wordpress:latest
# Test
# http://<SERVER-IP>:8080
3. Cockpit Web-GUI
Cockpit ist die Admin-Oberfläche für Server und Container (inkl. Podman-Plugin).
sudo apt install -y cockpit cockpit-podman
sudo systemctl enable --now cockpit.socket
# Zugriff: https://<SERVER-IP>:9090
4. Traefik als Reverse Proxy
Traefik läuft rootful und bindet Ports 80/443 (Let’s Encrypt). WordPress bleibt rootless auf Port 8080.
sudo mkdir -p /etc/traefik/dynamic
sudo touch /etc/traefik/acme.json
sudo chmod 600 /etc/traefik/acme.json
/etc/traefik/traefik.yml:
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
providers:
file:
directory: "/etc/traefik/dynamic"
watch: true
certificatesResolvers:
letsencrypt:
acme:
email: deine-mail@example.com
storage: /etc/traefik/acme.json
httpChallenge:
entryPoint: web
accessLog:
filePath: "/var/log/traefik/access.log"
format: common
/etc/traefik/dynamic/wp.yml:
http:
routers:
wp:
rule: "Host(`deine-domain.tld`)"
entryPoints: ["websecure"]
service: wp-svc
tls:
certResolver: letsencrypt
wp-redirect:
rule: "Host(`deine-domain.tld`)"
entryPoints: ["web"]
middlewares: ["https-redirect"]
service: wp-svc
middlewares:
https-redirect:
redirectScheme:
scheme: https
permanent: true
services:
wp-svc:
loadBalancer:
servers:
- url: "http://host.containers.internal:8080"
Hinweis: host.containers.internal erlaubt Traefik (Host) den Zugriff auf den rootless-exponierten Port 8080.
5. Autostart mit Quadlets
Quadlets starten Pod/Container per systemd im User-Kontext (rootless).
mkdir -p ~/.config/containers/systemd
~/.config/containers/systemd/wp.pod:
[Pod]
Name=wp
PublishPort=8080:80
~/.config/containers/systemd/wp-db.container:
[Container]
Image=mariadb:10.11
Name=wp-db
Pod=wp
Environment=MYSQL_ROOT_PASSWORD=geheim
Environment=MYSQL_DATABASE=wordpress
Environment=MYSQL_USER=wpuser
Environment=MYSQL_PASSWORD=wppass
Volume=/srv/wp-db:/var/lib/mysql
RestartPolicy=always
~/.config/containers/systemd/wordpress.container:
[Container]
Image=wordpress:latest
Name=wordpress
Pod=wp
Environment=WORDPRESS_DB_HOST=127.0.0.1
Environment=WORDPRESS_DB_USER=wpuser
Environment=WORDPRESS_DB_PASSWORD=wppass
Environment=WORDPRESS_DB_NAME=wordpress
Volume=/srv/wordpress:/var/www/html
RestartPolicy=always
Aktivieren:
systemctl --user daemon-reload
systemctl --user enable --now wp.pod wp-db.container wordpress.container
loginctl enable-linger $USER
6. Fail2Ban (SSH & WordPress)
Fail2Ban drosselt Fehlversuche anhand des Traefik-Access-Logs.
/etc/fail2ban/filter.d/traefik-wp-login-post.conf:
[Definition]
failregex = ^<HOST> .* "POST /wp-login\.php.*" .* (200|403)
ignoreregex = ^<HOST> .* "POST /wp-login\.php.*" .* 30[123] .*/wp-admin/
/etc/fail2ban/filter.d/traefik-xmlrpc.conf:
[Definition]
failregex = ^<HOST> .* "POST /xmlrpc\.php.*" .* 200
ignoreregex =
Jail-Beispiel (/etc/fail2ban/jail.d/traefik-wp.conf):
[traefik-wp-login-post]
enabled = true
port = http,https
filter = traefik-wp-login-post
logpath = /var/log/traefik/access.log
maxretry = 6
findtime = 10m
bantime = 1h
[traefik-xmlrpc]
enabled = true
port = http,https
filter = traefik-xmlrpc
logpath = /var/log/traefik/access.log
maxretry = 4
findtime = 10m
bantime = 1h
sudo systemctl restart fail2ban
sudo fail2ban-client status traefik-wp-login-post
7. Firewall-Härtung
Öffne nur die benötigten Ports.
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 9090/tcp
sudo ufw enable
sudo ufw status
8. Dateizugriff per SFTP
- Web-Dateien:
/srv/wordpress(Themes, Plugins, Uploads) - DB-Daten:
/srv/wp-db
9. Fazit
- Podman (rootless): isolierter, sicherer Betrieb
- Dateien in
/srv: einfacher SSH/SFTP-Zugriff, persistente Daten - Traefik: automatisches HTTPS & Routing
- Cockpit: komfortable Server-GUI
- Fail2Ban + UFW: wirksame Grundhärtung
Damit betreibst Du WordPress sicher und modern – optimiert für Zürich.