Monday, October 28, 2013

Setting up owncloud with nginx

Owncloud is the main service running on my raspberry. I'm using it for file uploading and sharing, contact and calendar synchronization with Android and to store bookmarks.
All this is running on nginx web server, which should be more lightweight than Apache, mariaDB and php-fpm.

First you need to install few packages:
pacman -S mariadb mariadb-clients owncloud nginx php-fpm php-apcu

Let's have a look at configuration for each part.
Mysql/MariaDB:
Mysql configuration (for ArchlinuxARM) is stored in /etc/mysql/my.cnf but there is no need to change it, the default values are just fine. You only need to create new database and grant access for users.
I assume you have already set up root password for mysql and it is running. Log in with mysql -u root -p.
Now create database and preferably user for owncloud and grant access to him:
CREATE USER 'krisko'@'rasppi' IDENTIFIED BY 'password';
CREATE DATABASE IF NOT EXISTS owncloud;
GRANT ALL PRIVILEGES ON owncloud.* TO 'krisko'@'rasppi' IDENTIFIED BY 'password';

Note: I am using rasspi as my hostname, this is set in /etc/hosts (otherwise I would use IP address):
172.16.0.1    rasppi    rasppi

If you run into problems with connecting owncloud to DB, refer to troubleshooting section below.

Next step is to adjust configuration for php-fpm:
Configuration file is /etc/php/php-fpm.conf and again in this file only few things need to be set.
It is good to set listen directive to socket file (instead of IP:port), because communication between nginx and php-fpm will be faster that way (not that it really matters on Raspberry, but it is a good practise). Next thing is to set process manager values for handling children:
listen = /run/php-fpm/php-fpm.sock
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

This should be just good. Next file to edit is /etc/php/php.ini, here you can set open_basedir to allow access to owncloud, allow necessary modules and setup max upload file size for owncloud:
open_basedir = /srv/http/:/home/:/tmp/:/usr/share/pear/:/usr/share/webapps/owncloud/:/mnt/storage/owncloud/
disable_functions = show_source, system, shell_exec, passthru, exec, phpinfo, popen, proc_open, set_ini
memory_limit = 1024M
post_max_size = 1024M
upload_max_filesize = 1024M
extension=gd.so
extension=iconv.so
extension=intl.so
extension=mysqli.so
extension=mysql.so
extension=openssl.so
extension=pdo_mysql.so
extension=xmlrpc.so
extension=zip.so

Last file is /etc/php/conf.d/apcu.ini it handles php caching, although there isn't much to be cached with owncloud, but again it gives you some extra performance.
extension=apcu.so
; enable APC
apc.enabled=1
; The number of shared memory segments
apc.shm_segments=1
; The size of each shared memory segment
apc.shm_size=16M
; The number of seconds a cache entry is allowed to idle in a slot in case this
; cache entry slot is needed by another entry.
apc.ttl=259200

Nginx configuration:
I am using https connection to owncloud (this is highly recommended!), for this you need to create self signed certificates (you can refer e.g. to this page to create your certificates). My certificates are stored in /etc/nginx/certs, don't forget to limit read and write permissions on certificates (owner root, permissions 400).
Here's my complete /etc/nginx/nginx.conf configuration including php_cluster (will be described in another post) and transsmission setup:
#user html; #this is the default user

worker_processes  1;

#logging is handled by systemd
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

events {
    worker_connections  128;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    upstream php_cluster {
        #ip_hash;
        server 172.16.0.2:9000;
        server unix:/run/php-fpm/php-fpm.sock backup;
    }

#owncloud configuration
server {
        listen 443 ssl;
        server_name 192.168.0.5;

        ssl_certificate /etc/nginx/certs/server.crt;
        ssl_certificate_key /etc/nginx/certs/server.key;

        # Path to the root of your installation
        root /srv/http;

        client_max_body_size 10G; # set max upload size
        #fastcgi_buffers 64 4K;

        location = / {
            error_page 404 /owncloud/core/templates/404.php;
        }

        rewrite ^/owncloud/caldav(.*)$ /owncloud/remote.php/caldav$1 redirect;
        rewrite ^/owncloud/carddav(.*)$ /owncloud/remote.php/carddav$1 redirect;
        rewrite ^/owncloud/webdav(.*)$ /owncloud/remote.php/webdav$1 redirect;
        rewrite ^/core/(.*)$ /owncloud/core/$1 redirect;

        index index.php;
        error_page 403 = /owncloud/core/templates/403.php;
        error_page 404 = /owncloud/core/templates/404.php;

        location = /owncloud/robots.txt {
            allow all;
            log_not_found off;
            access_log off;
        }

        #owncloud disable access to crucial folders
        location ~ ^/owncloud/(data|config|\.ht|db_structure\.xml|README) {
                    deny all;
        }

        #transmission configuration
        location /transmission/ {
            proxy_pass_header X-Transmission-Session-Id;
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Forwarded-Server $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://127.0.0.1:9091/transmission/web/;
        }

        # Also Transmission specific
        location /rpc {
            proxy_pass         http://127.0.0.1:9091/transmission/rpc;
        }

        location ~ ^(.+?\.php)(/.*)?$ {
                try_files $1 = 404;

                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $document_root$1;
                fastcgi_param PATH_INFO $2;
                fastcgi_param HTTPS on;
                fastcgi_buffer_size 128k;
                fastcgi_buffers 256 16k;
                fastcgi_busy_buffers_size 256k;
                fastcgi_temp_file_write_size 256k;
                fastcgi_pass php_cluster;
                fastcgi_connect_timeout 90;
                fastcgi_send_timeout 90;
                fastcgi_read_timeout 90;
         }

        # Optional: set long EXPIRES header on static assets
        location ~* ^.+\.(jpg|jpeg|gif|bmp|ico|png|css|js|swf)$ {
                expires 30d;
                # Optional: Don't log access to assets
                access_log off;
        }
}
}

Last step is to create symbolic link in nginx docroot:
ll /srv/http/
lrwxrwxrwx 1 root root 27 Aug 14 19:42 owncloud -> /usr/share/webapps/owncloud

Now all should be set and prepared to create your owncloud user and set connection to DB. Start all processes (php-fpm, mysqld and nginx) and connect to URI: https://<ip>:<port:>/owncloud


Postsetup & Troubleshooting:

First thing to set after successful owncloud installation is cron job for file indexing. I am using crontab for this, so add to runtime users crontab (in this case user http) (with command crontab -e -u http):
*/2  *  *  *  * php -f /srv/http/owncloud/cron.php 1>/dev/null

Next you may want to save your owncloud configuration file, because this will be overwritten during next owncloud update.
cp /usr/share/webapps/owncloud/config/config.php{,.backup}

Failed to connect to database:
This is probably caused by wrong GRANT for user accessing the database. To find out which user needs to have grants, enable DB logging and try to access database. Then look in the logs and add GRANT for user if needed.
#enable logging
SET global general_log = 1;
SET global log_output = 'table';
#select from log table
select * from mysql.general_log;
#disable logging
SET global general_log = 0;

There should be access like this:
| 2013-10-21 11:22:13.337566 | [krisko] @ rasppi [172.16.0.1] |      4230 |         1 | Connect      | krisko@rasppi as anonymous on owncloud

from this you can see that GRANT for user krisko@rasppi needs to be set (if isn't).
Don't forget to disable logging afterwards.
Here are some usefull mysql commands:
select user,host from mysql.user; 
show grants for krisko@rasppi;
show grants for current_user; 

7 comments:

  1. Thank you for doing this blog post. This guide has helped me to setup owncloud to my raspberry pi.

    Though I'm having some issues with performance. Pages takes to load around 30 seconds or more. I think it's because php-apc not running properly. I've got almost similar config as you, besides nginx.config file. Do you know what could be the cause of this issue?

    Here's my ngnix.conf too if you want to check it out: http://pastebin.com/0u5qnder

    Thank you.

    ReplyDelete
    Replies
    1. Hi, I'm glad this guide was helpful for you.
      You can check if you have apc enabled with 'php -i | grep -i apc.enabled', but don't expect much performance of it.
      My owncloud loads page in 12-15 seconds, the difference is probably that I have my raspberry overclocked to max performance:

      arm_freq=1000
      core_freq=500
      sdram_freq=500
      over_voltage=6

      Delete
    2. Thank you for your quick response.

      Yes. You were right, my apc was working correctly. Maybe I just expected owncloud to be super fast on Raspberry Pi. Silly me.

      Anyways, I overclocked my RPI as suggested and get around same performace with my setup.

      Only thing, that bothers me now is sync speed, which is really slow. Testing it locally, so I'd expect it to be a bit faster then this. How about you?

      Also, I get this error on my owncloud: Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken.

      Which is weird, since WebDAV seems to be working okay. Maybe my nginx.conf is missing something, not sure.

      Anyways, thanks again for this guide and your help. Cheers.

      Delete
    3. Hi, this webdav error is probably caused by some misconfiguration in nginx. Although it does work, so it doesn't really bother me :)

      Later I'll post how to run owncloud with php-fpm cluster, so there will be noticeable performance improvement.

      Delete
    4. Looking forward for that. Thank you for your time and effort.

      Delete
  2. very nice blog! recently I am installing owncloud 7.0.2 on raspberry pi, I have the same config as you, (archlinux + mariadb + nginx + php-fpm), but after I log in, it always directly to http://192.168.1.52/owncloud/index.php/apps/files/ and shows the error 404.
    I have been struggled on this problem for weeks, can you help me a little with that ? Thanks

    ReplyDelete
  3. Hi Krisko,
    I'm pretty sure I used this post as a reference for my setup over a year ago. And, it was a great help as I'm no Php buff! I never managed to work the socket very well, so stuck to the standard approach.
    I'm now after latest update of Archlinux and Owncloud i'm getting server timeout, could be heat. Got any other ideas, what it could be?
    I was looking into nginx-x-accel-redirect: https://doc.owncloud.org/server/7.0/admin_manual/configuration/serving_static_files_configuration.html#nginx-x-accel-redirect

    ReplyDelete