Hosting Nextcloud on TrueNAS Core
This is guide on how to host a public Nextcloud instance securely on TrueNAS Core. I'm currently in the process of moving all my personal data out of third party cloud providers and decided to set up a NAS (Network Attached Storage) running TrueNAS Core for storing all my data. I also want to be able to share my contacts, files, and photos with other members of my family and settled with using Nextcloud a free and open source self-hosted cloud provider. I've been using other Nextcloud instances for a few years now and absolutely love it. If you're looking to host your own data, you've come to the right place.
Requirements and Disclaimers ¶
In order to set up a public Nextcloud instance, you must have:
- A machine running TrueNAS Core. TrueNAS Scale may work as well but you will need to modify some steps (namely, package installation).
- A domain name. For the sake of this guide I will be using
drive.domain.com
.
At the time of this writing, I am using the following program versions. Your installation may vary.
TrueNAS Core 13.0-U5.3
MariaDB 10.6.16
Caddy 2.7.5
Redis 7.2.3
PHP 8.2
Nextcloud 27.1.4
Creating Datasets ¶
We first want to create a few separate datasets for the Nextcloud instance. By keeping the database, data, configuration, and themes managed by separate datasets, it ensures that we can restore the Nextcloud service in the case it inevitably fails.
In Storage > Pools, press the three dots next to the root dataset and press Add Dataset. My root dataset is named tank
so I will be using this name to refer to it going forward. This new dataset will be the main dataset housing all Nextcloud data. Name it nextcloud-data
then press Submit.
We also need to create sub-datasets under the newly created Nextcloud dataset for each category of data Nextcloud stores. Create four sub-datasets with the following properties:
nextcloud-data:
config:
Compression level: LZ4
Enable Atime: On
data:
Compression level: LZ4
Enable Atime: Off
db:
Compression level: LZ4
Enable Atime: Off
themes:
Compression level: LZ4
Enable Atime: On
Configuring Dataset Ownership ¶
We need to set the proper owners of each dataset.
First, we will create a MySQL user. Go to Account > Users and press Add. Fill in the following user information:
Full Name: mysql
Username: mysql
User ID: 88
[x] New Primary Group
Disable Password > Yes
[ ] Samba Authentication
Then press Submit.
Go back to Storage > Pools and press Edit Permissions next to each sub-dataset created earlier. Make the following changes to dataset ownership. You may need to check an Apply User and an Apply Group checkbox for each:
nextcloud-data:
config:
User: www
Group: www
data:
User: www
Group: www
db:
User: mysql
Group: mysql
themes:
User: www
Group: www
Creating a Jail with Mounted Datasets ¶
Now we will create a jail which will run the Nextcloud server.
In Jails, press Add. Name this jail nextcloud
, then set Jail Type to Default (Clone Jail), and set the Release to the latest release (13.2-RELEASE). Then press Next.
Check DHCP Autoconfigure IPv4 which should automatically check VNET. Then press Next and Submit.
To ensure the jail automatically starts, press Edit on the jail, then check Auto-start. We also need to check allow_raw_sockets under Jail Properties. Then press Save. Finally, press Start on the jail to start it.
It's much easier to mount the datasets to the jail using the given TrueNAS shell. In Shell, type the following commands:
iocage exec nextcloud mkdir -p /mnt/data
iocage exec nextcloud mkdir -p /var/db/mysql
iocage exec nextcloud mkdir -p /usr/local/www/nextcloud/config
iocage exec nextcloud mkdir -p /usr/local/www/nextcloud/themes
iocage fstab -a nextcloud /mnt/tank/nextcloud-data/data /mnt/data nullfs rw 0 0
iocage fstab -a nextcloud /mnt/tank/nextcloud-data/db /var/db/mysql nullfs rw 0 0
iocage fstab -a nextcloud /mnt/tank/nextcloud-data/config /usr/local/www/nextcloud/config nullfs rw 0 0
iocage fstab -a nextcloud /mnt/tank/nextcloud-data/themes /usr/local/www/nextcloud/themes nullfs rw 0 0
If for some reason you need to manually edit the fstab file, you can do so with iocage fstab -e nextcloud
.
Since MariaDB has its own internal cache, we also do not want to cache for the database dataset. This will improve performance:
zfs set primarycache=metadata tank/nextcloud-data/db
Connecting to the Jail ¶
To make it easier to temporarily access our new jail we will enable SSH (don't worry, we will disable it once the server is completely setup). In Jails > nextcloud
> Shell:
passwd # change to something temporary you will remember!
echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
service sshd enable
service sshd start
Then connect to the jail via SSH as root
. The jail's IP address will be located in Jails > nextcloud
.
Installation of Packages ¶
We will now install packages necessary for the server. Run the following commands:
pkg update
pkg install neovim # or nano, or your editor of choice
pkg install wget
pkg install mariadb106-server
pkg install caddy
pkg install redis
# and all PHP packages...
pkg install php82 php82-bz2 php82-ctype php82-curl php82-dom php82-exif php82-fileinfo php82-filter php82-gd php82-iconv php82-intl php82-ldap php82-mbstring php82-opcache php82-pdo php82-pdo_mysql php82-pecl-APCu php82-pecl-imagick php82-pecl-redis php82-posix php82-session php82-simplexml php82-xml php82-xmlreader php82-xmlwriter php82-xsl php82-zip php82-zlib php82-bcmath php82-gmp php82-sysvsem
Configuring the Database ¶
Next, we will configure MariaDB, our database of choice. I've chosen MariaDB because it is officially supported by Nextcloud and the performance of PostgreSQL vs MySQL vs MariaDB seem to all be approximately the same.
In /usr/local/etc/mysql/my.cnf
, change the socket:
socket = /tmp/mysql.sock
Then run the server.
service mysql-server enable
service mysql-server start
mysql_secure_installation --socket=/tmp/mysql.sock
You will need to answer a few prompts during the secure installation:
Enter current password for root (enter for none): # enter the password we set earlier
Switch to unix_socket authentication [Y/n] y
Change the root password? [Y/n] y
New password: # choose a secure database password
Remove anonymous users? [Y/n] y
Disallow root login remotely? [Y/n] y
Remove test database and access to it? [Y/n] y
Reload privilege tables now? [Y/n] y
We can now set up the Nextcloud database. Log into MySQL using the database password from earlier.
mysql -u root -p
Then create the database using the following SQL query:
CREATE DATABASE nextcloud;
CREATE USER 'nextcloud_admin'@'localhost' IDENTIFIED BY 'YOUR_DB_PASSWORD_HERE';
GRANT ALL ON nextcloud.* TO 'nextcloud_admin'@'localhost';
FLUSH PRIVILEGES;
exit
We now have a properly configured Nextcloud database!
Configuring PHP ¶
We need to configure PHP-FPM, the FastCGI implementation of PHP. First, enable the service:
service php-fpm enable
service php-fpm start
cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini
Then edit /usr/local/etc/php.ini
to configure basic PHP settings:
memory_limit = 512M
post_max_size = 1999M
cgi.fix_pathinfo = 1
upload_max_filesize = 1999M
date.timezone = America/Kentucky/Louisville # or your local timezone via http://php.net/manual/en/timezones.php
opcache.enable = 1
opcache.enable_cli = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 60
opcache.save_comments = 1
opcache.jit = 1255
opcache.jit_buffer_size = 128M
Then tune PHP-FPM settings in /usr/local/etc/php-fpm.d/www.conf
:
pm = dynamic
pm.max_children = 120
pm.start_servers = 12
pm.min_spare_servers = 6
pm.max_spare_servers = 18
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp
Then restart the service:
service php-fpm restart
Installing Nextcloud ¶
We will now install Nextcloud. Run the following commands:
cd /tmp
wget https://download.nextcloud.com/server/releases/latest.tar.bz2
wget https://download.nextcloud.com/server/releases/latest.tar.bz2.sha512
shasum -a 512 -c latest.tar.bz2.sha512
tar -xvf latest.tar.bz2 -C /usr/local/www
chown -R www:www /usr/local/www/nextcloud /mnt/data
Then configure Nextcloud cron jobs. Open the crontab with the following commands:
setenv EDITOR nvim
crontab -u www -e
Then add the following job:
*/5 * * * * /usr/local/bin/php -f /usr/local/www/nextcloud/cron.php
Configuring the Webserver ¶
We can now configure the webserver. I've chosen Caddy because the configuration syntax is very simple and automatic HTTPS/SSL configuration is a huge win in my mind.
Edit /usr/local/etc/caddy/Caddyfile
and add the following server configuration.
YOUR_JAIL_IP_HERE, drive.domain.com {
root * /usr/local/www/nextcloud
file_server
php_fastcgi localhost:9000 {
env front_controller_active true
}
encode gzip
header {
Strict-Transport-Security "max-age=15768000;includeSubDomains"
}
redir /.well-known/carddav /remote.php/dav 301
redir /.well-known/caldav /remote.php/dav 301
redir /.well-known/webfinger /index.php/.well-known/webfinger 301
redir /.well-known/nodeinfo /index.php/.well-known/nodeinfo 301
@forbidden {
path /.htaccess
path /data/*
path /config/*
path /db_structure
path /.xml
path /README
path /3rdparty/*
path /lib/*
path /templates/*
path /occ
path /console.php
}
respond @forbidden 404
log {
output file /var/log/caddy/access.log
format json
}
}
Then start the server:
service caddy enable
service caddy start
You should be able to navigate to your jail IP in a browser and see the Nextcloud admin account configuration page! We will configure this after we make a few changes.
Configuring Caching ¶
We want to configure caching with Redis to increase performance.
First, edit /usr/local/etc/redis.conf
:
bind 127.0.0.1
port 0
unixsocket /var/run/redis/redis.sock
unixsocketperm 770
Then start Redis and set the proper permissions:
service redis enable
service redis start
pw usermod www -G redis
We also need to enable APCu, our local caching mechanism. Edit /usr/local/etc/php/ext-20-apcu.ini
and add the following:
apc.enabled=1
apc.enable_cli=1
Configuring Nextcloud ¶
Finally, we can set up the Nextcloud admin account. Navigate back to the jail IP in your browser and fill in the following information:
Username: ncadmin
Password: # some secure password you will remember!
Data folder: /mnt/data
Database user: nextcloud_admin
Database password: # the database password you used earlier
Database name: nextcloud
Database host: localhost:/tmp/mysql.sock
Then press Install. This may take a while. I suggest pressing Skip when asked to install recommended apps - you can always install them later.
We now need to configure a few Nextcloud configuration settings to use Redis and good defaults. We will be using the occ
Nextcloud utility but you can also modify these values directly in /usr/local/www/nextcloud/config/config.php
.
su -m www -c 'php /usr/local/www/nextcloud/occ config:system:set redis host --value="/var/run/redis/redis.sock"'
su -m www -c 'php /usr/local/www/nextcloud/occ config:system:set redis port --value=0 --type=integer'
su -m www -c 'php /usr/local/www/nextcloud/occ config:system:set filelocking.enabled --value=true --type=boolean'
su -m www -c 'php /usr/local/www/nextcloud/occ config:system:set memcache.local --value="\OC\Memcache\APCu"'
su -m www -c 'php /usr/local/www/nextcloud/occ config:system:set memcache.locking --value="\OC\Memcache\Redis"'
# set your default phone region based on https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements
su -m www -c 'php /usr/local/www/nextcloud/occ config:system:set default_phone_region --value="US"'
su -m www -c 'php /usr/local/www/nextcloud/occ config:system:set overwrite.cli.url --value="https://drive.domain.com:443"'
su -m www -c 'php /usr/local/www/nextcloud/occ config:system:set trusted_domains 0 --value="YOUR_JAIL_IP"'
su -m www -c 'php /usr/local/www/nextcloud/occ config:system:set trusted_domains 1 --value="drive.domain.com"'
su -m www -c 'php /usr/local/www/nextcloud/occ config:system:set knowledgebaseenabled --value=false --type=boolean'
su -m www -c 'php /usr/local/www/nextcloud/occ config:system:set trashbin_retention_obligation --value="auto, 31"'
Then restart the necessary services.
service redis restart
service php-fpm restart
service caddy restart
Hardening Security ¶
There are a few adjustments we can take to ensure our instance is properly hardened to reduce risk of data loss.
We can harden our FreeBSD jail by inserting the following into /etc/sysctl.conf
:
security.bsd.see_other_uids=0
security.bsd.see_other_gids=0
security.bsd.unprivileged_read_msgbuf=0
security.bsd.unprivileged_proc_debug=0
kern.randompid=$(jot -r 1 9999)
security.bsd.stack_guard_page=1
Then run the following command to clear temporary files:
sysrc clear_tmp_enable=YES
Configuring Email ¶
In order to get notified for alerts, updates, and to be able to send email reset notifications to users, you will need to set up SMTP.
For the sake of this tutorial we will be using Gmail's SMTP because it is reliable and convenient and ensures your emails will never get flagged as spam. If you know how to set up SMTP yourself feel free to use your own server.
Go to https://myaccount.google.com/ > Security > How you sign in to Google > 2-Step Verification > App passwords and add a new application. You can call this application truenas-nextcloud-email
which will give you a generated app password. Copy this password.
Then go to http://YOUR_JAIL_IP/index.php/settings/admin
and scroll down to the Email server section. Type in the following information:
Send mode: SMTP
Encryption: None/STARTTLS
From address: noreply@drive.domain.com
Server address: smtp.gmail.com : 587
Authentication: [x] Authentication required
Credentials (username): # your Gmail address
Credentials (password): # the password you copied earlier
To test, make sure your admin account's email is set in your Nextcloud user settings. Then go back to the Email server section and press Send email to send a test email. If configured properly, you should see an email appear in your inbox.
Disabling SSH ¶
The final task is to disable SSH to prevent users on the local network from logging in to our server. Run the following commands from the jail shell:
service sshd stop
service sshd disable
That's it! You now have a fully functioning Nextcloud server!
Please be sure to keep your server regularly updated. Outdated software means a higher risk of compromise.
Resources ¶
I would like to give credit to the following resources (in no particular order) for guiding me along the way in writing this guide.
- Creating Jails | Managing TrueNAS Core by Blackbeard Support
- How to install Nextcloud on FreeNAS in an iocage jail with hardened security by Samuel Dowling
- Nextcloud server recommendations
- Caddy FreeBSD Wiki
- The optimal & fastest Nextcloud-FPM docker setup with Caddy as webserver and https-proxy by zilexa