- Teil 1: Owncloud auf dem Raspberry Pi: Eine Geschichte in mehreren Teilen
- Teil 2: Ein Video in dem ihr sehen könnt, wie der Raspberry Pi sich ‘anfühlt’
- Teil 4: Speedup für statische Dateien
Zugriffszeiten ohne Cache
Obwohl sich die Datei nicht geändert hat, dauert der Zugriff auf dem langsamen Raspberry PI mehrere Sekunden, weil der Aufruf über owncloud/?app=files_sharing&getfile=css/sharing.css erfolgt. Der Webserver (nginx oder Apache) kann die Datei nicht direkt ausliefern. Anders ist es z.B. bei den jquery.js-Dateien: diese werden direkt ausgeliefert.
Obwohl die Dateien ‘not modified’ sind, dauert der Zugriff viel zu lange!
Mit Optimierung
Wenn der Webserver (nginx) sich direkt um die Dateien ‘kümmern’ kann, werden sie auch rasend schnell geliefert (139ms).
Wenn die Dateien sich bereits im Browser-Cache befinden, geht es sogar noch schneller:
Die Funktion loadfile()
Die Funktion loadfile() verwaltet .css und .js – Dateien der Plugins unter apps/. Vor der Auslieferung an den Web-Client werden zwei Variablen (%webroot% und %appswebroot% mit str_replace in den Dateien ersetzt. Dann berechnet die Funktion einem md5() – Hash und liefert an den Web-Client. Wenn sich die Datei nicht geändert hat, ist das eigentlich unnötig und kostet nur Prozessorzeit.
# http://localhost/owncloud/?app=files_imageviewer&getfile=css%2Fjquery.fancybox-1.3.4.css
# => /var/www/owncloud/apps/files_imageviewer/css/jquery.fancybox-1.3.4.css
#
# But lookout:
#owncloud/lib/base.php:
public static function loadfile(){
if(file_exists(OC::$APPSROOT . '/apps/' . OC::$REQUESTEDAPP . '/' . OC::$REQUESTEDFILE)){
if(substr(OC::$REQUESTEDFILE, -3) == 'css'){
$appswebroot = (string) OC::$APPSWEBROOT;
$webroot = (string) OC::$WEBROOT;
$filepath = OC::$APPSROOT . '/apps/' . OC::$REQUESTEDAPP . '/' . OC::$REQUESTEDFILE;
header('Content-Type: text/css');
OC_Response::enableCaching();
OC_Response::setLastModifiedHeader(filemtime($filepath));
$cssfile = file_get_contents($filepath);
---> $cssfile = str_replace('%appswebroot%', $appswebroot, $cssfile);
---> $cssfile = str_replace('%webroot%', $webroot, $cssfile);
OC_Response::setETagHeader(md5($cssfile));
header('Content-Length: '.strlen($cssfile));
echo $cssfile;
exit;
}elseif
...
}
Optimierung
Ersatz für loadfile()
Über ein Shell-Script (update_cache.sh) können wir die Ersetzung der Variablen einfach durchführen. Damit die Dateien von nginx nicht mehr komprimiert werden müssen, werden sie zusätzlich auch noch mit gzip komprimiert (nginx: gzip_static on;).
Das Script sollte zur Sicherheit einfach täglich (/etc/cron.daily) aufgerufen werden. Nach jeder Änderung an Owncloud (z.B. Installation von Add-Ons) sollte es erneut gestartet werden.
#!/bin/sh
#update_cache.sh
# call ist daily (/etc/cron.daily) and after modification
# of your owncloud-installation (new apps).
me=`basename $0`
fatal() {
msg="$1"
echo "$me:fatal:$msg"
exit 1
}
webroot="/owncloud"
appswebroot="$webroot"
webdir="/var/www/$webroot"
wwwusr="www-data:www-data"
mycache="mycache"
cachedir="$webdir/$mycache"
[ -d "$webdir" ] || fatal "webdir not found: $webdir"
[ -d "$cachedir" ] || mkdir $cachedir || fatal "cannot create: $cachedir"
cd "$cachedir" || fatal "cannot cd to $cachedir"
( cd $webdir && find . -name \*.css ) | grep -v "\./$mycache" |
while read f
do
d=`dirname "$f"`
[ -d "$d" ] || mkdir -p "$d" || fatal "cannot create $d"
echo "$f"
sed -e"s#%webroot%#$webroot#g" -e "s#%appswebroot%#$appswebroot#g" < "$webdir/$f" > $f
# Precompress for Mod_gzip
gzip <$f > $f.gz
done
chown -R $wwwusr $cachedirBeispiel
nachher: .fancybox-ie #fancybox-bg-n { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='%appswebroot%/apps/files_imageviewer/img/fancy_shadow_n.png', sizingMethod='scale'); }
---
vorher: .fancybox-ie #fancybox-bg-nw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/owncloud/apps/files_imageviewer/img/fancy_shadow_nw.png', sizingMethod='scale'); }
nginx-Konfiguration
Das Shell-Script kopiert die Dateien nach /var/www/owncloud/mycache. Jetzt müssen wir nginx nur noch mitteilen, was er mit diesen Dateien machen soll: Möglichst schnell ausliefern!
Normale Dateien, die keine Modifikation genötigen, werden direkt ausgeliefert.
# This block will catch static file requests, such as images, css, js # The ?: prefix is a 'non-capturing' mark, meaning we do not require # the pattern to be captured into $1 which should help improve performance # # MN: Added svg here #location ~* \.(?:ico|css|js|gif|jpe?g|png|svg|js)$ { location ~* /owncloud/(?:apps/[^/]+|core)/(?:css|js|img|img/[^/]+)/[^/]+\.(?:ico|css|js|gif|jpe?g|png|svg|js)$ { # Some basic cache-control for static files to be sent to the browser #expires max; #add_header Pragma public; #add_header Cache-Control "public, must-revalidate, proxy-revalidate"; expires 7d; add_header Pragma public; add_header Cache-Control "public"; }
location ~* /owncloud/mycache/ {
# Some basic cache-control for static files to be sent to the browser
expires 7d;
add_header Pragma public;
#add_header Cache-Control "public, must-revalidate, proxy-revalidate";
add_header Cache-Control "public";
}Die Zugriffe auf getfile() biegen wir einfach um. Dazu sind ein paar Tricks mit Regular Expressions nötig. Hier kann man mit $1 auf den Wert in er ersten Klammer (), mit $2 auf den Wert in der 2. Klammer, usw. zugreifen.
Das Statement ist etwas ‘tricky’.
location = /owncloud/ {
# hier nur requests auf /owncloud/ oder index.php
# http://localhost/owncloud/?app=files_imageviewer&getfile=css%2Fjquery.fancybox-1.3.4.css
if ($args ~ "app=([^&]+)&getfile=(css)%2F(.*\.css)$") {
set $app $1;
set $file $2/$3;
# redict to ownclod/mycache
# .css (and .css.gz) must be copied there!
# try_files not allowed here
rewrite ^/owncloud/.*$ /owncloud/mycache/apps/$app/$file last;
}
}Nebenwirkungen
Es gibt ein paar Nebenwirkungen:
- Das Shell-Script update_cache.sh muss aufgerufen werden
Sicherheit
.css – Dateien sind nicht sicherheitskritisch. Man sollte sich aber davor hüten, andere Dateien. oder gar die User-Files von Owncloud über den Webserver zu cachen!
Das wäre dann ein riesiges Sicherheitsproblem, weil nicht (mehr) authentifizierte Benutzer Zugriff bekommen.
Also: Vorsicht;
Fazit
Wie man sehen kann, wird owncloud auf dem Raspberry Pi rapide beschleunigt. Meiner Meinung nach sollten sich die Entwickler von Owncloud noch einmal überlegen, ob man mit den .css und .js-Dateien nicht etwas schlauer umgehen kann.







9. January 2013 at 23:13
Hi,
hast du diesen Tip schon den OwnCloud entwicklern mitgeteilt?
Ich möchte mir einen RaspberryPi aufsetzten mit OwnCloud und das wäre es natürlich cool, wenn ich diese Änderung nicht selbst in die aktuelle Version neu implementieren müßte…
Gruß
Eugen
24. January 2013 at 21:50
Richtig offiziell mitgeteilt habe ich denen das noch nicht.
Ich will erst die aktuelle Version von Owncloud ausprobieren, vielleicht hat sich da ja etwas geändert.
Aber: “Never change a running system” – es funktioniert bei mir gerade so gut.
5. February 2013 at 14:16
Hi, hab jetzt auch einen owncloud-server mit dem Raspi und nginx aufgesetzt.
Ich bin zwar kein Linux-Newbie mehr aber bei einigen deiner Ounkte steh ich ganz schön auf dem Schlauch.
wie kann ich den nginx anpassen (z.B. ssl, gzip, caches timeouts…) und wie bzw. wo muss ich die Änderungen die du in diesem Part zur Optimierung vorschlägst denn vornehmen?
Da blick ich noch nicht ganz durch.. wäre schön, wenn du mir weiterhelfen könntest.
7. June 2013 at 08:13
hallo
und nichts verstehe ^^
an welcher stelle sind denn die obigen scripts einzufügen?
hast du schon owncloud 5 getestet?
bei mir läuft owncloud 5 mit lighttpd mit php-apc aber ohne deine optimierung, da ich noch recht neu bei linux bin