Getting Started
Let's begin by installing our web and database servers. Notice we're installing Postgres 9.5, not 9.6 - this is because, at the time of this writing, the PHP PDO module for Postgres requires version 9.5:
$ sudo -s
Password:
# pkg install nginx postgresql95-server
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
Updating database digests format: 100%
The following 4 package(s) will be affected (of 0 checked):
New packages to be INSTALLED:
nginx: 1.12.1,2
postgresql95-server: 9.5.8_1
libxml2: 2.9.4
postgresql95-client: 9.5.8_1
Number of packages to be installed: 4
The process will require 34 MiB more space.
7 MiB to be downloaded.
Proceed with this action? [y/N]: y
Assuming all went well, it's time initialise the database server:
# sudo -u pgsql initdb -D /usr/local/pgsql/data
Next, let's set up the services (note special Bash syntax):
# sysrc {ntpdate,nginx,postgresql,php_fpm}_enable=YES
# sysrc ntpdate_hosts=fi.pool.ntp.org
Notice I've also enabled network date/time synchronisation. Incorrect date/time will result in spurious authentication issues in Nextcloud. Just pick the right server pool.
Finally, let's fire up the database server and create the database we're going to use for Nextcloud. I'm using “nextcloud” as an example as the new Postgres user and database name:
# service postgresql start
LOG: ending log output to stderr
HINT: Future log output will go to log destination "syslog".
# createuser -U pgsql nextcloud
# createdb -U pgsql nextcloud -O nextcloud
Installing PHP
Next, it's time to install PHP and it's required extensions. The list of extensions differs from the one in the installation guide, but trust me - you need all of this stuff. Please note that I'm using Bash as my shell:
# pkg install php71 php71-{ftp,ctype,dom,gd,iconv,json,xml,mbstring,posix,simplexml,xmlreader,xmlwriter,zip,zlib,session,hash,filter,opcache,pdo_pgsql,curl,openssl,fileinfo,pcntl}
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
The following 37 package(s) will be affected (of 0 checked):
New packages to be INSTALLED:
php71: 7.1.9
php71-ftp: 7.1.9
php71-ctype: 7.1.9
php71-dom: 7.1.9
php71-gd: 7.1.9
php71-iconv: 7.1.9
php71-json: 7.1.9
php71-xml: 7.1.9
php71-mbstring: 7.1.9
php71-posix: 7.1.9
php71-simplexml: 7.1.9
php71-xmlreader: 7.1.9
php71-xmlwriter: 7.1.9
php71-zip: 7.1.9
php71-zlib: 7.1.9
php71-session: 7.1.9
php71-hash: 7.1.9
php71-filter: 7.1.9
php71-opcache: 7.1.9
libXpm: 3.5.12
xproto: 7.0.31
libXext: 1.3.3_1,1
xextproto: 7.3.0
libXau: 1.0.8_3
libX11: 1.6.5,1
libxcb: 1.12_2
libXdmcp: 1.1.2
libpthread-stubs: 0.4
kbproto: 1.0.7
libXt: 1.1.5,1
libSM: 1.2.2_3,1
libICE: 1.0.9_1,1
freetype2: 2.8
png: 1.6.29
jpeg-turbo: 1.5.1
libiconv: 1.14_10
oniguruma6: 6.4.0
libzip: 1.1.3
Number of packages to be installed: 37
The process will require 49 MiB more space.
9 MiB to be downloaded.
Proceed with this action? [y/N]: y
Configuring PHP
Let's massage our new PHP installation to work with Nextcloud. First, we need to make PHP-FPM expose some environment variables. You could define each variable separately, but since this particular server will only be used for Nextcloud, with no other shared hosting accounts, I will make mine just expose everything:
# nano /usr/local/etc/php-fpm.d/www.conf
Uncomment the following line:
clear_env = no
and make sure the nginx user can both read from and write to the php-fpm socket:
listen.owner = www
listen.group = www
Second, we need to make some changes to PHP's main configuration file, php.ini:
# cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini
# nano /usr/local/etc/php.ini
Uncomment and update the following lines:
opcache.enable = 1
opcache.enable_cli = 1
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 10000
opcache.memory_consumption = 128
opcache.save_comments = 1
opcache.revalidate_freq = 1
And bump the upload and memory limits:
memory_limit = 512M
upload_max_filesize = 1G
With that, PHP and nginx should be good to go and you should be able to start the services:
# service php-fpm start
# service nginx start
Configure Caching
Since these shares might be shared amount multiple users, let's configure Redis as a caching backend to take advantage of transactional locking. For this we will need to install the Redis server and the corresponding PHP extension:
# pkg install redis autoconf
# sysrc redis_enable=YES
# service redis start
Unfortunately, pkg doesn't currently include the Redis module for PHP 7,1, so we'll have to install it manually from source:
# curl -O https://pecl.php.net/get/redis-3.1.4.tgz
# tar zxvf redis-3.1.4.tgz
# cd redis-3.1.4
# phpize
# ./configure && make && make test
If the compilation and testing was successful, install and activate:
# make install
# echo extension=redis.so >> /usr/local/etc/php/ext-20-redis.ini
# service php-fpm restart
Installing Nextcloud
With all the prerequisites in place, it's finally time to install Nextcloud 12:
$ curl -O https://download.nextcloud.com/server/releases/latest-12.tar.bz2
$ shasum -a 512 -c <(curl -fSsk https://download.nextcloud.com/server/releases/latest-12.tar.bz2.sha512)
latest-12.tar.bz2: OK
$ tar -zxvf latest-12.tar.bz2
Where do you want to put your new Nextcloud installation? Any path will work - here's just an example on a server with “ZFS on root”. Creating a dedicated dataset for the system will allow us to set custom ZFS options as well as configure a dedicated snapshot schedule:
# zfs create zroot/nextcloud
# shopt -s dotglob nullglob
# mv nextcloud/* /zroot/nextcloud
# mkdir /zroot/nextcloud/data
The Nextcloud service needs to be able to write to that directory tree so let's give ownership to the www-user:
# chown -R www /zroot/nextcloud
Let's button up the Nextcloud config by activating it's cron script:
# sudo -u www crontab -e
*/15 * * * * /usr/local/bin/php -f /zroot/nextcloud/cron.php
Finally, let's make sure our database indices are up to snuff:
# cd /zroot/nextcloud
# sudo -u www php occ db:add-missing-indices
Configuring nginx
The Nextcloud documentation has an excellent section on configuring nginx. I've shamelessly ripped their config which I'm using in the following examples:
# curl -o /usr/local/etc/nginx/nextcloud.conf https://gist.githubusercontent.com/filipp/6547dfe9524a1a05e49f69397ae9adff/raw/298b98e6f49f938fd8664f550b72ac1b3c671a55/nextcloud.conf
# nano /usr/local/etc/nginx/nextcloud.conf
I've marked the variables that you should change with a $-sign. Search and replace, then include the file in your nginx config:
# echo "include nextcloud.conf;" >> /usr/local/etc/nginx/nginx.conf
Check out this article from Calomel.org for some extra tips on optimising and securing your nginx install.
Adding Encryption
Let's finish off by adding SSL encryption courtesy of the fine folks at Let's encrypt:
# pkg install py27-certbot
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
The following 25 package(s) will be affected (of 0 checked):
New packages to be INSTALLED:
py27-certbot: 0.16.0_1,1
py27-openssl: 16.2.0
py27-cryptography: 1.7.2
py27-ipaddress: 1.0.18
py27-setuptools: 36.0.1
py27-idna: 2.5
py27-six: 1.10.0
py27-pyasn1: 0.2.2
py27-enum34: 1.1.6
py27-cffi: 1.7.0
py27-pycparser: 2.10
py27-acme: 0.16.0,1
py27-requests: 2.18.1
py27-chardet: 3.0.3
py27-certifi: 2017.4.17
py27-urllib3: 1.21.1
py27-pysocks: 1.6.7
py27-pytz: 2016.10,1
py27-pyrfc3339: 1.0
py27-zope.interface: 4.1.3
py27-zope.component: 4.2.2
py27-zope.event: 4.1.0
py27-parsedatetime: 2.1
py27-configobj: 5.0.6_1
py27-configargparse: 0.12.0
Number of packages to be installed: 25
The process will require 23 MiB more space.
3 MiB to be downloaded.
Proceed with this action? [y/N]: y
Before we can request a cert, we need to disable the nginx directive that denies access to all paths that start with a full stop (like .well-known).
# nano /usr/local/etc/nginx/nextcloud.conf
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
#deny all;
}
I will first experiment with the –staging environment since that won't throttle our connections in case we need to do this more then 5-times:
# certbot --staging certonly --webroot -w /zroot/nextcloud -d cloud.example.com
… if that worked OK, you can request a production cert by omitting the –staging switch. Also, don't forget to uncomment that deny all we just disabled! Once you've run through the installer and everything is up and running, don't forget to drop by Nextcloud security scan.
HTH and good luck!