Nextcloud is a FOSS solution for cloud storage, among other capabilities such as email, notes, calender, tasks. Pretty much every thing that you can do with the Google suite, you can use Nextcloud for. For that reasoning,

Basic Installation Step

We'll start by getting the machine up-to-date and setting up our webserver, apache, with the following commands

$ sudo apt update && sudo apt upgrade
$ sudo apt install apache2
$ systemctl start apache2 # turns on apache now 
$ systemctl enable apache2 # auto-start apache2 on boot

If you’ve configured the server right, you should be able to go to the server’s IP (which you can find by running hostname -I) in the browser of your choice and see the "Apache2 Ubuntu Default Page."


Next, we can install MariaDB — the database.

$ sudo apt install mariadb-server
$ mysql_secure_installation

During the installation you'll be prompted to login (but we don't have an account setup yet!). Just hit enter and it'll prompt you to create an account. After that, accept all of the recommended prompt options and you’re set. After we've installed the database, we'll then configure it for NextCloud. (note that "Password" will be your own password created during the installation phase).

$ mariadb 
CREATE DATABASE nextcloud;
CREATE USER nextcloud IDENTIFIED BY 'Password';
GRANT USAGE ON *.* TO nextcloud@localhost IDENTIFIED BY 'Password';
GRANT ALL privileges ON nextcloud.* TO nextcloud@localhost;
FLUSH PRIVILEGES;
quit;

While it's not necessary for NextCloud, we'll install phpMyAdmin so that we have a GUI interface to our database.

$ sudo apt install php libapache2-mod-php php-mysql
$ sudo apt install phpmyadmin

When running through the installation dialog, make sure to set the webserver as apache2 and follow all of the default options. After the install, we will symlink the apache and phpMyAdmin configurations which, in tandem with the following commands, will enable phpMyAdmin.

$ sudo ln -s /etc/phpmyadmin/apache.conf /etc/apache2/conf-available/phpmyadmin.conf
$ a2enconf phpmyadmin
$ service apache2 reload
$ systemctl reload apache2

Now, (fingers crossed) if you go to [server ip]/phpmyadmin/ you'll see the phpMyAdmin login page; however, do not login yet. We do not have encryption enabled on the web page yet so your ISP or server can theoretically see what you send. We'll setup encryption down the road in a bit.

But first, we'll install the required PHP (libraries)

$ sudo apt install php-gd php-json php-mysql php-curl php-mbstring php-intl php-imagick php-xml php-zip

as well as NextCloud itself

$ wget https://download.nextcloud.com/server/releases/latest.tar.bz2
$ tar -xvf latest.tar.bz2 # unzip
$ cd nextcloud
$ mv ./* /var/www/html/ # move all files to webserver directory
$ mv ./.htaccess /var/www/html # move hidden dot files
$ mv ./.user.ini /var/www/html # ^
$ cd /var/www/html
$ chown -R www-data:www-data ./* # Recursively set www-data as owner of files
$ chown www-data:www-data .htaccess # ^ for hidden dot files
$ chown www-data:www-data .user.ini # ^

Now if you go to [server ip] you’ll get the Nextcloud page BUT DO NOT LOGIN / CREATE ACCOUNT. Again, we still need to set up encryption!

To set up encryption, we'll use certbot which we'll install and configure like this:

$ sudo apt install certbot
$ sudo apt install python-certbot-apache
$ vim /etc/apache2/sites-available/000-default.conf

then uncomment and change ServerName to whatever domain you’re using, such as cloud.mehvix.com.

Next, you need to point your domain at your server and open your server to the external access. You’ll first need to port forward your server (you can find the ip via hostname -I) to port 443, and then create an A record under your domain’s DNS settings pointing at your external IP (found via dig +short myip.opendns.com @resolver1.opendns.com). Note that if you’re using Cloudflare, you have to disable Universal SSL for Nextcloud to work.

After making your server open to the WWW, you can finish setting up certbot by restarting the webserver and activating certbot

$ systemctl restart apache2
$ certbot --apache

Following the set up dialog will prompt you to auto-redirect from http to https. Your choice, but I'd go ahead and choose redirect. Now you can login on the myPhpAdmin/Nextcloud securely!

We're not done yet though. For security reasons, it’s a good idea to have the data folder outside of the web root (/var/www/) I already set up my drives/raid config, so all I had to do was create and mount a partition:

$ mkdir /media/nextcloud-data/
$ chown www-data:www-data /media/nextcloud-data/
$ mkfs.ext4 /dev/sda
$ mount /dev/sda /media/nextcloud-data/
Then to set up automount, I did sudo blkid to grab the UUID of the partition which I then appended to /etc/fstab:
UUID=[YOUR UUID] /media/nextcloud-data ext4 defaults 0 0

From there, you can go ahead to the Nextcloud page, create an account (you will use this for all NextCloud logins). Make sure to change the data folder to /media/nextcloud-data/ or whatever dir you are using, then enter the MariaDB username (nextcloud) and password.

Now you’ve got yourself a working Nextcloud Server! However, there are still a couple things that you still need to configure which I’ll cover in the following section.

Securing Nextcloud

If you head to https://yournextcloud.com/settings/admin/overview you’ll see all security and setup warnings. Here’s how you fix the most common:

The PHP memory limit is below the recommended value of 512MB.

vim /etc/php/7.4/apache2/php.ini

upload_max_filesize = 512M
memory_limit = 512M
post_max_size = 512M

systemctl restart apache2

The “Strict-Transport-Security” HTTP header is not set to at least “15552000” seconds. For enhanced security, it is recommended to enable HSTS as described in the security tips.

vim /etc/apache2/sites-available/000-default-le-ssl.conf

Add the following under ServerName:

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

a2enmod headers
systemctl restart apache2

Your web server is not properly set up to resolve “/.well-known/[caldav][carddav]“. Further information can be found in the documentation

vim /etc/apache2/sites-available/000-default-le-ssl.conf

Add the following under ServerName:

<Directory /var/www/html/>
	Options +FollowSymLinks
	AllowOverride All
</Directory>

systemctl restart apache2

No memory cache has been configured. To enhance performance, please configure a memcache, if available. Further information can be found in the documentation

sudo apt install php-apcu
vim /var/www/html/config/config.php
'memcache.local' => '\OC\Memcache\APCu'
sudo vim /etc/php/7./mods-available/apcu.ini
apc.enable_cli=1
systemctl restart apache2

The PHP OPcache is not properly configured

vim /etc/php/7.4/apache2/php.ini
The following are default settings, consider checking out this blog for information on what each parameter means

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

systemctl restart apache2

Some columns in the database are missing a conversion to big int

sudo -u www-data php /var/www/html/occ db:convert-filecache-bigint

The database is missing some indexes

sudo -u www-data php /var/www/html/occ db:add-missing-indices

MySQL is used as database but does not support 4-byte characters

First, update MariaDB:
vim /etc/mysql/my.cnf

[mysqld]
innodb_file_per_table=1

systemctl restart mariadb
mariadb

ALTER DATABASE nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
use nextcloud;
set global innodb_large_prefix=on;
set global innodb_file_format=Barracuda;
quit;

Then, update Nextcloud:
sudo -u www-data php /var/www/html/occ config:system:set mysql.utf8mb4 --type boolean --value="true"
sudo -u www-data php /var/www/html/occ maintenance:repair

Transferring [file] - server replied: [nothing]

sudo -u www-data php /var/www/html/occ files:scan --all

Files aren’t showing up for [user]

sudo chown -R www-data:www-data [data mount location]/[user]
sudo -u www-data php /var/www/html/occ files:scan -- [user]

Transferring [file] - server replied: Forbidden (Sabre\DAV\Exception\Forbidden)

sudo rm [username]/uploads

Home storage for user [user] not writable

sudo chown -R www-data:www-data [data mount location]/[user]

Further Securing & Optimization

There are various other actions you can take to ensure that both your os and nextcloud are secure. I’ll be covering the one’s found on this wiki page.

Give PHP read access to /dev/urandom

On my system this ended up breaking Nextcloud, but I’ll keep it in here because it’s in the Nextcloud docs. If you’re site breaks, you should try commenting out open_basedir
sudo vim /etc/php/7.4/apache2/php.ini
Add open_basedir = /dev/urandom
systemctl restart apache2

Install and Tune PHP-FPM

sudo apt-get install php-fpm
a2enmod proxy_fcgi setenvif
a2enconf php7.4-fpm
systemctl reload apache2
vim /etc/php/7.4/fpm/pool.d/www.conf and add the following:

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


Note that these are the recommended settings for 4GB total/1GB database and should be modified for your system.

Quality of Life Changes + Apps

While theses tips aren’t needed for security, they’re nice to have.

Removing /index.php from every URL

vim /var/www/html/config/config.php

'htaccess.RewriteBase' => '/'

sudo -u www-data php /var/www/html/occ maintenance:update:htaccess
systemctl restart apache2

Increasing the max file size

vim /etc/php/7.4/apache2/php.ini

upload_max_filesize = 16G
post_max_size = 16G
max_input_time = 3600
max_execution_time = 3600
upload_tmp_dir = /var/big_temp_files/

vim /var/www/html/.user.ini

upload_max_filesize = 16G
post_max_size = 16G

chown www-data:www-data /media/big_temp_files/

Solving “Index column size too large. The maximum column size is 767 bytes.”

mariadb

set global innodb_file_format = BARRACUDA
set global innodb_large_prefix = ON
set global innodb_file_per_table = ON
set global innodb_default_row_format = 'DYNAMIC'
quit

vim /etc/mysql/my.cnf

innodb_file_per_table=1
innodb-file-format=barracuda
innodb-file-per-table=ON
innodb-large-prefix=ON
innodb_default_row_format = 'DYNAMIC'

systemctl restart mariadb

Fixing right click not working (How to manually install an addon)

This is fixed, but I figured I'd keep it in anyways
$ cd /var/www/html/apps/
$ wget --load-cookies /tmp/cookies.txt "https://docs.google.com/uc?export=download&confirm=$(wget --quiet --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate 'https://docs.google.com/uc?export=download&id=1usRzYpaOVFwKn63xrCrtJTHuLpMXQz_j' -O- | sed -rn 's/.*confirm=([0-9A-Za-z_]+).*/\1\n/p')& 1usRzYpaOVFwKn63xrCrtJTHuLpMXQz_j" -O rclick && rm -rf /tmp/cookies.txt
$ rm -rf files_rightclick/
$ unzip rclick      
$ rm rclick
$ systemctl restart apache2
systemctl restart apache2

Set timezone

vim /var/www/html/config/config.php

Find your timezone in the ones available here.

'logtimezone' => 'America/Chicago',

vim /etc/php/7.4/apache2/php.ini

date.timezone = America/Chicago,

sudo -u www-data php occ config:system:set logtimezone --value "Los_Angeles"

Change default files for new users

All files that are created for a user can be found in /var/www/html/core/skeleton/

Backing Up

                    $ cd /var/www/html/
$ sudo -u www-data php occ maintenance:mode --no-check-certificate
$ cd /var/www/
$ rsync -Aavx html/ backupdir/html_bkup_`date +"%Y%m%d"`/
$ mysqldump --single-transaction -u [nextcloud] -p[password] nextcloud > backupdir/sqlbkp_`date +"%Y%m%d"`.bak
$ cd /var/www/html/
$ sudo -u www-data php occ maintenance:mode --off