Nach einem Kopiervorgang stimmen die Rechte nicht mehr. chmod 755 -R ist für Ordner richtig und für Dateien fast immer falsch – hier ist der Einzeiler, der beides trennt.
Ein rekursives chmod 755 setzt auf jeder Datei das Ausführungsbit. Bei Ordnern ist das nötig – ohne x lässt sich ein Verzeichnis nicht betreten. Bei Dateien ist es überflüssig und je nach Server-Konfiguration ein Sicherheitsproblem, etwa wenn das Ausführungsbit für Server Side Includes ausgewertet wird.
Richtig ist deshalb, Ordner und Dateien getrennt zu behandeln.
find . -type d -print0 | xargs -0 chmod 755 && \
find . -type f -print0 | xargs -0 chmod 644
Für TYPO3 sind andere Werte sinnvoll, weil Webserver und Shell-Benutzer dieselbe Gruppe brauchen. Das gesetzte Bit 2 vor der Ordnermaske ist das SGID-Bit: Neu angelegte Dateien erben damit die Gruppe des Ordners statt der des anlegenden Benutzers.
# TYPO3, zum Kopieren
find -type d -print0 | xargs -0 chmod 2770 && find -type f ! -perm /0111 -print0 | xargs -0 chmod 0660
! -perm /0111 schließt jede Datei aus, die irgendein Ausführungsbit gesetzt hat. Ohne diesen Zusatz verlieren Shell-Skripte und die Binärdateien unter vendor/bin/ ihr x und laufen nicht mehr – ein Fehler, der erst beim nächsten Deployment auffällt.
Nicht zu verwechseln mit ! -executable: Das fragt, ob der aufrufende Benutzer die Datei ausführen darf, und liefert als root fast überall etwas anderes. ! -perm /0111 fragt dagegen, ob überhaupt ein Ausführungsbit gesetzt ist – für Besitzer, Gruppe oder alle. Nur das ist unabhängig davon, wer den Befehl startet.
Diese beiden Werte gehören zusammen mit folderCreateMask und fileCreateMask in der TYPO3-Konfiguration gedacht – stehen sie dort anders, weichen neu erzeugte Dateien wieder ab.
-print0 und -0-print0 beendet jeden Dateinamen nicht mit einem Zeilenumbruch, sondern mit einem Null-Byte. Das Null-Byte ist das einzige Zeichen, das in einem Dateinamen nicht vorkommen kann, und deshalb das einzige sichere Trennzeichen. xargs -0 liest passend dazu.
Ohne die beiden Optionen zerlegt xargs Namen mit Leerzeichen – und setzt die Rechte dann auf Pfade, die es gar nicht gibt.
Der eigentliche Grund für xargs ist aber ein anderer, und er trifft jedes größere Projekt: Ein chmod 2770 * scheitert ab einer gewissen Menge mit Argument list too long, weil die Shell nur begrenzt viele Argumente übergeben kann. xargs zerlegt die Liste in so viele Aufrufe, wie nötig sind. Deshalb funktioniert der Einzeiler auch dort, wo die naheliegende Variante aufgibt.
Welche Werte richtig sind, hängt davon ab, wer außer der Gruppe noch lesen können muss. 2770 und 0660 sperren alle anderen aus – richtig auf einem eigenen Server, auf dem Webserver und Shell-Benutzer dieselbe Gruppe haben. Wo ein anderer Benutzer lesen muss – auf geteiltem Hosting wie bei Mittwald oder in einem Container mit abweichender UID – braucht es 2775 und 0664.
# Eigener Server, TYPO3\nfind -type d -print0 | xargs -0 chmod 2770 && find -type f ! -perm /0111 -print0 | xargs -0 chmod 0660\n\n# Geteiltes Hosting (etwa Mittwald) oder Container\nfind -type d -print0 | xargs -0 chmod 2775 && find -type f ! -perm /0111 -print0 | xargs -0 chmod 0664
Die Variante ohne ! -perm /0111 gibt es auch, sie setzt alle Dateien gleich. Ich rate davon ab: Sie ist kürzer, kostet aber die Ausführungsbits, und der Schaden zeigt sich erst später an einer Stelle, die mit Dateirechten nichts zu tun zu haben scheint.
find steigt nicht in symlinkte Verzeichnisse ab. Normalerweise ist das erwünscht – bei einem Deployment mit geteilten Verzeichnissen wird es zur Falle.
Bei Deployer liegen fileadmin, var/log und die Datenablage nicht im Release, sondern in einem gemeinsamen Verzeichnis; im Release stehen nur Symlinks darauf. Wer den Befehl im Release ausführt, korrigiert also genau die Verzeichnisse nicht, auf die es ankommt – und bekommt dabei keinen Fehler zu sehen. Der Durchlauf meldet Erfolg.
Zwei Wege: den Befehl im gemeinsamen Verzeichnis wiederholen, oder find mit -L aufrufen, damit es Symlinks folgt. Ich nehme den ersten, weil -L auch jedem anderen Symlink folgt und man dann leicht mehr anfasst als beabsichtigt.
cd /var/www/typo3/shared
find -type d -print0 | xargs -0 chmod 2770 && find -type f ! -perm /0111 -print0 | xargs -0 chmod 0660Wer keine Pipe braucht, kommt mit -exec und abschließendem + aus. Das sammelt ebenfalls mehrere Pfade pro Aufruf und ist damit genauso schnell:
find . -type d -exec chmod 2770 {} +
find . -type f -exec chmod 0660 {} +
Die xargs-Variante bleibt trotzdem nützlich, sobald noch etwas anderes dazwischen soll – filtern, zählen, protokollieren.