Hi,
this Tuturial describes the steps to setup owncloud on top of debian/raspian with lighttpd as webserver and https encryption with certificates sign by Let’s encrypt campain.
Operating System
Install a minimal debian jessie system.
Login as root. On raspbian login as user pi change to root.
1 | pi@raspown ~ $ sudo su - |
If you want to setup the cloud by ssh and you want to login with root an password authentification set “PermitRootLogin” to “yes” in /etc/ssh/sshd_config.
Don’t forget to set it back to “without-password” after finishing.
Install required packages
1 2 3 4 5 6 | root@raspown:~ # apt-get -y install php5 php5-common php5-gd php-xml-parser php5-intl php5-json php5-mcrypt root@raspown:~ # apt-get -y install php5-sqlite php5-mysql php5-pgsql smbclient php5-curl curl libcurl3 libcurl3-dev root@raspown:~ # apt-get -y install lighttpd php5-cgi root@raspown:~ # apt-get -y remove apache2 apache2-bin apache2-data libaprutil1-dbd-sqlite3 libaprutil1-ldap liblua5.1-0 root@raspown:~ # apt-get -y install python-pip root@raspown:~ # apt-get -y install git bash |
For Raspbian Users. Do not start graphical desktop, just boot in text mode
1 2 | root@raspown:~ # systemctl get-default root@raspown:~ # systemctl set-default -f multi-user.target |
Set the hostname respectily full qualified domain name
1 | root@raspown:~ # hostnamectl set-hostname yourhost.yourdomain.net |
Configure a static IP Address. Disable old (init) config style by saving /etc/network/interfaces and creating an empty file
1 2 | root@raspown:~ # mv /etc/network/interfaces /etc/network/interfaces.save root@raspown:~ # touch /etc/network/interfaces |
Setting up eth0. Create a file /etc/systemd/network/eth0.network, Name it as you want.
[Match]
# You can also use wildcards. Maybe you want enable dhcp
# an all eth* NICs
Name=eth0
[Network]
#DHCP=v4
# static IP
# 192.168.100.2 netmask 255.255.255.0
Address=192.168.100.2/24
Gateway=192.168.100.1
DNS=192.168.100.1
and enable systemd-networkd and resolved
1 2 | root@raspown:~ # systemctl enable systemd-networkd.service root@raspown:~ # systemctl enable systemd-resolved.service |
Define DNS Server. You can add the DNS Server either in the Network section of the NIC adapter config (see above) or in /etc/systemd/resolved.conf
Create a symlink
1 2 | root@raspown:~ # mv /etc/resolv.conf /etc/resolv.conf.save root@raspown:~ # ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf |
Enable lighttpd on Port 80
Start the webserver and see if its running
1 2 3 4 | root@raspown # lighty-enable-mod fastcgi-php root@raspown # systemctl enable lighttpd.service root@raspown # systemctl start lighttpd.service root@raspown # journalctl -xn |
https certificates
Lets Encrypt
Create the certificates. Get project sources
1 | root@raspown:~ # git clone https://github.com/letsencrypt/letsencrypt |
Install additional packages needed by letsencrypt create the virtual environment. Do not use the standard shell on Debian 8 based systems. Also the Python Package Index must be reachable:
1 | root@raspown:~ /letsencrypt # bash letsencrypt-auto -v |
If you want to use your own key and signing request:
Create your server key and csr by openssl. Do not enter a challenge password at the end of the creation process otherwise lighttpd will prompt at each start for it.
1 | root@raspown:~ # mkdir -p /etc/lighttpd/ssl |
Create Key and Signing request. For a better quality of random numbers consider to generate the key on a “real” PC. Note: The CommonName and the the subjectAltName of the siging request must set to the domain name to which the certificate should belongs to. The output format of the csr must set to DER.
Create an x509 v3 exentension file /etc/lighttpd/ssl/ssl_v3.cfg
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[ v3_req ]
basicConstraints = CA:FALSE
nsCertType = server,client
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage=serverAuth,clientAuth,emailProtection,codeSigning,timeStamping
subjectAltName = @alt_names
[alt_names]
DNS.1 = yourhost.yourdomain.net
# DNS.2 =
[req_distinguished_name]
Generate Key and signing request
1 2 3 4 5 6 7 8 9 10 11 | root@raspown:~ # openssl req -nodes -new -newkey rsa:2048 -sha256 -outform DER -out /etc/lighttpd/ssl/server.der -keyout /etc/lighttpd/ssl/server.key -subj '/C=DE/ST=Franken/L=Nuremberg/O=Your Company/OU=Your OU/emailAddress=webmaster@yourdomain.net/CN=yourhost.yourdomain.net/' -config /etc/lighttpd/ssl/ssl_v3.cfg # Sets the following parameters # Country Name (2 letter code) [AU]:DE # State or Province Name (full name) [Some-State]:Franken # Locality Name (eg, city) []:Nuremberg # Organization Name (eg, company) [Internet Widgits Pty Ltd]:Your Company # Organizational Unit Name (eg, section) []:Your OU # Common Name (e.g. server FQDN or YOUR name) []:yourhost.yourdomain.net # Email Address []:webmaster@yourdomain.net # A challenge password []: # An optional company name []: |
Verify that your csr contains all your parameter:
1 | root@raspown:~ # openssl req -inform der -in /etc/lighttpd/ssl/server.der -noout -text |
Get the certificate from the LetsEncrypt CA. This example is based on the webroot authenticator to validate the domain (DV). Means, the letsencrypt-auto script creates a file in the webroot of your webserver which will be read during the domain validation process by the LetsEncrypt webservice.
Before you call the script make sure your webserver is reachable from the internet by your dns name at port 80 (letsencrypt http-01 challenge).
If your Webserver is behind a DSL Router ensure you have configured a port forwarding rule from port 80 to the internal ip address of your webserver. The default lighttpd Webroot for Port 80 is at /var/www/html.
If you want to use your own csr and webroot authentification you have to specify a webroot-map in letsencrypts config file to define a conjunction between domain name and webroot path otherwise an error “PluginError–webroot-path must be set” occurs.
Create a config file /etc/letsencrypt/cli.ini
authenticator = webroot
webroot-path = /var/www/html
webroot-map = {"yourhost.yourdomain.net" : "/var/www/html"}
1 | root@raspown:~ /letsencrypt # bash letsencrypt-auto certonly --config /etc/letsencrypt/cli.ini --agree-tos --csr /etc/lighttpd/ssl/server.der --cert-path /etc/lighttpd/ssl/server.pem |
And set restricted permissions for csr, certificate and key.
1 2 3 4 5 | root@raspown:~ # cat /etc/lighttpd/ssl/server.key /etc/lighttpd/ssl/server.crt > /etc/lighttpd/ssl/server.pem root@raspown:~ # chown -R www-data:root /etc/lighttpd/ssl/ root@raspown:~ # chmod 460 /etc/lighttpd/ssl/* root@raspown:~ # chown -R www-data:www-data /etc/lighttpd/ssl/server.key root@raspown:~ # chmod 400 /etc/lighttpd/ssl/server.key |
For testing
For testing https you can use selfsigned certificates
1 2 3 | root@raspown:~ # mkdir -p /etc/lighttpd/ssl/ root@raspown:~ # openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/lighttpd/ssl/server.key -out /etc/lighttpd/ssl/server.crt root@raspown:~ # cat /etc/lighttpd/ssl/server.key /etc/lighttpd/ssl/server.crt > /etc/lighttpd/ssl/server.pem |
1 2 | root@raspown:~ # chown -R www-data:root /etc/lighttpd/ssl/ root@raspown:~ # chmod 460 /etc/lighttpd/ssl/* |
Configure Lighttpd
Append the following lines to your config file /etc/lighttpd/lighttpd.conf , ensure that the owncloud data directory is not readable from the web.
# If you want to use HTTP logging (troubleshooting) insert both lines below
# Consider to mount the log folder /var/log/lighttpd as
# tmpfs (but logs are lost after reboot) to avoid excessive writing to the SD Card.
# Add fstab
# tmpfs /var/log/lighttpd tmpfs rw,size=256M,noexec,nodev,nosuid,uid=33,gid=33 0 0
server.modules += ( "mod_accesslog" )
accesslog.filename = "/var/log/lighttpd/access.log"
# SSL Server settings
# redirect all to https
$HTTP["scheme"] == "http" {
# redirect all http traffic to https, expect the letsencrypt webroot auth requests
$HTTP["url"] !~ "^/\.well-known/" {
# capture vhost name with regex conditiona -> %0 in redirect pattern
# must be the most inner block to the redirect rule
$HTTP["host"] =~ ".*" {
url.redirect = (".*" => "https://%0$0")
}
}
}
$SERVER["socket"] == ":443" {
ssl.engine = "enable"
ssl.pemfile = "/etc/lighttpd/ssl/server.pem"
# ssl.ca-file = "/etc/lighttpd/ssl/server.crt"
# Enter your hostname
server.name = "yourhost.yourdomain.net"
server.document-root = "/var/www/owncloud"
ssl.use-sslv2 = "disable"
ssl.use-sslv3 = "disable"
ssl.use-compression = "disable"
ssl.honor-cipher-order = "enable"
# A more secure cipher list. Not working with older Webbrowsers!
ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM:AES128+EECDH:AES128+EDH"
server.errorlog = "/var/log/lighttpd/serror.log"
accesslog.filename = "/var/log/lighttpd/saccess.log"
}
# Owncloud Data directory
$HTTP["url"] =~ "^/oc/data/" {
url.access-deny = ("")
}
# Owncloud root
$HTTP["url"] =~ "^/oc($|/)" {
dir-listing.activate = "disable"
}
# Letsencrypt webauth root
$HTTP["url"] =~ "^/\.well-known/" {
dir-listing.activate = "disable"
}
# Not Owncloud or Webauth
$HTTP["url"] !~ "^/oc$|^/oc/|^/\.well-known/" {
url.access-deny = ("")
}
Create the webserver root directory for your owncloud instance
1 2 | root@raspown # mkdir -p /var/www/owncloud root@raspown # chown www-data:www-data /var/www/owncloud |
Start the webserver and see if its running
1 2 3 4 | root@raspown # lighty-enable-mod fastcgi-php root@raspown # systemctl enable lighttpd.service root@raspown # systemctl start lighttpd.service root@raspown # journalctl -xn |
Owncloud
Installing owncloud(In this tutorial 8.2)
1 2 3 | root@raspown # cd /var/www/owncloud root@owncloud: /var/www/owncloud # wget https://download.owncloud.org/community/owncloud-8.2.1.tar.bz2 root@owncloud: /var/www/owncloud # tar -xvjf owncloud-8.2.1.tar.bz2 |
Owncloud is now extracted to the subfolder owncloud in the webserver root /var/www/owncloud . I renamed this folder to oc. If you plan another name alter also the deny and dir-listing directive in lighttpd.conf to your folder.
1 | root@owncloud: /var/www/owncloud # mv owncloud oc |
Remove owncloud sources
1 | root@owncloud: /var/www/owncloud # rm owncloud-8.2.1.tar.bz2 |
Set Folder permissions
1 2 3 4 | root@owncloud: /var/www/owncloud # cd oc root@owncloud: /var/www/owncloud/oc # mkdir -p data root@owncloud: /var/www/owncloud/oc # chmod -R o-wxr /var/www/owncloud root@owncloud: /var/www/owncloud/oc # chown -R www-data:www-data /var/www/owncloud |
Database
The default database backend of owncloud is sqlite. If you plan to synchronize your Data with the Ownclound Desktop Client a real Database System is recommended.
Here are the steps to setup a mysql Datebase. Install the server and choose secure password.
1 | root@raspown # apt-get -y install mysql-server |
Secure your installation
1 2 3 4 5 6 7 8 9 10 | root@raspown # mysql_secure_installation Remove anonymous users ? [Y /n ] y ... Success! Disallow root login remotely? [Y /n ] y ... Success! Remove test database and access to it? [Y /n ] y - Dropping test database... ... Success! Reload privilege tables now? [Y /n ] y ... Success! |
Open the MySQL Console as Database root
1 | root@raspown # mysql -u root -p |
Create a User ocuser (Replace ocpassword with your Password ) and the database owncloud and permit the user to the database.
mysql> create database owncloud;
mysql> CREATE USER 'ocuser'@'localhost' identified by 'ocpassword';
mysql> grant all on owncloud.* to 'ocuser'@'localhost';
mysql> FLUSH PRIVILEGES;
If you want to change the password
mysql> use mysql;
mysql> SET PASSWORD FOR 'ocuser'@'localhost' = PASSWORD('ocpassword');
Securing the installation
AppArmor
I use AppArmor to secure lighttpd and mysql. The raspbian kernel does not support AppArmor out of the box. To use AppArmor you have to recompile the kernel. My post provides a script which supports you :-). Debian Jessie has the support for AppArmor already included.
Installing and activating, on a PC with grub booloader add apparmor=1 security=apparmor to the kernel parameters in /etc/default/grub
1 2 3 4 5 | root@raspown # apt-get install apparmor apparmor-profiles apparmor-utils root@raspown # cp /etc/default/grub /etc/default/grub.org root@raspown # perl -pi -e 's,GRUB_CMDLINE_LINUX="(.*)"$,GRUB_CMDLINE_LINUX="$1 apparmor=1 security=apparmor",' /etc/default/grub root@raspown # update-grub root@raspown # reboot |
On an Raspberry edit /boot/cmdline.txt
1 | root@raspown # sed -e's/\( root=\/dev\/mmcblk0p2\)/\1 apparmor=1 security=apparmor/g' /boot/cmdline.txt --in-place=.bak |
Check if apparmor is correct installed
1 | root@raspown # aa-status |
Note: If error “apparmor filesystem is not mounted.” occurs you have to forgot to call update-grub
By default a mysql profiles is loaded and enforced. Create a lighttpd profile /etc/apparmor.d/usr.sbin.lighttpd This profile is based on the example shipped with debian /usr/share/doc/apparmor-profiles/extras/usr.sbin.lighttpd and OpenSUSE
# ------------------------------------------------------------------
#
# Copyright (C) 2002-2005 Novell/SUSE
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
# License published by the Free Software Foundation.
#
# ------------------------------------------------------------------
# vim:syntax=apparmor
#include
/usr/sbin/lighttpd {
#include
#include
#include
# needed to change max file descriptors
capability sys_resource,
# network service ;)
capability net_bind_service,
# changing the uid/gid on startup
capability setgid,
capability setuid,
/etc/ld.so.cache r,
/etc/lighttpd r,
/etc/lighttpd/*.conf r,
/etc/lighttpd/conf.d/*.conf r,
/etc/lighttpd/auth.d/* r,
/etc/lighttpd/vhosts.d r,
/etc/lighttpd/vhosts.d/* r,
/usr/sbin/lighttpd mix,
/usr/lib/lighttpd/*.so mr,
/usr/lib64/lighttpd/*.so mr,
/etc/ssl/private/*.pem r,
/etc/lighttpd/ssl/server.pem r,
# home dir. e.g. used for sockets.
/var/lib/lighttpd/ r,
/var/lib/lighttpd/** rwl,
# mod_compress cache
/var/cache/lighttpd/ r,
/var/cache/lighttpd/** rwl,
# pid
/{,var/}run/lighttpd.pid rwl,
# log files
/var/log/lighttpd/*.log rw,
# Socket
/run/lighttpd/* w,
# exec
# /usr/bin/php-cgi Cx,
/usr/bin/php5-cgi Cx,
# include_shell
/bin/bash mix,
/bin/dash mix,
/bin/zsh mix,
/bin/cat mix,
# http docs
/var/www/ r,
/var/www/** r,
# Debian/Ubuntu integration in default installation
#include
/etc/mime.types r,
/usr/share/lighttpd/ r,
/usr/share/lighttpd/*.pl rmix,
/etc/lighttpd/conf-available/ r,
/etc/lighttpd/conf-available/*.conf r,
/etc/lighttpd/conf-enabled/ r,
/etc/lighttpd/conf-enabled/*.conf r,
profile /usr/bin/php5-cgi {
#include
/etc/* r,
/etc/ssl/openssl.cnf r,
/etc/php/** r,
/etc/php5/** r,
/lib/lib*so* mr,
/var/lib/php5/sessions/* rwk,
/var/www/ r,
/var/www/** r,
/var/www/owncloud/oc/apps/** rwk,
/var/www/owncloud/oc/config/** rwk,
/var/www/owncloud/oc/data/** rwk,
/tmp/ r,
/tmp/* rwk,
/usr/share/mysql/charsets/Index.xml r,
/usr/bin/php5-cgi r,
/usr/lib/lib*so* mr,
/usr/lib{,32,64}/** mr,
}
}
Set it in enforce mode
1 2 | root@raspown # aa-enforce /usr/sbin/lighttpd root@raspown # systemctl restart lighttpd.service |
Add the line
/etc/ld.so.cache r,
also into /usr/sbin/mysqld {} Section of /etc/apparmor.d/usr.sbin.mysqld
1 | root@raspown # aa-enforce /usr/sbin/mysqld |
If have already tested the apparmor profile for a while. If owncloud shows unexpected behaviours check the syslog for apparmor DENIES and send it to me:
1 | root@raspown # journalctl -x --since yesterday|grep 'apparmor="DENIED"' |
Tripwire
Next step in security is to monitor filesystem changes. Here are the steps to handle this with tripwire. For further information see documention
Install tripwire
1 | root@raspown # apt-get install tripwire |
Create a site key. The site key is used for creating and signing the policy
1 | root@raspown # twadmin -m G -S /etc/tripwire/site.key -Q YourSecureSiteKeyPassword |
Create a local key. The local key is used checking file integrity and update database on changes (OS Update..)
1 | root@raspown # twadmin -m G -L /etc/tripwire/${HOSTNAME}-local.key -P -Q YourSecureLocalKeyPassword |
Adjust the config /etc/tripwire/twcfg.txt as needed and create the config file from the text template
1 | root@raspown # twadmin --create-cfgfile -S /etc/tripwire/site.key /etc/tripwire/twcfg.txt |
Adjust the default policy /etc/tripwire/twpol.txt to your system. This is an good overview.
and append the rules for owncloud to the end of the file /etc/tripwire/twpol.txt
#
# owncloud
#
#
(
rulename = "owncloud Directories",
severity = $(SIG_MED)
)
{
/var/www/ -> $(SEC_BIN) (recurse = 1) ;
/var/www/owncloud/oc/config -> $(SEC_CONFIG) (recurse = 1) ;
!/var/www/owncloud/oc/data;
}
Create the policy file from text file
1 | root@raspown # twadmin --create-polfile /etc/tripwire/twpol.txt |
Do the init filesystem scan and create the database and eleminate all errors
1 | root@raspown # tripwire --init |
Checking your system is simple, the report is stored at /var/lib/tripwire/report/.
1 | root@raspown # tripwire --check |
If your database has to be updated, maybe you update your Linux OS, run “tripwire –update” against the latest report file. This opens an text editor. Edit only the changes (removing the [X] => [ ]) which should not be written to the database. Save the file and you will prompted for the local passphrase.
1 | root@raspown # tripwire --update -r /var/lib/tripwire/report/report-20151118.twr |
After updating the database its an good idea to copy the database file /var/lib/tripwire/*.twd to an storage which is readonly. Before each tripwire check command check also if the database in the /var/lib/tripwire and on the readonly storage is identically.
Setup an cron job which periodically starts an tripwire check
Owncloud Configuration
All backend service are now prepared and running. Open a brower and connect to your Owncloud Installation. Navigate to
https://yourFQDNHostname/oc/
Owncloud is now ready to configure and use
Michael