Jailed ownCloud in FreeBSD 10.1

Moving to FreeBSD

I’ve had a ownCloud installation running for a good year or so on my unRAID server. As for ownCloud itself, I’ve been very happy with it. Managing non-unRAID things on unRAID though… not so fun. With that said, I’ve decided to move my installation to a FreeBSD 10.1 based system running on a Mac Mini. This box already services some minor things such as Murmur for our World of Warcraft guild The ORLY Factor, Git, etc. but is nearly idle most of the time.

Jail It!

A great feature of FreeBSD is jails. With a jail you can isolate an environment from the rest of the system such that if it comprimised, the rest of the system is not. Installations do not much with each other as well. All great stuff – lets put ownCloud in a jail!

ezjail

For jail management I choose ezjail. This makes working with jails… er, a bit eaezsier.

Install & Prepare ezjail

I did not have ezjail already installed. Below are the steps I took to get ezjail installed and prepped on the system:

Install (alternatively, cd /usr/ports/sysutils/ezjail && make install clean):

sudo pkg install ezjail

Create a base jail & update it:

sudo ezjail-admin install -sp   
sudo ezjail-admin update -P

A few entries need added to /etc/rc.conf:

cloned_interfaces="${cloned_interfaces} lo1"    
ifconfig_bge0_alias="inet 132.0.0.248 netmask 255.255.255.255"
ezjail_enable="YES"

The ‘cloned_interfaces’ allows loopback isolation in the jail, while the second provides a new IP alias. Lastly, enable ezjail. Note that the interface name will vary depending on hadware. In this case, the NIC is bge0. This can be found by simply inspecting ifconfig.

Create the ownCloud Jail

Now it’s time to create an actual jail for ownCloud:

sudo ezjail-admin create owncloud 132.0.0.248
cp /etc/resolv.conf /usr/jails/owncloud/etc/
service ezjail start

Validate our jail is created & on the right IP:

jls
   JID  IP Address      Hostname                      Path
 1  132.0.0.248     owncloud                      /usr/jails/owncloud

Setting up the jailed ownCloud

Time to set up ownCloud and it’s dependencies in the ‘owncloud’ jail! First, attach to the jail’s console:

sudo ezjail-admin console owncloud

Next, some software installs & configures. This portion is heavily based on ownCloud 7 on FreeBSD 10.1 though I make various tweaks and have installed ownCloud 8.x.

MySQL Installation

Install and start Percona MySQL. The standard version of MySQL should work fine as well.

pkg install perl5 percona56-server
service mysql-server start

Create a standard install (Most if not all defaults can be accepted here):

mysql_secure_installation

The file /var/db/mysql/my.cnf has all the gory details.

Create a datbase and user for ownCloud:

mysql -p -e "create database owncloud;"
mysql -p -e "grant all on owncloud.* to 'owncloud'@'localhost' identified by 'CHANGE_THIS_PASSWORD'; flush privileges;"

PHP / PHP-FPM

Install required packages

 pkg install php55-extensions php55-mysql php55-pdo_mysql php55-zlib php55-openssl php55-bcmath php55-gmp php55-gd php55-curl php55-ldap php55-exif php55-fileinfo php55-mbstring php55-gmp php55-bz2 php55-zip php55-mcrypt

Create a PHP-FPM configuration in /usr/local/etc/php-fpm.conf. This file will already exist. Ensure at least the following is completed as per your needs:

[global]
pid = run/php-fpm.pid  
error_log = log/php-fpm.log

[owncloud]
listen=/var/run/php-fpm.socket  
listen.owner=www  
listen.group=www  
listen.mode=0666  
listen.backlog=-1  
listen.allowed_clients=127.0.0.1  
user=www  
group=www  
pm=dynamic  
pm.max_children=4  
pm.start_servers=1  
pm.min_spare_servers = 1  
pm.max_spare_servers = 2  
pm.max_requests = 500  
env[HOSTNAME] = $HOSTNAME  
env[PATH] = /usr/local/bin:/usr/bin:/bin  
env[TMP] = /tmp  
env[TMPDIR] = /tmp  
env[TEMP] = /tmp  

(Note: Tweak to your needs of course)

In order to avoid weird filename issues, ensure our default charset is UTF-8. Copy over /usr/local/etc/php.ini-production to /usr/local/etc/php.ini and find default_charset. Remove the comment line and make sure the value is “utf-8”. Example:

default_charset = "utf-8"

Start the service

service php-fpm start

Nginx

For a webserver, nginx is great. It’s lightweight and fast.

Install

sudo pkg install nginx

Create a configuration @ /usr/local/etc/nginx/nginx.conf. As an example, here is mine:

user  www;  
worker_processes  1;

pid        /var/run/nginx.pid;

events {  
        worker_connections  1024;
}

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

        sendfile                on;
        server_tokens           off;

        #
        # Generated with https://mozilla.github.io/server-side-tls/ssl-config-generator/
        # 2015-Feb-23
        #
        ssl_certificate /path/to/my/SSLCert.pem;
        ssl_certificate_key /path/to/my/SSLCertPrivateKey.pem;
        ssl_session_timeout 5m;
        ssl_session_cache shared:SSL:50m;

        # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
        ssl_dhparam /path/to/my/DHParam.pem;

        # modern configuration. tweak to your needs.
        ssl_protocols TLSv1.1 TLSv1.2;
        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';
        ssl_prefer_server_ciphers on;

        # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
        add_header Strict-Transport-Security max-age=15768000;
        # End of Generated

        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;
        add_header X-DEMENTiA indeed;
        ssl_stapling on;
        ssl_stapling_verify on;

        gzip               off;
        # See https://github.com/owncloud/client/issues/1291
        #gzip              on;
        #gzip_types        text/css text/javascript text/mathml text/plain text/xml application/x-javascript application/atom+xml application/rss+xml application/xhtml+xml image/svg+xml;

    upstream php-handler {
            server unix:/var/run/php-fpm.socket;
    }

        server {
                listen 80;
                server_name nu.l33t.codes;
                return 301 https://nu.l33t.codes$request_uri;

                add_header X-Frame-Options "SAMEORIGIN";
        }

        server {
                listen 443 ssl;

                server_name nu.l33t.codes;
                root /usr/local/www/owncloud;
                index index.php;

                client_max_body_size 10G;
                fastcgi_buffers 64 4K;
                add_header X-Frame-Options "SAMEORIGIN";                

                error_page 403 /core/templates/403.php;
                error_page 404 /core/templates/404.php;

                error_log /var/log/nginx-owncloud.error.log;

        location ~ ^/(?:\.htaccess|data|config|db_structure\.xml|README){
            deny all;
        }

            location ~* ^/(favicon.ico|robots.txt) {
            allow all;
            log_not_found off;
            access_log off;
                }

            rewrite ^/caldav(.*)$ /remote.php/caldav$1 redirect;
            rewrite ^/carddav(.*)$ /remote.php/carddav$1 redirect;
            rewrite ^/webdav(.*)$ /remote.php/webdav$1 redirect;
                location /shares {
                        if (!-f $request_filename) {
                                rewrite ^/shares /dav.php last;
                                break;
                        }

                        if (!-d $request_filename) {
                                rewrite ^/shares /dav.php last;
                                break;
                        }
                }

            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_param MOD_X_ACCEL_REDIRECT_ENABLED on;
                    fastcgi_pass php-handler;
            }

        }
}

Ensure your /usr/local/etc/nginx/fastcgi_params looks correct. Again, here is my configuration:

fastcgi_param  QUERY_STRING       $query_string;  
fastcgi_param  REQUEST_METHOD     $request_method;  
fastcgi_param  CONTENT_TYPE       $content_type;  
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;  
fastcgi_param  REQUEST_URI        $request_uri;  
fastcgi_param  DOCUMENT_URI       $document_uri;  
fastcgi_param  DOCUMENT_ROOT      $document_root;  
fastcgi_param  SERVER_PROTOCOL    $server_protocol;  
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;  
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;  
fastcgi_param  REMOTE_PORT        $remote_port;  
fastcgi_param  SERVER_ADDR        $server_addr;  
fastcgi_param  SERVER_PORT        $server_port;  
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;  

Start nginx

service nginx start

ownCloud

Finally! Time to install ownCloud itself. As of this writing, I am installing version 8.0.

cd /usr/local/www
fetch https://download.owncloud.org/community/owncloud-8.0.0.tar.bz2
tar xvf owncloud-8.0.0.tar.bz2
chown -R www:www owncloud
find owncloud -type d -exec chmod 751 {} \;
find owncloud -type f -exec chmod 444 {} \;
rm owncloud-8.0.0.tar.bz2

rc.conf

I want everything installed to start automatically, so a few entries need added to /etc/rc.conf:

mysql_enable="YES"  
php_fpm_enable="YES"  
nginx_enable="YES"  

Done!

That’s it! ownCloud is up and running! A few changes to the firewall to NAT to the new jailed IP and I’m in business.

Update

  1. Disabled gzip completely for now in nginx configuration. Having gzip enabled was causing some syncs to fail. See No E-Tag received from server, check Proxy/Gateway. I’d like gzip enabled so I’ll mess with this more as I have time.

Additional Resources