Backup-Tools neben PHP-Frameworks — .htaccess-Konflikte lösen

htaccess-Konflikte mit Backup-Tools erkennen und lösen

Du installierst MySQLDumper oder ein anderes Backup-Tool in einem Unterverzeichnis deiner Website — und bekommst nur eine 404-Seite oder wirst auf die Startseite umgeleitet. Der Grund: Dein PHP-Framework (CodeIgniter, Laravel, WordPress, Symfony) fängt alle Anfragen über URL-Rewriting ab und leitet sie an seinen eigenen Router weiter. Das Backup-Tool wird nie erreicht.

Das Grundproblem: URL-Rewriting

Moderne PHP-Frameworks nutzen mod_rewrite in der .htaccess, um alle Anfragen an eine zentrale index.php zu leiten. Das sieht typischerweise so aus:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]

Die Bedingungen !-f (keine Datei) und !-d (kein Verzeichnis) sollten eigentlich dafür sorgen, dass existierende Verzeichnisse durchgelassen werden. In der Praxis greift das aber oft nicht — weil die Framework-.htaccess weitere Regeln enthält, weil das Verzeichnis zwar existiert aber die Datei darin nicht direkt aufgerufen wird, oder weil verschachtelte Rewrite-Regeln sich gegenseitig überschreiben.

Die universelle Lösung

Das Muster ist bei allen Frameworks gleich: Du fügst eine RewriteCond hinzu, die dein Backup-Verzeichnis explizit vom Rewriting ausschließt. Die Regel muss vor der eigentlichen RewriteRule stehen.

# Backup-Verzeichnis vom Rewriting ausschließen
RewriteCond %{REQUEST_URI} !^/mysqldumper(/|$)

Das (/|$) am Ende matched sowohl /mysqldumper/ als auch /mysqldumper ohne Trailing Slash.

CodeIgniter

CodeIgniter hat eine der aggressivsten Rewrite-Konfigurationen. Die Standard-.htaccess im Root-Verzeichnis:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [QSA,L]

Lösung: RewriteCond-Ausnahme hinzufügen

RewriteEngine On

# Backup-Tool vom Rewriting ausschließen
RewriteCond %{REQUEST_URI} !^/mysqldumper(/|$)

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [QSA,L]

Achtung bei CodeIgniter 4: CI4 hat die .htaccess im public/-Verzeichnis statt im Root. Die Anpassung muss dort erfolgen:

# public/.htaccess (CodeIgniter 4)
RewriteEngine On

RewriteCond %{REQUEST_URI} !^/mysqldumper(/|$)

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [QSA,L]

Das Backup-Tool liegt dann unter /public/mysqldumper/ auf dem Dateisystem, erreichbar unter https://deinedomain.de/mysqldumper/.

Laravel

Laravel routet alles durch public/index.php. Die relevante .htaccess liegt in public/:

# public/.htaccess (Laravel Standard)
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

Und in public/.htaccess:

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^ index.php [L]
</IfModule>

Lösung: Ausnahme in public/.htaccess

<IfModule mod_rewrite.c>
  RewriteEngine On

  # Backup-Tool ausschließen
  RewriteRule ^mysqldumper(/|$) - [L]

  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^ index.php [L]
</IfModule>

Hier nutzen wir eine andere Technik: RewriteRule ^mysqldumper - [L] bedeutet „wenn die URL mit mysqldumper beginnt, tue nichts (-) und stoppe die Regelverarbeitung ([L])“. Das ist bei Laravel oft zuverlässiger als eine RewriteCond.

Das Backup-Tool installierst du in public/mysqldumper/.

WordPress

WordPress hat seine Rewrite-Regeln im Root-Verzeichnis. Sie werden automatisch generiert und sehen so aus:

# BEGIN WordPress
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.php$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.php [L]
</IfModule>
# END WordPress

Lösung: Ausnahme VOR dem WordPress-Block

# Backup-Tool vom WordPress-Rewriting ausschließen
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteRule ^mysqldumper(/|$) - [L]
</IfModule>

# BEGIN WordPress
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.php$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.php [L]
</IfModule>
# END WordPress

Wichtig: Setze die Ausnahme vor den # BEGIN WordPress-Kommentar. WordPress überschreibt alles zwischen # BEGIN WordPress und # END WordPress wenn du die Permalink-Einstellungen speicherst. Alles davor bleibt erhalten.

Symfony

Symfony nutzt je nach Version unterschiedliche Verzeichnisstrukturen:

  • Symfony 3: web/.htaccess
  • Symfony 4+: public/.htaccess

Lösung für Symfony 4+ (public/.htaccess)

<IfModule mod_rewrite.c>
  RewriteEngine On

  # Backup-Tool ausschließen
  RewriteRule ^mysqldumper(/|$) - [L]

  RewriteCond %{REQUEST_URI}::$0 ^(/.+)/(.*)::\2$
  RewriteRule .* %1/ [R=301,L]

  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^ index.php [L]
</IfModule>

Das Backup-Tool kommt in public/mysqldumper/.

Das allgemeine Muster

Egal welches Framework — der Ansatz ist immer einer von zwei Wegen:

Variante A: RewriteRule mit Stop-Flag

# VOR den Framework-Regeln einfügen:
RewriteRule ^mysqldumper(/|$) - [L]

Bedeutet: Wenn die URL mit mysqldumper beginnt, stoppe sofort. Kein Rewriting, keine Weiterleitung.

Variante B: RewriteCond als Ausnahme

# Direkt VOR der RewriteRule des Frameworks:
RewriteCond %{REQUEST_URI} !^/mysqldumper

Bedeutet: Wende die nächste RewriteRule nur an, wenn die URL nicht mit /mysqldumper beginnt.

Variante A ist in der Regel zuverlässiger, weil sie unabhängig von der Position funktioniert. Variante B ist fragiler — sie gilt nur für die unmittelbar folgende RewriteRule.

Mehrere Verzeichnisse ausschließen

Wenn du mehrere Tools oder Verzeichnisse vom Rewriting ausschließen willst:

# Variante A: Mehrere RewriteRules
RewriteRule ^mysqldumper(/|$) - [L]
RewriteRule ^phpmyadmin(/|$) - [L]
RewriteRule ^adminer(/|$) - [L]

# Variante B: Eine RewriteCond mit Alternation
RewriteCond %{REQUEST_URI} !^/(mysqldumper|phpmyadmin|adminer)(/|$)

Troubleshooting

Änderung zeigt keine Wirkung

  • Browser-Cache leeren (oder Inkognito-Modus nutzen)
  • Prüfen, ob mod_rewrite aktiv ist: apache2ctl -M | grep rewrite
  • Prüfen, ob AllowOverride All in der vHost-Konfiguration gesetzt ist
  • Apache neustarten nach Änderungen an der vHost-Config: systemctl restart apache2

Rewrite-Debugging aktivieren

# In der vHost-Konfiguration (nicht .htaccess!):
LogLevel alert rewrite:trace3

# Dann im Error Log:
tail -f /var/log/apache2/error.log

Das zeigt dir Schritt für Schritt, welche Rewrite-Regeln greifen und warum. Vergiss nicht, das Log-Level danach wieder zurückzusetzen — trace3 erzeugt sehr viel Output.

Eigene .htaccess im Backup-Verzeichnis

Zusätzlich zur Ausnahme im Framework kannst du eine eigene .htaccess im Backup-Verzeichnis anlegen, die das Rewriting explizit deaktiviert:

# mysqldumper/.htaccess
RewriteEngine Off

Das ist ein guter Fallback, falls die Ausnahme in der Haupt-.htaccess nicht greift.

Mehr zur Installation und Ersteinrichtung von MySQLDumper findest du im Installations-Guide.