Install ownCloud 9 on Ubuntu 16.04 Server

It's not officially supported yet but works very well with PHP 7 and other packages in the new LTS version of Ubuntu Posted 9 June 2016

Ubuntu 16.04 Server is not an officially supported platform for ownCloud 9 yet and I had a fair amount of difficulty getting it installed due to a lack of documentation. That is not a complaint, just an observation.

It’s a shame because Ubuntu is the most popular cloud OS by a very large margin and ownCloud is seeing huge adoption as well. Ubuntu 16.04 ships with many updated packages and the performance gains with PHP 7 are significant. If you are installing ownCloud today, there is a fair chance you want to install it on Ubuntu 16.04 because it is a Long Term Support release.

The ownCloud project is in a period of transition now, having been forked by some members of the core development team into a new project called Nextcloud. If you watched last week’s Linux Action Show you know that Frank and Jos were pretty enthusiastic about releasing a ‘drop in’ Nextcloud package to replace ownCloud - perhaps as soon as the end of this month!

With a little trial and error I have everything tested and working now, and I hope this saves you a bit of time. There are no PHP 5 dependencies at all, we’ll use the standard LAMP stack with default PHP 7 packages from Ubuntu (though I use MariaDB here instead of MySQL).

Prerequisites

Before you begin, this tutorial assumes you have the following ready now:

  • A fresh install of Ubuntu 16.04 running somewhere
  • SSH access
  • A non-root user with sudo privileges (optional, recommended)
  • A domain, or subdomain, with a DNS A record pointing at your server’s IP address (technically optional, but required for HTTPS via Certbot)

See here for a quick guide on setting up a new non-root user with sudo privileges and see here to test your DNS changes have propagated since DNS edits are not instant.

I will also go a little beyond the default install and cover some sensible security and performance upgrades using memcached and Redis server. Everything in this blog post will use the default Ubuntu packages except for ownCloud itself, which requires adding a new PPA. I generally avoid adding third-party PPAs but in this case it makes sense.

You should probably start with sudo -i so you don’t have to put “sudo” in front of all the following commands or keep re-typing your password. This is a long post but you can easily have everything set up in under 30 minutes. Let’s get everything installed:

apt install apache2 mariadb-server php7.0 php7.0-common libapache2-mod-php7.0 php7.0-gd php-xml-parser php7.0-json php7.0-curl php7.0-bz2 php7.0-zip php7.0-mcrypt php7.0-mysql php7.0-mbstring memcached php-memcached php-redis redis-server

This installs everything you need to run ownCloud today. We still have to grab the owncloud-files package from their repository but we are manually setting up the software stack first. If you try to follow the official install guide today you will have unresolvable dependencies with PHP 5 and broken packages after installing the owncloud metapackage.

LAMP set up

Let’s do the easy stuff first. I’m sticking with Nano for text editing because it is the default editor in Ubuntu. Make the changes to the file with Nano, press Ctrl + O to write ‘Out’ the changes, then Ctrl + X to exit Nano and return to the SSH prompt.

Apache, part 1

Apache should look for index.php files first because ownCloud is a PHP application.

nano /etc/apache2/mods-enabled/dir.conf

Now edit the DirectoryIndex line in that file to match this, putting index.php first:

<IfModule mod_dir.c>
    DirectoryIndex index.php index.html
</IfModule>

I recommend editing Apache’s global configuration file for a few changes.

nano /etc/apache2/apache2.conf

Shorten the timeout duration and increase KeepAlive values to boost performance. These three values are already in the file, just edit them to match this then save & exit.

Timeout 20
KeepAliveTimeout 100
MaxKeepAliveRequests 200

We don’t need the default site configuration data or the /var/www/html directory so we’ll just get rid of both. Remove the default site directory and its contents.

rm -rf /var/www/html

Clear the contents of the existing site configuration file

echo "" > /etc/apache2/sites-available/000-default.conf

Now edit the default site configuration to create a simple redirect to your ownCloud hostname.

nano /etc/apache2/sites-available/000-default.conf

Starting with the next step, and continuing through the rest of this page, substitute your actual hostname (like example.com or cloud.example.com) for YOUR-OWNCLOUD-URL.

Use this VirtualHost block:

<VirtualHost *:80>

  Redirect permanent / https://YOUR-OWNCLOUD-URL/
  # If you are not going to use HTTPS, be sure to change the above protocol from https to http!

</VirtualHost>

Now create a new VirtualHost configuration for the ownCloud site. I am assuming you will be securing it with HTTPS because you are crazy not to. We’ll do this in two steps. First, a simple HTTP configuration for the first run of Certbot. Then the full Apache configuration with HTTP and HTTPS VirtualHosts.

Enable the necessary Apache modules

a2enmod autoindex deflate expires filter headers include mime rewrite setenvif ssl

Open the new site configuration file for editing

nano /etc/apache2/sites-available/owncloud.conf

Copy the following simple HTTP VirtualHost into the /etc/apache2/sites-available/owncloud.conf file opened in the last step.

<VirtualHost *:80>

  ServerName YOUR-OWNCLOUD-URL
  DocumentRoot /var/www/owncloud

</VirtualHost>

Create the /var/www/owncloud directory manually

mkdir /var/www/owncloud

Put a simple test message there for Apache to serve

echo "Hello World" > /var/www/owncloud/index.html

Enable the new site configuration

a2ensite owncloud.conf

Now test Apache for any errors

apachectl configtest

Now restart Apache to enable the changes so far

service apache2 restart

If you visit your ownCloud site hostname right now with your web browser, and everything is working as expected, you should see the simple “Hello World” message displayed.

Certbot

Certbot (formerly Let’s Encrypt) is in the default Ubuntu repositories now and can be installed and certificate renewal automated with minimal effort. If you already have a certificate then skip this section.

Install Certbot (aka Let’s encrypt).

apt install python-letsencrypt-apache

Get a certificate. Follow the prompts and enter the domain name(s) to secure.

letsencrypt --apache certonly

Test that automated renewals will work - use the same email address you provided at setup.

letsencrypt renew --dry-run --email YOU@EXAMPLE.COM --agree-tos

Next create a root cronjob to check the expiry date daily and renew automatically as needed.

crontab -e

Enter the following two lines and be sure to press enter so you get a (non-visible) newline character at the end of the second line, or cron may not run.

MAILTO=""
@daily letsencrypt renew --non-interactive --email YOU@EXAMPLE.COM --agree-tos  
# This is a blank line...

(Seriously, don’t forget that newline character after the ‘–agree-tos’ on the @daily line).

Apache, part 2

Below is a tested and working Apache VirtualHost that upgrades insecure requests to HTTPS and looks for your HTTPS certificates in the default Certbot location. Be sure to find and replace YOUR-OWNCLOUD-URL with your actual domain or subdomain, and change the certificate paths if you already have a commercial certificate.

It is strongly recommended that you use Mozilla’s excellent SSL Configuration Generator and check it for updates periodically. To get package versions, use apache2 -v and openssl version and plug those into the generator. My example uses Apache 2.4.18 and OpenSSL 1.0.2g with the default Intermediate profile (but I’ve commented out HSTS as a precaution. Do enable it, but understand it means committing to HTTPS for 6 months and clearing your browser cache won’t help you if you change your mind).

<VirtualHost *:80>

  ServerName YOUR-OWNCLOUD-URL

  RewriteEngine on
  RewriteCond %{SERVER_NAME} =YOUR-OWNCLOUD-URL
  RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent]

</VirtualHost>


<VirtualHost *:443>

  # Basics
  ServerName YOUR-OWNCLOUD-URL
  ServerAlias www.YOUR-OWNCLOUD-URL
  # Next line puts ownCloud at the domain root instead of a /owncloud/ subdirectory (e.g. example.com vs. example.com/owncloud/)
  Alias /owncloud "/var/www/owncloud/"
  DocumentRoot /var/www/owncloud

  # TLS
  SSLEngine on
  SSLProtocol             all -SSLv3
  SSLCipherSuite          ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
  SSLHonorCipherOrder     on
  SSLCompression          off
  SSLSessionTickets       off
  SSLOptions +StrictRequire
  SSLCertificateFile /etc/letsencrypt/live/YOUR-OWNCLOUD-URL/cert.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/YOUR-OWNCLOUD-URL/privkey.pem
  Include /etc/letsencrypt/options-ssl-apache.conf
  SSLCertificateChainFile /etc/letsencrypt/live/YOUR-OWNCLOUD-URL/chain.pem
  SSLUseStapling on

  # HSTS recommended, un-comment the next line but realize it means you are committed to staying with HTTPS for the duration of the max-age value below (15768000 seconds = 6 months)
  # Header always set Strict-Transport-Security "max-age=15768000"

  # Always ensure Cookies have "Secure" set (JAH 2012/1)
  Header edit Set-Cookie (?i)^(.*)(;\s*secure)??((\s*;)?(.*)) "$1; Secure$3$4"

  # ownCloud
  <Directory /var/www/owncloud/>

    Options +FollowSymlinks
    AllowOverride All

    <IfModule mod_dav.c>  
      Dav off  
    </IfModule>

    SetEnv HOME /var/www/owncloud
    SetEnv HTTP_HOME /var/www/owncloud

  </Directory>

</VirtualHost>
SSLStaplingCache        shmcb:/var/run/ocsp(128000)

MariaDB

MariaDB and Ubuntu have an odd issue which prevents you from setting the root user password. The specific error message you get is ERROR 1698 (28000): Access denied for user ‘root’@’localhost’. Easy to fix though, asked and answered in this superuser thread. Before we can make the install safe we have to fix this issue.

mysql -u root
use mysql;
update user set plugin='' where User='root';
flush privileges;
exit;

Now we have the ability to set a password for the database’s root user so continue with the secure install command, and be sure to set a new (alphanumeric) password and accept the default choices at the prompts. The installer will guide you. Remember that when using the terminal, the default choice is always upper-case so just press enter to accept like this: “Do you want to do X? [Y/n]” Yes is the default, you don’t need to press the ‘Y’ key.

mysql_install_db && mysql_secure_installation

Now MariaDB is installed with secure defaults and we are back to the SSH prompt. Next create a new database, user, and set the user password for the ownCloud install with this one-liner. Change the uppercase values to match whatever you want to set, and stick to alphanumeric characters for everything to avoid problems with the quotation marks.

mysql -u root -p -e "create database DBNAME; create user DBUSER; set password for DBUSER = password('PASSWORD'); grant all privileges on DBNAME.* TO DBUSER@localhost identified by 'PASSWORD'; flush privileges;"

ownCloud

Okay, now let’s finally get to the ownCloud install! This is pretty straightforward - get the repository signing key and add it to our trusted keys, then add the ownCloud Ubuntu 16.04 repository for the latest stable version, then update everything and install ownCloud.

cd /tmp
wget -nv https://download.owncloud.org/download/repositories/9.0/Ubuntu_16.04/Release.key -O Release.key
apt-key add - < Release.key
sh -c "echo 'deb http://download.owncloud.org/download/repositories/stable/Ubuntu_16.04/ /' >> /etc/apt/sources.list.d/owncloud.list"
apt update
apt install owncloud-files

Now create a directory outside of the Apache document root for your data and grant Apache’s www-data user permissions to it.

mkdir /var/owncloud-data && chown -R www-data:www-data /var/owncloud-data/

Now you are ready for the installation wizard so test and restart Apache to put all changes so far into effect and visit your ownCloud URL. If you have a typo in your config files the configtest will tell you which file and what line the error is on. For persistent problems try tail -f /var/log/apache2/error.log and reload the site in your browser to monitor the error log. Ctrl + C to quit monitoring with tail when you are done.

apachectl configtest
service apache2 restart

Visit your ownCloud URL with your web browser. You should see the Quick Start menu to create the admin account. Make sure you click on the ‘Storage & database’ link to expose extra options below the username and password fields.

Set the data directory to /var/owncloud-data and enter the database name, user, and database password plus your ownCloud admin user name and password.

Log in and check that everything works as expected. Visit the Admin page by clicking on your user name at top right and selecting ‘Admin’ from the menu. Issues or errors will be listed here. One message will be about caching, which we’ll set up right now.

After the Quick Start step is complete we can create a custom ownCloud configuration file for our overrides. Create the file:

nano /var/www/owncloud/config/custom.config.php

Paste the following into the file, substituting a good strong password for ‘REDIS-PASSWORD’. Save that password for the next step.

<?php
$CONFIG = array (
  'asset-pipeline.enabled' => true,
  'memcache.local' => '\\OC\\Memcache\\Memcached',
  'filelocking.enabled' => 'true',
  'memcache.distributed' => '\\OC\\Memcache\\Redis',
  'memcache.locking' => '\\OC\\Memcache\\Redis',
  'redis' =>
    array (
      'host' => 'localhost',
      'port' => 6379,
      'timeout' => 0,
      'dbindex' => 0,
      'password' => 'REDIS-PASSWORD',
    ),
);

Now we need to tell Redis the password. Open its configuration file and enter the password.

# Edit Redis config
nano /etc/redis/redis.conf
# Add this line, matching your Redis password from earlier
requirepass REDIS-PASSWORD

This prevents other users from accessing or wiping your database. You can also test Apache again and restart it to make sure everything works as expected apachectl configtest && service apache2 restart.

At this point you are basically done, but you should visit your admin page again and check for any error messages https://YOUR-OWNCLOUD-URL/settings/admin. You should see the message “All checks passed” at the top of the page. We installed everything necessary for the default encryption module so you can enable it by selecting ‘Apps’ then ‘Not enabled’ from the top left menu.

Extras

Here are some recommended best practices to keep the machine up to date and improve security.

Unattended upgrades

Ubuntu has an unattended-upgrades package which automatically downloads and installs security updates. You can install and enable it with this command:

apt install unattended-upgrades && dpkg-reconfigure unattended-upgrades

iptables

You should lock down the ports Ubuntu is listening on. For an ownCloud server, all you need to leave open for inbound traffic is port 22 (SSH) port 80 (HTTP) and port 443 (HTTPS). Close everything else permanently with these commands.

Close unnecessary ports with IPTables

iptables -P INPUT ACCEPT && iptables -F && iptables -A INPUT -i lo -j ACCEPT && iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT && iptables -A INPUT -p tcp --dport 22 -j ACCEPT && iptables -A INPUT -p tcp --dport 80 -j ACCEPT && iptables -A INPUT -p tcp --dport 443 -j ACCEPT  && iptables -A INPUT -j LOG && iptables -A FORWARD -j LOG && iptables -A INPUT -j DROP

Install iptables-persistent to save these rules across updates and restarts

apt install iptables-persistent && service iptables-persistent start

Fail2ban

Fail2ban can automatically close connections to machines that repeatedly try and fail to log in. This is great for stopping brute-force attacks and repeat offenders. It integrates with iptables and generates new rules as new attacks happen. One note about time and time zones - It is best practice to switch to UTC time on your server so that all applications are synced to the same time zone. This ensures fail2ban and all application log entries sync properly.

Install fail2ban:

apt install fail2ban

Install NTP daemon & set UTC time system-wide:

apt install ntp && timedatectl set-timezone Etc/UTC

Create a fail2ban filter:

nano /etc/fail2ban/filter.d/owncloud.conf

Paste the following two lines into the new file:

[Definition]
failregex={"reqId":".*","remoteAddr":"<HOST>","app":"core","message":"Login failed: .*","level":2,"time":".*"}

Create a new ‘jail’ for fail2ban to use for ownCloud logins:

nano /etc/fail2ban/jail.d/owncloud.conf

Paste the following eight lines into the new jail file:

[owncloud]
enabled = true
filter = owncloud
port = https
bantime = 21600
findtime = 3600
maxretry = 3
logpath = /var/owncloud-data/owncloud.log

Now restart fail2ban to apply all changes:

service fail2ban restart

That was a lot to read but if you made it this far you now have a well configured ownCloud install with safe defaults and automatic security updates enabled. This will run on an inexpensive VPS from any of the major providers as the minimum hardware requirements for ownCloud are quite low. A machine with 1 CPU and 1GB RAM will run all of the above with no problems.

I hope that saved you some time and frustration, and if you spot any errors please let me know and I’ll make the necessary corrections.

Edit Log:
1000UTC 14th June 2016
For the optional Contacts app the extra package php7.0-mbstring is required, and for the optional Calendar app the custom asset-pipeline.enabled setting is not supported. If you plan to use these then install the extra package and omit (or delete) the asset pipeline entry from your custom config file. I also moved the custom config file creation step to be later, to avoid interfering with the Quick Start process. (Thanks Bjorn)
2200UTC 23rd June 2016
Derp - I forgot to include the commands to activate the new ownCloud site in Apache and to install fail2ban so I'm adding them now. (Thanks Jorge)
2200UTC 10th September 2016
I have made multiple edits to the order of the Apache and Certbot configuration steps, which I hope will resolve any Apache error messages. I also made the prerequisites clearer for new users.