I currently have Seafile as my primary server to share my files. I also have a additional installation of a caldav and carddav server called baikal. This is fine so far and works but has a lot of different components to maintain. As Nextcloud made some progress I think it is time to take another look at it to find out if I should replace Seafile and the other servers with one Nextcloud installation.

In this post I just show how I setup my own Nextcloud server using HA-Proxy, let’s encrypt and a virtual machine to run it.

Setup overview

As you already might see, this setup gets a bit more complicated than a standard one server setup. Eventually, you may set up all the services on one machine and it should work as well. Using this kind of installation, I do not have to configure all the backup and I use the benefits of the ZFS filesystem of free nas. Another reason is that I do not only serve Nextcloud on my systems but other https based services as well. HA-Proxy does the reverse proxy work and ssl offloading with let’s encrypt and multiple subdomains.

graph LR subgraph DMZ haproxy -->|reverse proxy| nextCloud1["nextCloud
192.168.1.60"] nextCloud1 -->|send mails| mail[mail
mail gateway
192.168.1.20] nextCloud1 -->|ssl| mysql[mysql
192.168.1.100] nextCloud1 -->|nfs / smb| freenas[freenas
192.168.1.101] end subgraph Firewall pfSense[pfSense
192.168.0.1
Public IP] -->|port forward| haproxy[haproxy
SSL offloading
192.168.1.50] end subgraph LAN Client[Client
192.168.0.30] -->|https| pfSense end subgraph "BBI (Big Bad Internet)" ClientPublic[INet Clients] -->|https| pfSense end

If you prefer an easy setup, there might be different tutorials out there, that help you to set up everything on one machine. Also take a closer look to the official installation manual . In fact this blog post is based on their installation manual.

Preparing the virtual machine

OS installation

Important: if not mentioned otherwise, all commands are executed as root. You may use sudo as well to run these commands.

I do not cover how to set up a database server or a normal virtual machine. There are many good tutorials out there how to setup a basic Debian server. I just mention some steps that I do on my VM after the initial installation. During the setup I only install the basic tools and the ssh server.

One impartant thing is to make sure the IP does not change and is fixed. This can be done by editing /etc/network/interfaces and change the network configuration according to the following information.

allow-hotplug ens18
iface ens18 inet static
        address 192.168.1.60
        netmask 255.255.255.0
        broadcast 192.168.1.255
        network 192.168.1.0
        gateway 192.168.1.1
        dns-search example.com

iface ens18 inet6 static
        address xxx:yyy:zzz::60
        netmask 64

After rebooting, the system should be reachable using this IP address. I also make sure I can login using ssh and my local sshkey. For my virtual machines, I set up ntp, zabbix-agent and qemu-guest-agent.

Data share mount

The virtual machine should only contain the application and run the service. The data itself should remain on my freenas instance. In this installation, we’ll use nfs to mount this share to /srv/nextcloud.

Important: Choose a path outside of /var/www/nextcloud for your data to make sure they are not directly accessible through your webserver.

apt install nfs-client
mkdir -p /srv/nextcloud
nano /etc/fstab
mount -a
mkdir -p /srv/nextcloud/data
chown -R www-data.www-data /srv/nextcloud

The data folder inside the Nextcloud mount is there to separate potential additional folders that might follow in the future. I do not like to have all stuff in the root of the mount.

The line to mount the share in my /etc/fstab looks somewhat like the example below. The nfs-server on my freenas has an ip restriction for the mount as well. Yea, not the safest way, but ok for my setup.

192.168.1.101:/mnt/tank/nextcloud   /srv/nextcloud      nfs     rw,noatime,rsize=32768,wsize=32768,timeo=14,intr,tcp,soft      0       0

Reboot the vm to make sure the mount comes back online when booting.

HA-Proxy configuration

The configuration below are the most essential parts I set up to run Nextcloud.

  • All traffic comming on port 80 is redirected to 443
  • the certificate is specified on the ssl frontend
  • If the hostname matches, the traffic gets redirected to the backend
  • I add the X-Forwarded headers to the request as I do on all my setups. This should make named virtual hosts work on the target side
  • Finally I pass the traffic to the given Nextcloud host on port 80 without ssl
  • HA-Proxy checks port 80 every 2 seconds and will fail the route when 3 checks fail and reactivate after 2 successful checks

    frontend 80
    bind *:80
    mode http
    
    redirect scheme https code 301 if !{ ssl_fc }
    
    rontend 443
    bind *:443 ssl crt /etc/haproxy/certs/current/www.example.com.pem ssl crt /etc/haproxy/certs/current
    mode http
    
    acl 443_cloud_host hdr(host) -i cloud.example.com
    acl 443_cloud_host hdr(host) -i cloud.example.com:443
    use_backend 443_cloud if 443_cloud_host
    
    backend 443_cloud
    acl forwarded_proto hdr_cnt(X-Forwarded-Proto) eq 0
    acl forwarded_port hdr_cnt(X-Forwarded-Port) eq 0
        http-request add-header X-Forwarded-Port %[dst_port] if forwarded_port
        http-request add-header X-Forwarded-Proto https if { ssl_fc } forwarded_proto
    mode http
    server cloud 192.168.1.60:80  check port 80 inter 2000 rise 2 fall 3

Database preparation

To setup the database, I just created a new database called nextcloud with the Nextcloud user using phpMyAdmin . All the tables get set up during installation. For this setup we have the following db information:

host=192.168.1.100
username=nextcloud
password=passw0rd
dbname=nextcloud

Nextcloud installation

Getting Nextcloud

First we need to download the latest Nextcloud server package from Nextcloud . We will use the Archive File containing the full package. Unzip the file and move the content to /var/www/nextcloud. Finally run chown to make sure apache is able to change some files on updates or app installation / uninstallation.

chown -R www-data.www-data /var/www/nextcloud

Basic packages installation

To run some Nextcloud maintenance tasks, sudo comes in quite handy. So we install it as well.

apt install sudo

Next, we are going to set up the easiest possibly way without any complex part on the web server side.

apt install apache2 libapache2-mod-php7.3 php7.3-gd php7.3-json php7.3-mysql \
            php7.3-curl php7.3-mbstring php7.3-intl php-imagick php7.3-xml \
            php7.3-zip php7.3-bz2 php7.3-gmp

Optional packages

These packages are optional but I like to have some previews and the clamav antivirus integration. So these packages have to be installed as well.

apt install ffmpeg libreoffice
apt install clamav clamav-daemon

APCu and Redis installation

To get some performance on filelocks and local memory cache, we have to install two things.

  • APCu which takes care of the local memory caching
  • redis-server that will be used as locking database for file locks

Finally we have to make sure that the user www-data is able to use redis. We do this by adding www-data to the redis group.

apt install redis-server php-redis php-apcu
usermod -a -G redis www-data

php configuration

Now it is time to configure the php installation. These are the options I set on my installation to start with. So far this works quite well. As we use mod_php we have to use nano /etc/php/7.3/apache2/php.ini to edit the right configuration. Do not forget to restart apache after changing these values using systemctl restart apache2

memory_limit = 512M

date.timezone = "Europe/Zurich"

upload_max_filesize = 16G
post_max_size = 16G

max_input_time = 3600
max_execution_time = 3600

output_buffering = 0

opcache.enable=1
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.memory_consumption=128
opcache.save_comments=1
opcache.revalidate_freq=1

Apache2 configuration

PHP is ready and now we have to make sure apache uses the right path to run Nextcloud from. To do this we use nano /etc/apache2/sites-available/000-default.conf and make the virtual host entry look similar to the configuration below.

There are also the two well known redirects, we have to do here as we run https on the public facing side but the server itself only uses http. The redirects used in the provided .htaccess file do not work using a ssl reverse proxy. If you miss these three entries, Nextcloud will provide you a warning that these entries do not work.

<VirtualHost *:80>
        ServerName cloud.example.com
        ServerAdmin hosting@example.com
        DocumentRoot /var/www/nextcloud

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        <Directory /var/www/nextcloud/>
                Require all granted
                AllowOverride All
                Options FollowSymLinks MultiViews
                <IfModule mod_dav.c>
                        Dav off
                </IfModule>
        </Directory>

        <IfModule mod_headers.c>
            Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains"
        </IfModule>

        RewriteEngine On
        RewriteRule ^/\.well-known/carddav https://%{SERVER_NAME}/remote.php/dav/ [R=301,L]
        RewriteRule ^/\.well-known/caldav https://%{SERVER_NAME}/remote.php/dav/ [R=301,L]
</VirtualHost>

Next we have to make sure all the required modules are enabled. When finished, we restart apache2 to apply all the changes made.

a2enmod rewrite
a2enmod headers
a2enmod env
a2enmod dir
a2enmod mime
service apache2 restart

Installation wizard

Reaching this point, it is time to run the installation wizard of Nextcloud. This is quite easy. The screenshot below shows all you have to provide to make it work. You can choose to install the recommended apps or install the needed ones later by hand.

Important: When clicking on Finish setup the installation works but the redirection fails, it is due to the lack of configuration and a wrong https redirect in HA-Proxy. Nextcloud has no idea, that the page should generate https links and redirects.

Installation wizard

After finishing this first installation step, you should find a new configuration file for Nextcloud at /var/www/nextcloud/config/config.php. I had to modify this file a little bit to use all things and make Nextcloud work as expected.

  • I made sure that trusted_domains contained the correct fqdn
  • Add overwriteprotocol to make sure Nextcloud uses https links
  • Add the memcache.* and redis configuration option to enable the caching on Nextcloud

    <?php
    $CONFIG = array (
    'instanceid' => 'instanceid',
    'passwordsalt' => 'generated_salt',
    'secret' => 'abcd/secret',
    'trusted_domains' => 
    array (
    0 => 'cloud.example.com',
    ),
    'datadirectory' => '/srv/nextcloud/data',
    'dbtype' => 'mysql',
    'version' => '18.0.3.0',
    'overwriteprotocol' => 'https',
    'overwrite.cli.url' => 'https://cloud.example.com',
    'htaccess.RewriteBase' => '/',
    'dbname' => 'nextcloud',
    'dbhost' => '192.168.1.100',
    'dbport' => '',
    'dbtableprefix' => 'oc_',
    'mysql.utf8mb4' => true,
    'dbuser' => 'nextcloud',
    'dbpassword' => 'yourSuperSecretPasswordHash',
    'installed' => true,
    'memcache.local' => '\OC\Memcache\APCu',
    'memcache.locking' => '\OC\Memcache\Redis',
    'memcache.distributed' => '\OC\Memcache\Redis',
    'redis' => [
     'host' => '127.0.0.1',
     'port' => 6379,
    ],
    );
    

After updating the configuration, you should be able to log in and the application should work. But as soon as you navigate to Administration->Overview, you will have some warning about missing indexes and wrong data types. Run the following commands to fix these issues. There is no problem running them on an empty database. Running them on a large database will take a considerable amount of time.

cd /var/www/nextcloud
sudo -u www-data php occ db:add-missing-indices
sudo -u www-data php occ db:convert-filecache-bigint
sudo -u www-data php occ maintenance:update:htaccess

The overview page should now be presented with a green check mark telling you, that everything is ok. If there are any warnings, solve them before doing anything else.

System warnings

By now, you have a running installation ready to use. Make sure you test your installation and everything works smoothly. As soon as you confirmed this, you could take a closer look at the steps I took to further tune my setup.

Server tuning

enabling cron to perform background tasks

By default the cron tasks get executed on page loads. This might be ok for your single user little Nextcloud. But as soon as you have more load, this is not a really good idea. The recommended way of running these tasks is using cron.

You can start the editor using the following command.

crontab -u www-data -e

At the end of the file, just enter the line below to run the tasks. Just make sure the path to the cron.php fits your installation. The line tells cron to run the script every five minutes.

*/5  *  *  *  * php -f /var/www/nextcloud/cron.php

Switching apache from mpm_prefork to mpm_worker

As we know is the mpm_prefork mode of apache2 not the fastes and best way to run php application. It also consumes a lot of resources and does not scale very well. To change this, we switch apache2 to mpm_worker that allows us to handle more requests with less resources.

First we have to install php7.3-fpm as libapache2-mod-php7.3 is not compatible with the mpm_worker configuration. The we have to apply all the php.ini configuration chages from above to the php.ini of the fpm setup.

apt-install php7.3-fpm
nano /etc/php/7.3/fpm/php.ini

Following the php.ini changes, we have to configure the worker pool to be able to handle the load. When done, the last step is to restart the fpm service for the changes to take effect.

nano /etc/php/7.3/fpm/pool.d/www.conf
systemctl restart php7.3-fpm.service

The options change in the www.conf are the ones below.

pm = dynamic
pm.max_children = 120
pm.start_servers = 12
pm.min_spare_servers = 6
pm.max_spare_servers = 18
pm.max_requests = 500

Next, apache2 needs to be reconfigured. As I have no users on the host at this time, I just stop apache during the change. After enabling and disabling the components, we start apache again.

systemctl stop apache2
a2dismod php7.3
a2dismod mpm_prefork
a2enmod mpm_worker
a2enmod setenvif
a2enmod proxy_fcgi
a2enconf php7.3-fpm
systemctl start apache2

Recheck the installation and make sure Nextcloud still works as expected. The server should now be able to handle more requests at the same time.

enabling http/2

Now it is time to allow apache to use the newer http/2 protocol. This makes connections more efficient and reuses open sockets to bundle multiple requests.

Important: This is only available when apache is running mpm_worker or mpm_event!

a2enmod http2
systemctl restart apache2

If everything works as expected, you just have to uninstall the mod_php of apache2. By removing this package, we prevent activating it by accident and we do not have to worry about it anymore.

apt remove libapache2-mod-php7.3

Database performance

I recommend taking a closer look to your database setup as the Nextcloud database will grow and a badly configured mysql server will slow down the system a lot. Monitor your database and apply settings to optimize the mysql installation.

closing words

I used to know owncloud and had an installation running a few years ago. Sadly it could not keep up and failed syncing my files on a regular bases. This is why I migrated away to seafile. As seafile continues to slow down and had some project issues (e.g. failing background upload on my mobile), I am looking for something different. First I thought Nextcloud is just the new owncloud with all the same issues. In some cases this might be the truth but it made huge progress and transformed to a good and solid solution.

Just a small summary what load I put on the server when my personal test was over:

  • 3 PCs all using a Gbit-LAN Connection syncing 300GB of data
  • 3 Phones uploading a total of 40GB using the auto upload feature (activating was not easy as the app freezes)
  • PCs were downloading the automatically uploaded files of the mobiles as well
  • all that happened simultaniously

Learnings so far:

  • clamav does take quite a lot of CPU power
  • Mysql configuration issues will show up fast
  • Having a VM with more cores and memory will help to run everything smoothly
  • I do miss a “drive” mount on my windows machine. There is a prototype but it is currently broken
  • The foto app misses many many features (e.g. browsing by date / time, virtual albums, sorting)
  • The email integration is nice but will not replace my roundcube installation in the near future

Beside the missing “drive” feature on Windows, I do not really miss anything. Instead, I gained many things like the gnome integration on my Linux setups.

I continue to migrate away from seafile to Nextcloud as I can reduce my setup even more by shutting down baikal as well. Nextcloud provides all features (fileshare, file sync, auto upload, contact, shared calendars) I currently need.