Hardening Nextcloud

This server hosts both this website and an installation of Nextcloud 13 at fog.vincible.space. In an effort to lock down the Nextcloud installation, I have tuned certain settings in addition to the general server setup.

The domain vincible.space and all of its subdomains are served via TLS and also preloaded, meaning that all connections to any resources served over this domain must be encrypted. The connections to the Nextcloud installation must come from a whitelisted domain, currently only fog.vincible.space. An attempt to access the installation using the bare IP address 71.19.146.187 will result in a server-side redirect to a custom Error 403 page. This is set in the config/config.php along with Brute-force settings, which aim to protect against automated guessing of user credentials:

<?php
$CONFIG = array (
...
  'trusted_domains' => 
  array (
    0 => 'fog.vincible.space',
  ),
  'auth.bruteforce.protection.enabled' => true,
  'overwriteprotocol' => 'https',
  'overwrite.cli.url' => 'https://fog.vincible.space',
...
);

The current SSL / TLS certificate is from Let’s Encrypt. Using the OpenSSL command line, I have generated a strong 4096-bit Diffie-Hellman parameter (which takes forever on a single-core server):

openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

The Apache configuration file is modified as follows to increase the strength of the cryptographic ciphers used by TLS, and to enforce HSTS preloading. I have also added a Referrer-Policy header to preserve user privacy.

<IfModule mod_ssl.c>
    <VirtualHost *:443>
        SSLEngine on
        SSLOptions +StrictRequire
        DocumentRoot /var/www/nextcloud
        ServerName fog.vincible.space
        <Directory /var/www/nextcloud/>
            Options +FollowSymlinks
            AllowOverride All
            SetEnv HOME /var/www/nextcloud
            SetEnv HTTP_HOME /var/www/nextcloud
        </Directory>
        <IfModule mod_headers.c>
            Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
            Header always set Referrer-Policy "no-referrer"
        </IfModule>
        SSLCACertificateFile /etc/letsencrypt/live/fog.vincible.space/fullchain.pem
        SSLCertificateFile /etc/letsencrypt/live/fog.vincible.space/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/fog.vincible.space/privkey.pem
        Include /etc/letsencrypt/options-ssl-apache.conf
    </VirtualHost>
    SSLProtocol TLSv1.2
    SSLCipherSuite 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:!AES128
    SSLHonorCipherOrder on
    SSLCompression off
    SSLSessionTickets off
    SSLUseStapling on
    SSLStaplingResponderTimeout 5
    SSLStaplingReturnResponderErrors off
    SSLStaplingCache shmcb:/var/run/ocsp(128000)
    SSLOpenSSLConfCmd Curves secp384r1
    SSLOpenSSLConfCmd DHParameters "/etc/ssl/certs/dhparam.pem"
</IfModule>

Within the administration user interface for the Nextcloud installation, I have also enabled a minimum password length of 12 characters, as well as selected the option to check a hash of a proposed user password against the Have I Been Pwned list of compromised passwords. Additionally, users can opt in to two-factor authentication, using either a Time-based One-Time Password algorithm (TOTP) or a hardware token supporting Universal 2nd Factor (U2F), such as a yubikey. The use of a hardware token provides the strongest protection against credential phishing as is evidenced by Google’s claim that it “… has not had any of its 85,000+ employees successfully phished on their work-related accounts since early 2017, when it began requiring all employees to use physical Security Keys in place of passwords and one-time codes…”

As far as user data is concerned, the server uses full disk encryption as well as enabling Server-side encryption for all data by default on both the server’s home storage and any (future) external storage. Additionally the data directory is installed outside of the webroot to help further separate access to data from access to the web server (which is also set in the Nextcloud config/config.php file):

<?php
$CONFIG = array (
...
  'datadirectory' => '/var/lib/nextcloud/data',
...
);

Overall, these precautions provide for a fairly robust installation, which is much more secure than using a third party service such as Dropbox, etc. Of course the trade-off is increase in cost and maintenance burden as well as data availability in case of server failure, etc. If I were using a setup like this in production for other people, I would focus on increasing the availability of data in this setup including better and more backups as well as server redundancy.