Nextcloud 17 on FreeBSD 12.1

Not so long ago – almost 2 years from now – I wrote about setting up Nextcloud 13 on FreeBSD.

Today Nextcloud is at 17 version and the configuration that worked two years ago requires some tweaks.

nextcloud-logo.png

This guide will not cover the same information that is available in earlier Nextcloud 13 on FreeBSD article like settings to run Nextcloud inside FreeBSD Jail. Please refer to that earpier article for these settings.

Today we will use these as backends for Nextcloud 17.

  • PostgreSQL 12
  • PHP 7.3
  • Nginx 1.14 (with php-fpm)
  • Memcached 1.5.19

As Nextcloud in FreeBSD packages comes with MySQL and without PostgreSQL support we will need to build it from source using FreeBSD Ports.

Settings

Let’s fetch the latest FreeBSD Ports tree.

# rm -r /var/db/portsnap
# mkdir /var/db/portsnap
# portsnap auto

Now we need to configure needed options in the /etc/make.conf file.

# cat /etc/make.conf
WRKDIRPREFIX=${PORTSDIR}/obj
DEFAULT_VERSIONS+= php=7.3
DEFAULT_VERSIONS+= pgsql=12
OPTIONS_UNSET+=    MYSQL
OPTIONS_SET+=      PGSQL
OPTIONS_SET+=      IMAGICK
OPTIONS_SET+=      PCNTL
OPTIONS_SET+=      SMB
OPTIONS_SET+=      REDIS


Packages and Ports

First we will add some basic tools and things like PostgreSQL still using FreeBSD packages to save tome time instead of compiling them.

# pkg install \
    sudo \
    portmaster \
    beadm \
    lsblk \
    postgresql12-client \
    postgresql12-server \
    nginx \
    memcached \
    php73-pecl-memcached


Now we will compile Nextcloud and its dependencies using FreeBSD Ports – but with portmaster.

# env BATCH=yes portmaster \
    databases/php73-pdo_pgsql \
    databases/php73-pgsql \
    www/nextcloud 

PostgreSQL

We will now configure the FreeBSD’s Login Class for PostgreSQL database in the /etc/login.conf file.

# cat  /etc/login.conf

postgres:\
        :lang=en_US.UTF-8:\
        :setenv=LC_COLLATE=C:\
        :tc=default:

EOF

# cap_mkdb /etc/login.conf

… and PostgreSQL settings in main FreeBSD’s configuration /etc/rc.conf file.

# grep postgresql /etc/rc.conf
postgresql_enable=YES
postgresql_class=postgres
postgresql_data=/var/db/postgres/data12

Let’s initialize the PostgreSQL database.

# /usr/local/etc/rc.d/postgresql initdb
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.

The database cluster will be initialized with locales
  COLLATE:  C
  CTYPE:    en_US.UTF-8
  MESSAGES: en_US.UTF-8
  MONETARY: en_US.UTF-8
  NUMERIC:  en_US.UTF-8
  TIME:     en_US.UTF-8
The default text search configuration will be set to "english".

Data page checksums are disabled.

fixing permissions on existing directory /var/db/postgres/data12 ... ok
creating subdirectories ... ok
selecting dynamic shared memory implementation ... posix
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting default time zone ... Europe/Warsaw
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok

initdb: warning: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the option -A, or
--auth-local and --auth-host, the next time you run initdb.

Success. You can now start the database server using:

    /usr/local/bin/pg_ctl -D /var/db/postgres/data12 -l logfile start


As PostgreSQL database uses 8k blocks let’s set it in ZFS. We could of course create dedicated dataset for this purpose if needed.

# zfs set recordsize=8k zroot/ROOT/default

Now, let’s start the PostgreSQL database.

# /usr/local/etc/rc.d/postgresql start
2019-12-31 11:47:04.918 CET [36089] LOG:  starting PostgreSQL 12.1 on amd64-portbld-freebsd12.0, compiled by FreeBSD clang version 6.0.1 (tags/RELEASE_601/final 335540) (based on LLVM 6.0.1), 64-bit
2019-12-31 11:47:04.918 CET [36089] LOG:  listening on IPv6 address "::1", port 5432
2019-12-31 11:47:04.918 CET [36089] LOG:  listening on IPv4 address "127.0.0.1", port 5432
2019-12-31 11:47:04.919 CET [36089] LOG:  listening on Unix socket "/tmp/.s.PGSQL.5432"
2019-12-31 11:47:04.928 CET [36089] LOG:  ending log output to stderr
2019-12-31 11:47:04.928 CET [36089] HINT:  Future log output will go to log destination "syslog".

We will now create PostgreSQL database for our Nextcloud instance.

# psql -hlocalhost -Upostgres
psql (12.1)
Type "help" for help.

postgres=# CREATE USER nextcloud WITH PASSWORD 'NEXTCLOUD_DB_PASSWORD';
CREATE ROLE
postgres=# CREATE DATABASE nextcloud TEMPLATE template0 ENCODING 'UNICODE';
CREATE DATABASE
postgres=# ALTER DATABASE nextcloud OWNER TO nextcloud;
ALTER DATABASE
postgres=# \q

Keep in mind to put something more sophisticated in the NEXTCLOUD_DB_PASSWORD place.

PostgreSQL Cleanup and Indexing Script

Lets automate some PostgreSQL housekeeping.

# mkdir -p /var/db/postgres/bin
# chown postgres /var/db/postgres/bin
# vi /var/db/postgres/bin/vacuum.sh

#! /bin/sh

/usr/local/bin/vacuumdb -az 1> /dev/null 2> /dev/null
/usr/local/bin/reindexdb -a 1> /dev/null 2> /dev/null
/usr/local/bin/reindexdb -s 1> /dev/null 2> /dev/null
:wq

# cat /var/db/postgres/bin/vacuum.sh
#! /bin/sh

/usr/local/bin/vacuumdb -az 1> /dev/null 2> /dev/null
/usr/local/bin/reindexdb -a 1> /dev/null 2> /dev/null
/usr/local/bin/reindexdb -s 1> /dev/null 2> /dev/null

# chown postgres /var/db/postgres/bin/vacuum.sh
# chmod +x /var/db/postgres/bin/vacuum.sh

# su - postgres -c 'crontab -e'
0 0 * * * /var/db/postgres/bin/vacuum.sh
:wq
/tmp/crontab.JMg5BfT5HV: 2 lines, 42 characters.
crontab: installing new crontab

# su - postgres -c 'crontab -l'
0 0 * * * /var/db/postgres/bin/vacuum.sh

# su - postgres -c '/var/db/postgres/bin/vacuum.sh'

Nginx

Now its time for Nginx webserver.

# chown -R www:www /var/log/nginx

# ls -l /var/log/nginx
total 3
-rw-r-----  1 www  www   64 2019.12.31 00:00 access.log
-rw-r-----  1 www  www  133 2019.12.31 00:00 access.log.0.bz2
-rw-r-----  1 www  www   64 2019.12.31 00:00 error.log
-rw-r-----  1 www  www  133 2019.12.31 00:00 error.log.0.bz2

… and its main nginx.conf configuration file.

# cat /usr/local/etc/nginx/nginx.conf
user www;
worker_processes 4;
worker_rlimit_nofile 51200;
error_log /var/log/nginx/error.log;

events {
  worker_connections 1024;
}

http {
  include mime.types;
  default_type application/octet-stream;
  log_format main '$remote_addr - $remote_user [$time_local] "$request" ';
  access_log /var/log/nginx/access.log main;
  sendfile on;
  keepalive_timeout 65;

  upstream php-handler {
    server 127.0.0.1:9000;
  }

  server {
    # ENFORCE HTTPS
    listen 80;
    server_name nextcloud.domain.com;
    return 301 https://$server_name$request_uri;
  }

  server {
    listen 443 ssl http2;
    server_name nextcloud.domain.com;
    ssl_certificate /usr/local/etc/nginx/ssl/ssl-bundle.crt;
    ssl_certificate_key /usr/local/etc/nginx/ssl/server.key;

    # HEADERS SECURITY RELATED
    add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
    add_header Referrer-Policy "no-referrer";

    # HEADERS
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Robots-Tag none;
    add_header X-Download-Options noopen;
    add_header X-Permitted-Cross-Domain-Policies none;

    # PATH TO THE ROOT OF YOUR INSTALLATION
    root /usr/local/www/nextcloud/;

    location = /robots.txt {
      allow all;
      log_not_found off;
      access_log off;
    }

    location = /.well-known/carddav {
      return 301 $scheme://$host/remote.php/dav;
    }

    location = /.well-known/caldav {
      return 301 $scheme://$host/remote.php/dav;
    }

    # BUFFERS TIMEOUTS UPLOAD SIZES
    client_max_body_size 16400M;
    client_body_buffer_size 1048576k;
    send_timeout 3000;

    # ENABLE GZIP BUT DO NOT REMOVE ETag HEADERS
    gzip on;
    gzip_vary on;
    gzip_comp_level 4;
    gzip_min_length 256;
    gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
    gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;

    location / {
      rewrite ^ /index.php$request_uri;
    }

    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
      deny all;
    }

    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
      deny all;
    }

    location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
      fastcgi_split_path_info ^(.+\.php)(/.*)$;
      include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
      fastcgi_param HTTPS on;
      fastcgi_param modHeadersAvailable true;
      fastcgi_param front_controller_active true;
      fastcgi_pass php-handler;
      fastcgi_intercept_errors on;
      fastcgi_request_buffering off;
      fastcgi_keep_conn off;
      fastcgi_buffers 16 256K;
      fastcgi_buffer_size 256k;
      fastcgi_busy_buffers_size 256k;
      fastcgi_temp_file_write_size 256k;
      fastcgi_send_timeout 3000s;
      fastcgi_read_timeout 3000s;
      fastcgi_connect_timeout 3000s;
    }

    location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
      try_files $uri/ =404;
      index index.php;
    }

    # ADDING THE CACHE CONTROL HEADER FOR JS AND CSS FILES
    # MAKE SURE IT IS BELOW PHP BLOCK
    location ~ \.(?:css|js|woff2?|svg|gif)$ {
      try_files $uri /index.php$uri$is_args$args;
      add_header Cache-Control "public, max-age=15778463";
      # HEADERS SECURITY RELATED
      # IT IS INTENDED TO HAVE THOSE DUPLICATED TO ONES ABOVE
      add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
      # HEADERS
      add_header X-Content-Type-Options nosniff;
      add_header X-XSS-Protection "1; mode=block";
      add_header X-Robots-Tag none;
      add_header X-Download-Options noopen;
      add_header X-Permitted-Cross-Domain-Policies none;
      # OPTIONAL: DONT LOG ACCESS TO ASSETS
      access_log off;
    }

    location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ {
      try_files $uri /index.php$uri$is_args$args;
      # OPTIONAL: DONT LOG ACCESS TO OTHER ASSETS
      access_log off;
    }
  }
}

OpenSSL HTTPS Certificates

We will generate a certificates needed for HTTPS service for Nextcloud.

# mkdir -p /usr/local/etc/nginx/ssl

# cd /usr/local/etc/nginx/ssl

# openssl genrsa -des3 -out server.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
............+++++
....+++++
e is 65537 (0x010001)
Enter pass phrase for server.key: SERVER_KEY_PASSWORD
Verifying - Enter pass phrase for server.key: SERVER_KEY_PASSWORD

As usual use something more sensible then SERVER_KEY_PASSWORD string here πŸ™‚

# openssl req -new -key server.key -out server.csr
Enter pass phrase for server.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:PL
State or Province Name (full name) [Some-State]:lodzkie
Locality Name (eg, city) []:Lodz
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Vermaden Enterprises Ltd.
Organizational Unit Name (eg, section) []:IT Department
Common Name (e.g. server FQDN or YOUR name) []:nextcloud.domain.com
Email Address []:vermaden@interia.pl

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:


# cp server.key server.key.orig

# openssl rsa -in server.key.orig -out server.key
Enter pass phrase for server.key.orig: SERVER_KEY_PASSWORD
writing RSA key

# ls -l /usr/local/etc/nginx/ssl
total 7
-rw-r--r--  1 root  wheel  1151 2019.12.31 12:39 server.csr
-rw-------  1 root  wheel  1679 2019.12.31 12:41 server.key
-rw-------  1 root  wheel  1751 2019.12.31 12:40 server.key.orig

# openssl x509 -req -days 7000 -in server.csr -signkey server.key -out server.crt
Signature ok
subject=C = PL, ST = lodzkie, L = Lodz, O = Vermaden Enterprises Ltd., OU = IT Department, CN = nextcloud.domain.com, emailAddress = vermaden@interia.pl
Getting Private key

# ln -s /usr/local/etc/nginx/ssl/server.crt /usr/local/etc/nginx/ssl/ssl-bundle.crt

PHP

Here is the used PHP configuration with up to 16GB files for Nextcloud.

# grep '^[^;]' /usr/local/etc/php.ini
[PHP]
max_input_time=3600
engine = On
short_open_tag = On
precision = 14
output_buffering = OFF
zlib.output_compression = Off
implicit_flush = Off
unserialize_callback_func =
serialize_precision = 17
disable_functions =
disable_classes =
zend.enable_gc = On
expose_php = On
max_execution_time = 3600
max_input_time = 30000
memory_limit = 1024M
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off
display_startup_errors = Off
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
track_errors = Off
html_errors = On
error_log = /var/log/php.log
variables_order = "GPCS"
request_order = "GP"
register_argc_argv = Off
auto_globals_jit = On
post_max_size = 16400M
auto_prepend_file =
auto_append_file =
default_mimetype = "text/html"
default_charset = "UTF-8"
doc_root =
user_dir =
enable_dl = Off
file_uploads = On
upload_max_filesize = 16400M
max_file_uploads = 64
allow_url_fopen = On
allow_url_include = Off
default_socket_timeout = 300
[CLI Server]
cli_server.color = On
[Date]
date.timezone = Europe/Warsaw
[filter]
[iconv]
[intl]
[sqlite3]
[Pcre]
[Pdo]
[Pdo_mysql]
pdo_mysql.cache_size = 2000
pdo_mysql.default_socket=
[Phar]
[mail function]
SMTP = localhost
smtp_port = 25
mail.add_x_header = On
[SQL]
sql.safe_mode = Off
[ODBC]
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultlrl = 4096
odbc.defaultbinmode = 1
[Interbase]
ibase.allow_persistent = 1
ibase.max_persistent = -1
ibase.max_links = -1
ibase.timestampformat = "%Y-%m-%d %H:%M:%S"
ibase.dateformat = "%Y-%m-%d"
ibase.timeformat = "%H:%M:%S"
[MySQLi]
mysqli.max_persistent = -1
mysqli.allow_persistent = On
mysqli.max_links = -1
mysqli.cache_size = 2000
mysqli.default_port = 3306
mysqli.default_socket =
mysqli.default_host =
mysqli.default_user =
mysqli.default_pw =
mysqli.reconnect = Off
[mysqlnd]
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = Off
[OCI8]
[PostgreSQL]
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
[bcmath]
bcmath.scale = 0
[browscap]
[Session]
session.save_handler = files
session.save_path = "/tmp"
session.use_strict_mode = 0
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.hash_function = 0
session.hash_bits_per_character = 5
url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry"
[Assertion]
zend.assertions = -1
[COM]
[mbstring]
[gd]
[exif]
[Tidy]
tidy.clean_output = Off
[soap]
soap.wsdl_cache_enabled=1
soap.wsdl_cache_dir="/tmp"
soap.wsdl_cache_ttl=86400
soap.wsdl_cache_limit = 5
[sysvshm]
[ldap]
ldap.max_links = -1
[mcrypt]
[dba]
[opcache]
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
[curl]
[openssl] 

PHP PostgreSQL Database Settings

Below are needed to make PHP work with PostgreSQL database.

# cat /usr/local/etc/php/ext-20-pgsql.ini
extension=pgsql.so

# cat  /usr/local/etc/php/ext-20-pgsql.ini

[PostgresSQL]
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
EOF

# cat /usr/local/etc/php/ext-20-pgsql.ini
extension=pgsql.so

[PostgresSQL]
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0


… and the second one.

# cat /usr/local/etc/php/ext-30-pdo_pgsql.ini
extension=pdo_pgsql.so

# cat  /usr/local/etc/php/ext-30-pdo_pgsql.ini

[PostgresSQL]
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
EOF

# cat /usr/local/etc/php/ext-30-pdo_pgsql.ini
extension=pdo_pgsql.so

[PostgresSQL]
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0

PHP FPM

Now the PHP FPM daemon.

# grep '^[^;]' /usr/local/etc/php-fpm.conf
[global]
pid = run/php-fpm.pid
error_log = log/php-fpm.log
syslog.facility = daemon
include=/usr/local/etc/php-fpm.d/*.conf

# touch /var/log/php-fpm.log

# chown www:www /var/log/php-fpm.log

# grep '^[^;]' /usr/local/etc/php-fpm.d/www.conf
[www]
user = www
group = www
listen = 127.0.0.1:9000
listen.backlog = -1
listen.owner = www
listen.group = www
listen.mode = 0660
listen.allowed_clients = 127.0.0.1
pm = static
pm.max_children = 8
pm.start_servers = 4
pm.min_spare_servers = 4
pm.max_spare_servers = 32
pm.process_idle_timeout = 1000s;
pm.max_requests = 500
request_terminate_timeout = 0
rlimit_files = 51200
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp

Start Backend Services

We will now start all ‘backend’ services needed for Nextcloud.

# service postgresql start
2020-01-02 13:18:05.970 CET [52233] LOG:  starting PostgreSQL 12.1 on amd64-portbld-freebsd12.0, compiled by FreeBSD clang version 6.0.1 (tags/RELEASE_601/final 335540) (based on LLVM 6.0.1), 64-bit
2020-01-02 13:18:05.974 CET [52233] LOG:  listening on IPv6 address "::1", port 5432
2020-01-02 13:18:05.974 CET [52233] LOG:  listening on IPv4 address "127.0.0.1", port 5432
2020-01-02 13:18:05.975 CET [52233] LOG:  listening on Unix socket "/tmp/.s.PGSQL.5432"
2020-01-02 13:18:06.024 CET [52233] LOG:  ending log output to stderr
2020-01-02 13:18:06.024 CET [52233] HINT:  Future log output will go to log destination "syslog".

# service postgresql status
pg_ctl: server is running (PID: 36089)
/usr/local/bin/postgres "-D" "/var/db/postgres/data12"

# service php-fpm start
Performing sanity check on php-fpm configuration:
[02-Jan-2020 13:16:50] NOTICE: configuration file /usr/local/etc/php-fpm.conf test is successful

Starting php_fpm.

# service php-fpm status
php_fpm is running as pid 52193.

# service memcached start
Starting memcached.

# service memcached status
memcached is running as pid 52273.

# service nginx start
Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
Starting nginx.

Nextcloud Configuration

I created a link named /data to the Nextcloud data directory located at /usr/local/www/nextcloud/data place.

# ln -s /usr/local/www/nextcloud/data /data

The we use Firefox or other web browser to finish the Nextcloud configuration.

Type https://1.2.3.4 in the browser where 1.2.3.4 is your Nextcloud instance IP address.

I am sorry but the following image is in the Polish language – I forgot to change it to English … but I assume you will what to put in these fields by context.

nextcloud-setup.png

After we finish the setup we go straight to Nextcloud Overview page at https://1.2.3.4/settings/admin/serverinfoto page to see what else needs to be taken care of.

nextcloud-setup-overview.png

Two issues needs to be addressed. One is about Nginx configuration, the other is about PostgreSQL, let’s fix them.

We will add needed header to the Nginx configuration file.

# diff -u /usr/local/etc/nginx/nginx.conf.OLD /usr/local/etc/nginx/nginx.conf
--- /usr/local/etc/nginx/nginx.conf.OLD  2020-01-02 14:21:58.359398000 +0100
+++ /usr/local/etc/nginx/nginx.conf      2020-01-02 14:21:42.823426000 +0100
@@ -46,6 +46,7 @@
     add_header X-Robots-Tag none;
     add_header X-Download-Options noopen;
     add_header X-Permitted-Cross-Domain-Policies none;
+    add_header X-Frame-Options "SAMEORIGIN";

     # PATH TO THE ROOT OF YOUR INSTALLATION
     root /usr/local/www/nextcloud/;

# service nginx reload
Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful

… and update the PostgreSQL convertion.

# sudo -u www /usr/local/bin/php /usr/local/www/nextcloud/occ db:convert-filecache-bigint
Following columns will be updated:

* mounts.storage_id
* mounts.root_id
* mounts.mount_id

This can take up to hours, depending on the number of files in your instance!
Continue with the conversion (y/n)? [n] y

Viola! Both of our problems are gone now.

nextcloud-setup-overview-fixed.png

Trusted Domains

When you will enter the Nextcloud using different domain you will get a warning about that.

To add new Trusted Domain to the Nextcloud config do the following.

Here is how it looks before changes.

# grep -A 3 trusted /usr/local/www/nextcloud/config/config.php
  'trusted_domains' =>
  array (
    0 => '1.2.3.4',
  ),

We will now add nextcloud.domain.com domain.

# vi /usr/local/www/nextcloud/config/config.php

# grep -A 4 trusted /usr/local/www/nextcloud/config/config.php
  'trusted_domains' =>
  array (
    0 => '1.2.3.4',
    1 => 'nextcloud.domain.com',
  ),

You can of course add more with successive numbers.

# grep -A 5 trusted /usr/local/www/nextcloud/config/config.php
  'trusted_domains' =>
  array (
    0 => '1.2.3.4',
    1 => 'nextcloud.domain.com',
    2 => 'cloud.domain.com',
  ),

This is the end of this guide. Feel free to share your thougths πŸ™‚

Log Rotation with Newsyslog

Newsyslog is part of FreeBSD’s base system. We will add Nextcloud and backend daemons log files to Newsyslog configuration so they will be rotated.

 
# cat  /etc/newsyslog.conf
/data/nextcloud.log                          www:www     640  7     *    @T00  JC
/usr/local/www/nextcloud/data/nextcloud.log  www:www     640  7     *    @T00  JC
/var/log/php-fpm.log                         www:www     640  7     *    @T00  JC
/var/log/nginx/error.log                     www:www     640  7     *    @T00  JC
/var/log/nginx/access.log                    www:www     640  7     *    @T00  JC
EOF

Now you will not run out of free space when logs will grow in time.

EOF

Β 

48 thoughts on “Nextcloud 17 on FreeBSD 12.1

    1. vermaden Post author

      To be frank with you, I see the way Apple goes with Mac OS X (now macOS) and iOS as very disappointing – probably in all/most aspects. For example their Touch Bar is not bad idea if it was fit ABOVE ESC/F1/F2/…F12 line of keys but using it instead of these keys is just stupid. Same with lack of USB-A ports or lack of SD Memory Card slot … or dropping MagSafe connector for power …

      I hope that one day they will move to ARM64 for both MacBooks and iPads/iPhones and maybe their new unified system based on ARM64 will bring something more interesting then today’s offerings and state of the play.

      Regards,
      vermaden

      Like

      Reply
      1. Eddy.

        Didn’t take long for your dream of Macs moving to ARM64. The M-series chips are now up to second-gen and I think third-gen is on the horizon for late 2023.

        Liked by 1 person

  1. Pingback: Nextcloud 17 on FreeBSD 12.1 | 0ddn1x: tricks with *nix

  2. Pingback: Valuable News – 2020/01/13 | πšŸπšŽπš›πš–πšŠπšπšŽπš—

  3. fd0

    Hi
    Great wite-up!

    Have you considered and tested separation of front-end and back-end into separate jails, where postgress would ony be accessible through a rfc1918 network interface? Would be nice to see that…

    Like

    Reply
    1. vermaden Post author

      Thank you.

      .. about splitting the Nextcloud install into multiple containers/microservices (or just Jails in FreeBSD language) I would make the split into these parts:

      – Jail0 = Nextcloud + Nginx
      – Jail1 = php-fpm
      – Jail2 = Redis or Memcached
      – Jail3 = PostgreSQL

      Would like to hear of you would make different choice πŸ™‚

      Regards.

      Like

      Reply
      1. fd0

        my first setup will be an all in one jail.
        Will also try Nextcloud Hub instead of the Freebsd ports/pkgs version

        cheers, fd0

        Like

      2. vermaden Post author

        > My first setup will be an all in one jail.
        Good luck, its good way to first go the easy way to figure things out and then complicate πŸ™‚

        > Will also try Nextcloud Hub instead of the Freebsd ports/pkgs version
        I used compiled from FreeBSD Ports version (PostgreSQL support needed that) but what is the benefit of using Nextcloud Hub here? (I just do not know and I am curious :>)

        Regards.

        Like

  4. Alex

    Hello,
    Just wanted to add an security information from nextcloud.com considering nginx:
    https://nextcloud.com/blog/urgent-security-issue-in-nginx-php-fpm/

    1. Change: remove $request_uri;
    #######
    location / {
    rewrite ^ /index.php$request_uri;
    }
    —————————————
    > should become:
    location / {
    rewrite ^ /index.php;
    }
    ##########

    2. Change: add try_files $fastcgi_script_name =404;
    ##########
    location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
    fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
    try_files $fastcgi_script_name =404;

    Best regards
    Alex

    Like

    Reply
  5. fred

    After starting the backend services, I get this message in nginx’s error.log:

    2020/03/27 12:42:49 [error] 35105#100498: *61 upstream prematurely closed connection while reading response header from upstream, client: 172.16.1.2, server:
    cloud.domain.de, request: “GET / HTTP/1.1”, upstream: “fastcgi://172.16.1.2:9000”, host: “localhost”

    —–
    root@nextcloud:~ # curl -vvv localhost
    * Trying 127.0.0.1:80…
    * TCP_NODELAY set
    * Connected to localhost (172.16.1.2) port 80 (#0)
    > GET / HTTP/1.1
    > Host: localhost
    > User-Agent: curl/7.68.0
    > Accept: */*
    >
    * Mark bundle as not supporting multiuse
    < HTTP/1.1 502 Bad Gateway
    < Server: nginx
    < Date: Fri, 27 Mar 2020 11:49:23 GMT
    < Content-Type: text/html
    < Content-Length: 150
    < Connection: keep-alive
    <

    502 Bad Gateway

    502 Bad Gateway
    nginx

    * Connection #0 to host localhost left intact

    Like

    Reply
  6. Simon Kaffe Myers

    Howdy!
    This looks good, but I get into issues pretty quickly. I figure it is a local issue somehow, but I’m a complete dud in this area and don’t really know how to troubleshoot.

    I have set up a full jail and it’s a fresh installation, haven’t done anything besides following your guide.

    # grep postgres rc.conf
    postgresql_enable=YES
    postgresql_class=postgres
    postgresql_data=/var/db/postgres/data12

    # /usr/local/etc/rc.d/postgresql initdb
    su: unknown class: postgres

    # service postgresql start
    pg_ctl: directory “/var/db/postgres/data12” does not exist

    Seems like I’m missing some instruction, but then there probably would be not only be me reporting this, so I wonder where the pebkac happened, really…

    Like

    Reply
    1. vermaden Post author

      # /usr/local/etc/rc.d/postgresql initdb
      su: unknown class: postgres

      You need to create the postgres login class.

      # service postgresql start
      pg_ctl: directory β€œ/var/db/postgres/data12” does not exist

      You need to create /var/db/postgres/data12 directory.

      Hope that helps.

      Like

      Reply
  7. Simon Kaffe Myers

    Sadly, it does not. The login is created via the installation of postgres itself and is present and creating the directory just tells me it isn’t a database cluster directory. But I don’t wanna spam up your comment field with my personal server issues, so I’ll do some digging on my own. Hopefully I’ll get it working soon enough. :]

    Like

    Reply
    1. vermaden Post author

      The login is created via the installation of postgres itself and is present and creating the directory just tells me it isn’t a database cluster directory.

      I am not talking about user (or sometimes called login) but about LOGIN CLASS.

      This is strictly FreeBSD thing. Check more here:
      https://freebsd.org/handbook/users-synopsis.html @ 3.3.1.2. User Accounts
      https://man.freebsd.org/login.conf

      Here is how I set postgres login class in this guide:

      # tail -5 /etc/login.conf

      postgres:\
      :lang=en_US.UTF-8:\
      :setenv=LC_COLLATE=C:\
      :tc=default:

      # cap_mkdb /etc/login.conf

      Hope that helps more πŸ™‚

      Like

      Reply
  8. Simon Kaffe Myers

    Both yes and no, still didn’t work for me. However, I realized I parsed your guide incorrectly the first time around. Your replies has put me on the right path, and I’ll likely get it going soon enough once I get the time. Besides the guide itself, thanks for the input. :]

    Like

    Reply
  9. Maurizio

    Thank you for this guide, I am installing the Nextcloud v. 18 in a FreeBSD jail, but I haven’t understand the memcached use. In /etc/make.conf the line:
    OPTIONS_SET+= REDIS
    enable the REDIS option, the MEMCACHED option remain unset.
    Should be memcached enabled in /usr/local/www/nextcloud/config/config.php ?

    Regards
    Maurizio

    Like

    Reply
    1. vermaden Post author

      It was some time ago but I suspect that I wanted to use Memcached (as with older Nextcloud) and for some reason I moved to Redis instead πŸ™‚

      Like

      Reply
  10. Manuel

    When I run cap_mkdb /etc/login.conf

    she answers me:
    /usr/local/etc/rc.d/postgresql initdb
    ld-elf.so.1: Shared object “libicui18n.so.66” not found, required by “postgres”
    no data was returned by command “” / usr / local / bin / postgres “-V”
    initdb: error: The program “postgres” is needed by initdb but was not found in the
    same directory as “/ usr / local / bin / initdb”.
    Check your installation.
    It’s installed libicui18n.so.67.1
    How can I solve that?
    Greetings Manuel

    Like

    Reply
      1. Manuel

        Thanks for the reply.
        I have searched devel / icu and it is not installed.
        In ports there is no icu package.
        How should I install it.
        Regards.

        Like

  11. Pingback: #StackBounty: #nginx #iis #freenas #nextcloud Nextcloud in a FreeNAS jail served by NGINX behind a reverse proxy by IIS – TechUtils.in

  12. Manuel

    Hi.
    I have created a jail for the nextcloud files, “srv / data”. with “zfs create -o mountpoint = / srv / data zroot / srv / data”
    But when I want to access it when starting nextcloud, it tells me “Error while trying to create admin user: Failed to connect to the database: An exception occurred in driver: SQLSTATE [HY000] [2002] No such file or directory”
    Any ideas to fix it?
    Regards.

    Like

    Reply
      1. Manuel

        Hi.
        yes.
        root@Almayate:/usr/home/Manuel # ls -l -a /srv/
        total 36
        drwxr-xr-x 7 root wheel 7 Aug 18 18:45 .
        drwxr-xr-x 20 root wheel 26 Aug 19 20:45 ..
        drwxrwxrwx 2 www www 4 Aug 18 19:47 data
        drwxr-xr-x 19 root wheel 23 Aug 18 13:21 nextcloud
        drwxr-xr-x 4 root wheel 4 Aug 16 17:17 www

        Like

      2. vermaden Post author

        As you have problem with SQL it is probably postgres/postgresql user related and now www:www user/group related …

        IMHO start over as I do not know in which part you have the problem.

        Like

  13. marinos

    Hi, I’m followin these instructions throughout – but using php74 – and when using my browser to connect for the first time I get a “Internal Server Error – The server was unable to complete your request. …” message.

    Like

    Reply
    1. vermaden Post author

      Hi,

      the problem is probably in the php-fpm or nginx configuration.

      Generally these kind of error occur when nginx does not know how to ‘interpret’ the PHP files.

      Look for error messages in the php-fpm and/or nginx logs.

      Hope that helps.

      Like

      Reply
  14. Jason C

    Hello,
    First off, thanks for writing your guide. Everything was clear and I didn’t run into any problems until the very end with logging into Nextcloud.

    The initial configuration of Nextcloud with the web browser didn’t work and I get an error of “Could not fetch list of apps from the app store.”
    I confirmed that I could ping ‘apps.nextcloud.com’ so I don’t think it’s a firewall issue.
    The only option then is to ‘cancel’ and now I when I try to log in thru the web using the root account I get a redirect problem.

    >
    192.168.0.11 redirected you too many times.
    Try clearing your cookies.
    ERR_TOO_MANY_REDIRECTS
    >

    I don’t see any problems in the nginx error.log or php-fpm.log. But the nginx access.log shows many many requests
    192.168.0.113 – – [14/Mar/2021:16:33:22 -0500] “GET /settings/admin/serverinfoto HTTP/2.0”
    192.168.0.113 – – [14/Mar/2021:16:33:22 -0500] “GET /apps/files/ HTTP/2.0”
    192.168.0.113 – – [14/Mar/2021:16:33:22 -0500] “GET /apps/files/ HTTP/2.0”
    192.168.0.113 – – [14/Mar/2021:16:33:22 -0500] “GET /apps/files/ HTTP/2.0”
    192.168.0.113 – – [14/Mar/2021:16:33:22 -0500] “GET /apps/files/ HTTP/2.0”
    192.168.0.113 – – [14/Mar/2021:16:33:22 -0500] “GET /apps/files/ HTTP/2.0”
    192.168.0.113 – – [14/Mar/2021:16:33:22 -0500] “GET /apps/files/ HTTP/2.0”
    192.168.0.113 – – [14/Mar/2021:16:33:22 -0500] “GET /apps/files/ HTTP/2.0”
    192.168.0.113 – – [14/Mar/2021:16:33:22 -0500] “GET /apps/files/ HTTP/2.0”
    etc.

    Since the configuration didn’t complete, there was no /apps or /apps/files/ directories in /data/ so I thought that creating these directories might help. Nope.
    I thought maybe the ownership was wrong, so I changed it from root:wheel to www:www. But same problem.
    I also tried installing again without the link from /data to /usr/local/www/nextcloud/data, but again no change

    One other thing I don’t understand that may or may not be related is that I can’t log in as ‘nextcloud’ even though there is an entry for it in the nextcloud config.php. Maybe because initial config didn’t complet?

    So, I’m wondering if there’s any obvious thing I should try next?

    Like

    Reply
    1. vermaden Post author

      Hi,

      I am not sure which part could go wrong but I would just start over being very careful to make sure each instruction and command executed as described in the guide. With so many steps its very easy to make one small mistake omitting a single command that later would make your whole setup unusable … I do not know what else I can suggest to You 😦

      Hope that helps.

      Regards.

      Like

      Reply
  15. Jason C

    OK, because I’m stubborn I couldn’t stand the thought of starting over. I tried a couple more random changes I found.
    First, I changed the owner and group of the entire /usr/local/www/nextcloud directory to www:www as mentioned here
    https://help.nextcloud.com/t/install-fail-on-vanilla-server-running-freebsd-nctest-12-2-release-p3-freebsd-12-2-release-p3/106140/5
    No change, unfortunately.

    I then tried a solution here: https://www.truenas.com/community/threads/err_too_many_redirects-erro-after-nexcloud-20-0-4-plugin-install.89674/page-2
    Basically, the apps were installed into apps-pkg/, but Nextcloud looks for them in apps/. So move them all over and restart the Nextcloud install/config process.
    Success!
    Everything *seems* to be working now. Hopefully nothing else breaks, because at this point it’s 90% your knowledge Vermaden, 10% stubbornness on my part. And maybe a little luck thrown in.

    Thanks again for your help.

    Like

    Reply
    1. vermaden Post author

      Hi,

      glad You got it working mate.

      Someone also wrote to me what may be needed to fix that, here is his message:

      Prior to start the configuration on the interface you need to:

      # cp config.sample.php config.php

      This is because of (snippet from the config.sample.php)

      —– BEGIN SNIPPET —–

      /** The FreeBSD package separates apps into bundled apps and user-
      * installed apps. If this ‘apps_paths’ array is missing from
      * your config, your Nextcloud installation is broken
      */
      ‘apps_paths’ =>
      array (
      0 =>
      array (
      ‘path’ => ‘/usr/local/www/nextcloud/apps’,
      ‘url’ => ‘/apps’,
      ‘writable’ => true,
      ),
      1 =>
      array (
      ‘path’ => ‘/usr/local/www/nextcloud/apps-pkg’,
      ‘url’ => ‘/apps-pkg’,
      ‘writable’ => false,
      ),
      ),

      —– END SNIPPET —–

      Other parameters you’ll specify at setup stage, will be appended to these lines.

      If you don’t put this, you’ll end up in an error 404 while loading /index.php/apps/files/, and you’re unable to continue the setup.

      Hope that helps πŸ™‚

      Like

      Reply
      1. Jason C

        Thanks for passing that along. Hope I don’t need to reinstall in the future, but I’m at least somewhat confident now I could get it done successfully.
        Progress!

        Like

      2. vermaden Post author

        Remember the original Nextcloud 12 article? I still maintain that instance and upgraded it several times since then. Its at Nextcloud 20 and FreeBSD 12.2 now πŸ™‚ Updating Nextcloud is quite nice actually. I have used the browser method but you may use the CLI method as well.

        Regards.

        Like

  16. Sebastian

    This is the most comprehesive and useful writeup on Nextcloud in a FreeBSD jail, thanks a ton!

    I carried out the installation process on a FreeBSD 13.1 system with NC 25, postgreSQL 15 and nginx 1.22.1.
    Virtually the whole writeup was applicable, only a few quirks here and there.

    Just one thing: leaving pastgreSQL open with trust to each and every user without a password seemed a bit lax to me so I modified the corresponding entries in /var/db/postgres/data15/pg_hba.conf.

    Liked by 1 person

    Reply
  17. Dawid Kellerman

    I have to say THANK YOU! I refer to this manual on a weekly basis I run about 8 separate instances at this point and this old dog wants control over PostgreSQL versions and php control. Thank you for teaching me portmaster and getting me comfortable with PostgreSQL . With su its the first time I really understand rights and do things the proper way each service with its own user. Also I added a backup script to the whole mix same as you would the vacuum.sh

    #!/bin/sh
    
    #
    # su - postgres -c 'crontab -e'
    # 0 0 * * * /var/db/postgres/bin/vacuum.sh
    # 0 0 * * * /var/db/postgres/bin/pg_backup.sh
    #
    # Configuration
    DB_HOST="localhost"     # Database host
    DB_PORT="5432"          # Database port
    DB_USER="postgres"      # Database username
    BACKUP_DIR="/var/db/postgres/backup"  # Backup directory
    MAX_BACKUPS=14          # Number of backups to keep
    
    
    # Date and time for the backup file
    BACKUP_DATE=$(date +%Y-%m-%d_%H-%M-%S)
    
    # Create the backup directory if it doesn't exist
    mkdir -p "$BACKUP_DIR"
    
    # Get a list of databases
    DATABASES=$(psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -l -t | awk -F '|' '{gsub(/^[[:space:]]+|[[:space:]]+$/, "", $1); print $1}')
    
    # Loop through each database and perform backup
    for DATABASE in $DATABASES; do
        # Filename for the backup file
        BACKUP_FILE="${BACKUP_DIR}/${DATABASE}_${BACKUP_DATE}.sql"
    
        # Perform the backup using pg_dump
        pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -Fc "$DATABASE" > "$BACKUP_FILE"
    
        # Compress the backup file using xz with level 6 compression
        xz -6 "$BACKUP_FILE"
    
        # Print backup status
        if [ $? -eq 0 ]; then
            echo "Backup of database '$DATABASE' completed successfully: ${BACKUP_FILE}.xz"
        else
            echo "Backup of database '$DATABASE' failed!"
        fi
    done
    
    # Remove older backups exceeding the maximum number of backups to keep
    BACKUP_FILES=$(ls -t "$BACKUP_DIR"/*.sql.xz)
    COUNT=$(echo "$BACKUP_FILES" | wc -l | awk '{print $1}')
    if [ "$COUNT" -gt "$MAX_BACKUPS" ]; then
        REMOVE_COUNT=$((COUNT - MAX_BACKUPS))
        echo "$BACKUP_FILES" | tail -n "$REMOVE_COUNT" | while read -r FILE; do
            rm "$FILE"
            echo "Removed backup: $FILE"
        done
    fi
    chmod 600 "$BACKUPFILES"
    

    Like

    Reply
    1. vermaden Post author

      Thanks. Good to know that this quite older guide still has its purpose πŸ™‚

      … and thanks for sharing the backup script!

      Regards,
      vermaden

      Like

      Reply
    2. vermaden Post author

      Hi, thank You and sorry for late reply πŸ™‚

      … and thank you for sharing your script – I will definitely look into it :>

      Regards,
      vermaden

      Like

      Reply

Leave a comment