Nextcloud 15 installation guide (Ubuntu/NGINX)


Nextcloud advanced installation guide


Following this guide you will be able to install and configure Nextcloud 15 latest based on Ubuntu 18.04.x LTS, NGINX 1.15.8, TLSv1.2 or TLSv1.3, PHP 7.3new, MariaDB 10.3, Redis, fail2ban, firewall (ufw) and will achieve an A+ rating from both, Nextcloud and Qualys SSL Labs. We will request and implement your ssl certificate(s) from Let’s Encrypt in chapter 5. You only have to ammend the red marked values (YOUR.DEDYN.IO, 192.168.2.x, ssh port 22) regarding your environment!


Pre-requirements

From my perspective the requirements for this guide may be rated as low: you only have to

  • provide a 64Bit Server (e.g. Intel NUC),
  • forward two ports (80 and 443) from internet (your router e.g. FritzBox or Speedport) to your internal Nextcloud server
  • and install the operating system Ubuntu 18.04 LTS (64Bit).

Last Updates:

January, 11th 2019:

– updated nextcloud.conf (woff2?) required from  Nextcloud 15.0.1

… the entire update history


Table of content

  1. Prepare your server and install NGINX 1.15.8
  2. PHP 7.3
  3. MariaDB 10.3
  4. Redis
  5. Nextcloud (SSL enabled, A+)
  6. fail2ban and firewall (ufw)
  7. Monitor your server using netdata
  8. Mount additonal storage to your Nextcloud
  9. Install postfix and configure system notification mails
  10. A second factor for ssh (2FA)

1. Prepare your server and install NGINX

If you are interested in compiling NGINX and operate with OpenSSL 1.1.1 + TLS 1.3 you may find detailed instructions here.

sudo -s
apt install wget gnupg2 -y
cd /usr/local/src
mv /etc/apt/sources.list /etc/apt/sources.list.bak && touch /etc/apt/sources.list
cat <<EOF >>/etc/apt/sources.list
deb http://archive.ubuntu.com/ubuntu bionic main multiverse restricted universe
deb http://archive.ubuntu.com/ubuntu bionic-security main multiverse restricted universe
deb http://archive.ubuntu.com/ubuntu bionic-updates main multiverse restricted universe
deb [arch=amd64] http://nginx.org/packages/mainline/ubuntu/ bionic nginx
deb [arch=amd64] http://mirror2.hs-esslingen.de/mariadb/repo/10.3/ubuntu bionic main
deb http://ppa.launchpad.net/ondrej/php/ubuntu bionic main
EOF
wget http://nginx.org/keys/nginx_signing.key && apt-key add nginx_signing.key
apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 4F4EA0AAE5267A6C
apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
apt update && apt upgrade -y && apt install software-properties-common zip unzip screen curl ffmpeg libfile-fcntllock-perl -y
add-apt-repository ppa:certbot/certbot -y && apt update && apt upgrade -y && apt install letsencrypt ssl-cert -y
apt remove nginx nginx-common nginx-full -y --allow-change-held-packages
apt install nginx -y

Modify NGINX:

systemctl enable nginx.service && apt-mark hold nginx

To update NGINX in the future just issue the following statement:

apt-mark unhold nginx && apt upgrade -y && apt-mark hold nginx

Change NGINX configuration:

mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak && vi /etc/nginx/nginx.conf

to:

user www-data;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
multi_accept on;
use epoll;
}
http {
server_names_hash_bucket_size 64;
upstream php-handler {
server unix:/run/php/php7.3-fpm.sock;
}
set_real_ip_from 127.0.0.1;
set_real_ip_from 192.168.2.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
include /etc/nginx/mime.types;
#include /etc/nginx/proxy.conf;
#include /etc/nginx/ssl.conf;
#include /etc/nginx/header.conf;
#include /etc/nginx/optimization.conf;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'"$host" sn="$server_name" '
'rt=$request_time '
'ua="$upstream_addr" us="$upstream_status" '
'ut="$upstream_response_time" ul="$upstream_response_length" '
'cs=$upstream_cache_status' ;
access_log /var/log/nginx/access.log main;
sendfile on;
send_timeout 3600;
tcp_nopush on;
tcp_nodelay on;
open_file_cache max=500 inactive=10m;
open_file_cache_errors on;
keepalive_timeout 65;
reset_timedout_connection on;
server_tokens off;
resolver 208.67.222.222 208.67.220.220 valid=30s;
resolver_timeout 5s;
include /etc/nginx/conf.d/*.conf;
}

Start NGINX:

service nginx restart

Create folders and apply permissions:

mkdir -p /var/nc_data /var/www/letsencrypt /usr/local/tmp/cache /usr/local/tmp/sessions /usr/local/tmp/apc /upload_tmp
chown -R www-data:www-data /upload_tmp /var/nc_data /var/www
chown -R www-data:root /usr/local/tmp/sessions /usr/local/tmp/cache /usr/local/tmp/apc

2. Install PHP

apt install php7.3-fpm php7.3-gd php7.3-mysql php7.3-curl php7.3-xml php7.3-zip php7.3-intl php7.3-mbstring php7.3-json php7.3-bz2 php7.3-ldap php-apcu imagemagick php-imagick php-smbclient -y

Awesome, PHP 7.3 is already installed. Verify your timezone settings

date

and if necessary set it properly

timedatectl set-timezone Europe/Berlin

Configure PHP:

cp /etc/php/7.3/fpm/pool.d/www.conf /etc/php/7.3/fpm/pool.d/www.conf.bak
cp /etc/php/7.3/cli/php.ini /etc/php/7.3/cli/php.ini.bak
cp /etc/php/7.3/fpm/php.ini /etc/php/7.3/fpm/php.ini.bak
cp /etc/php/7.3/fpm/php-fpm.conf /etc/php/7.3/fpm/php-fpm.conf.bak
sed -i "s/;env\[HOSTNAME\] = /env[HOSTNAME] = /" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/;env\[TMP\] = /env[TMP] = /" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/;env\[TMPDIR\] = /env[TMPDIR] = /" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/;env\[TEMP\] = /env[TEMP] = /" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/;env\[PATH\] = /env[PATH] = /" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/pm.max_children = .*/pm.max_children = 240/" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/pm.start_servers = .*/pm.start_servers = 20/" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/pm.min_spare_servers = .*/pm.min_spare_servers = 10/" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/pm.max_spare_servers = .*/pm.max_spare_servers = 20/" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/;pm.max_requests = 500/pm.max_requests = 500/" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/output_buffering =.*/output_buffering = 'Off'/" /etc/php/7.3/cli/php.ini
sed -i "s/max_execution_time =.*/max_execution_time = 1800/" /etc/php/7.3/cli/php.ini
sed -i "s/max_input_time =.*/max_input_time = 3600/" /etc/php/7.3/cli/php.ini
sed -i "s/post_max_size =.*/post_max_size = 10240M/" /etc/php/7.3/cli/php.ini
sed -i "s/;upload_tmp_dir =.*/upload_tmp_dir = \/upload_tmp/" /etc/php/7.3/cli/php.ini
sed -i "s/upload_max_filesize =.*/upload_max_filesize = 10240M/" /etc/php/7.3/cli/php.ini
sed -i "s/max_file_uploads =.*/max_file_uploads = 100/" /etc/php/7.3/cli/php.ini
sed -i "s/;date.timezone.*/date.timezone = Europe\/\Berlin/" /etc/php/7.3/cli/php.ini
sed -i "s/;session.cookie_secure.*/session.cookie_secure = True/" /etc/php/7.3/cli/php.ini
sed -i "s/;session.save_path =.*/session.save_path = \"N;700;\/usr\/local\/tmp\/sessions\"/" /etc/php/7.3/cli/php.ini
sed -i '$aapc.enable_cli = 1' /etc/php/7.3/cli/php.ini
sed -i "s/memory_limit = 128M/memory_limit = 512M/" /etc/php/7.3/fpm/php.ini
sed -i "s/output_buffering =.*/output_buffering = 'Off'/" /etc/php/7.3/fpm/php.ini
sed -i "s/max_execution_time =.*/max_execution_time = 1800/" /etc/php/7.3/fpm/php.ini
sed -i "s/max_input_time =.*/max_input_time = 3600/" /etc/php/7.3/fpm/php.ini
sed -i "s/post_max_size =.*/post_max_size = 10240M/" /etc/php/7.3/fpm/php.ini
sed -i "s/;upload_tmp_dir =.*/upload_tmp_dir = \/upload_tmp/" /etc/php/7.3/fpm/php.ini
sed -i "s/upload_max_filesize =.*/upload_max_filesize = 10240M/" /etc/php/7.3/fpm/php.ini
sed -i "s/max_file_uploads =.*/max_file_uploads = 100/" /etc/php/7.3/fpm/php.ini
sed -i "s/;date.timezone.*/date.timezone = Europe\/\Berlin/" /etc/php/7.3/fpm/php.ini
sed -i "s/;session.cookie_secure.*/session.cookie_secure = True/" /etc/php/7.3/fpm/php.ini
sed -i "s/;opcache.enable=.*/opcache.enable=1/" /etc/php/7.3/fpm/php.ini
sed -i "s/;opcache.enable_cli=.*/opcache.enable_cli=1/" /etc/php/7.3/fpm/php.ini
sed -i "s/;opcache.memory_consumption=.*/opcache.memory_consumption=128/" /etc/php/7.3/fpm/php.ini
sed -i "s/;opcache.interned_strings_buffer=.*/opcache.interned_strings_buffer=8/" /etc/php/7.3/fpm/php.ini
sed -i "s/;opcache.max_accelerated_files=.*/opcache.max_accelerated_files=10000/" /etc/php/7.3/fpm/php.ini
sed -i "s/;opcache.revalidate_freq=.*/opcache.revalidate_freq=1/" /etc/php/7.3/fpm/php.ini
sed -i "s/;opcache.save_comments=.*/opcache.save_comments=1/" /etc/php/7.3/fpm/php.ini
sed -i "s/;session.save_path =.*/session.save_path = \"N;700;\/usr\/local\/tmp\/sessions\"/" /etc/php/7.3/fpm/php.ini
sed -i "s/;emergency_restart_threshold =.*/emergency_restart_threshold = 10/" /etc/php/7.3/fpm/php-fpm.conf
sed -i "s/;emergency_restart_interval =.*/emergency_restart_interval = 1m/" /etc/php/7.3/fpm/php-fpm.conf
sed -i "s/;process_control_timeout =.*/process_control_timeout = 10s/" /etc/php/7.3/fpm/php-fpm.conf
sed -i '$aapc.enabled=1' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.file_update_protection=2' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.optimization=0' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.shm_size=256M' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.include_once_override=0' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.shm_segments=1' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.ttl=7200' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.user_ttl=7200' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.gc_ttl=3600' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.num_files_hint=1024' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.enable_cli=0' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.max_file_size=5M' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.cache_by_default=1' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.use_request_time=1' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.slam_defense=0' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.mmap_file_mask=/usr/local/tmp/apc.XXXXXX' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.stat_ctime=0' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.canonicalize=1' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.write_lock=1' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.report_autofilter=0' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.rfc1867=0' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.rfc1867_prefix =upload_' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.rfc1867_name=APC_UPLOAD_PROGRESS' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.rfc1867_freq=0' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.rfc1867_ttl=3600' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.lazy_classes=0' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.lazy_functions=0' /etc/php/7.3/fpm/php.ini
sed -i "s/09,39.*/# &/" /etc/cron.d/php
(crontab -l ; echo "09,39 * * * * /usr/lib/php/sessionclean 2>&1") | crontab -u root -

Modify /etc/fstab

Determine the uid of your www-data user by issuing

id www-data

and only if it differs from ‘uid=33‘ replace the ‘uid=33‘ in the following rows properly before executing them!

sed -i '$atmpfs /usr/local/tmp/apc tmpfs defaults,uid=33,size=300M,noatime,nosuid,nodev,noexec,mode=1777 0 0' /etc/fstab
sed -i '$atmpfs /usr/local/tmp/cache tmpfs defaults,uid=33,size=300M,noatime,nosuid,nodev,noexec,mode=1777 0 0' /etc/fstab
sed -i '$atmpfs /usr/local/tmp/sessions tmpfs defaults,uid=33,size=300M,noatime,nosuid,nodev,noexec,mode=1777 0 0' /etc/fstab

OPTIONAL:

sed -i '$atmpfs /tmp tmpfs defaults,noatime,nosuid,nodev,noexec,mode=1777 0 0' /etc/fstab
sed -i '$atmpfs /var/tmp tmpfs defaults,noatime,nosuid,nodev,noexec,mode=1777 0 0' /etc/fstab

Mount tmpfs and then restart both, PHP and NGINX:

mount -a && service php7.3-fpm restart && service nginx restart

3. MariaDB

If you are interested in Postgresql instead of MariaDB please have a look here. Update your system and install MariaDB:

apt update && apt install mariadb-server -y

Verify your database server version:

mysql --version

A version like …

mysql Ver 15.1 Distrib 10.3.12-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2

10.3.12-MariaDB… should appear.

Secure MariaDB:

mysql_secure_installation
Enter current password for root (enter for none): <ENTER> or type the password
Set root password? [Y/n] Y

If already set during the MariaDB installation you will be asked wether to change or keep the 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

Configure MariaDB:

service mysql stop
mv /etc/mysql/my.cnf /etc/mysql/my.cnf.bak && vi /etc/mysql/my.cnf

Paste the following rows:

[client]
port = 3306
socket = /var/run/mysqld/mysqld.sock
default-character-set = utf8mb4
[mysqld_safe]
log_error=/var/log/mysql/mysql_error.log
socket = /var/run/mysqld/mysqld.sock
nice = 0
[mysqld]
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
log_error=/var/log/mysql/mysql_error.log
general_log_file = /var/log/mysql/mysql.log
general_log = 0
socket = /var/run/mysqld/mysqld.sock
port = 3306
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
lc_messages_dir = /usr/share/mysql
lc_messages = en_US
skip-external-locking
skip-name-resolve
bind-address = 127.0.0.1
max_connections = 200
connect_timeout = 5
wait_timeout = 600
max_allowed_packet = 16M
thread_cache_size = 128
sort_buffer_size = 4M
bulk_insert_buffer_size = 16M
tmp_table_size = 64M
max_heap_table_size = 64M
myisam_recover_options = BACKUP
key_buffer_size = 128M
#open-files-limit = 2000
table_open_cache = 400
myisam_sort_buffer_size = 512M
concurrent_insert = 2
read_buffer_size = 2M
read_rnd_buffer_size = 1M
query_cache_limit = 2M
query_cache_size = 64M
query_cache_type = 1
query_cache_min_res_unit = 2k
log_warnings = 2
slow_query_log_file = /var/log/mysql/mariadb-slow.log
long_query_time = 1
log_slow_verbosity = query_plan
slow-query-log = 1
slow-query-log-file = /var/log/mysql/slow.log
log_bin = /var/log/mysql/mariadb-bin
log_bin_index = /var/log/mysql/mariadb-bin.index
expire_logs_days = 10
max_binlog_size = 100M
default_storage_engine = InnoDB
innodb_buffer_pool_size = 1024M
innodb_buffer_pool_instances = 1
innodb_flush_log_at_trx_commit = 2
innodb_log_buffer_size = 32M
innodb_max_dirty_pages_pct = 90
innodb_file_per_table = 1
innodb_open_files = 400
innodb_io_capacity = 4000
innodb_flush_method = O_DIRECT
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
transaction_isolation = READ-COMMITTED
binlog_format = ROW
[mysqldump]
quick
quote-names
max_allowed_packet = 16M
[mysql]
#no-auto-rehash    # faster start of mysql but no tab completion
[isamchk]
key_buffer = 16M
!include /etc/mysql/mariadb.cnf
!includedir /etc/mysql/conf.d/

Restart MariaDB:

service mysql restart

Create the database and the user:

mysql -h localhost -uroot -p -e "CREATE DATABASE nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER nextcloud@localhost identified by 'nextcloud'; GRANT ALL PRIVILEGES on nextcloud.* to nextcloud@localhost; FLUSH privileges;"

Verify the transaction Isolation level was set to READ_Commit and the collation was set to UTF8MB4 properly:

mysql -h localhost -uroot -p -e "SELECT @@TX_ISOLATION; SELECT SCHEMA_NAME 'database', default_character_set_name 'charset', DEFAULT_COLLATION_NAME 'collation' FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='nextcloud'"

If the resultset will be “READ-COMMITTED” and “utf8mb4_general_ci” as shown go ahead with the installation of redis.


4. Redis

apt update && apt install redis-server php-redis -y

Change configuration and group membership:

cp /etc/redis/redis.conf /etc/redis/redis.conf.bak
sed -i "s/port 6379/port 0/" /etc/redis/redis.conf
sed -i s/\#\ unixsocket/\unixsocket/g /etc/redis/redis.conf
sed -i "s/unixsocketperm 700/unixsocketperm 770/" /etc/redis/redis.conf 
sed -i "s/# maxclients 10000/maxclients 512/" /etc/redis/redis.conf
usermod -a -G redis www-data
cp /etc/sysctl.conf /etc/sysctl.conf.bak && sed -i '$avm.overcommit_memory = 1' /etc/sysctl.conf

Reboot your server:

shutdown -r now

5. Create the nextcloud.conf:

sudo -s
mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak && touch /etc/nginx/conf.d/default.conf && vi /etc/nginx/conf.d/nextcloud.conf

Paste the following rows:

server {
server_name YOUR.DEDYN.IO;
listen 80 default_server;
location ^~ /.well-known/acme-challenge {
proxy_pass http://127.0.0.1:81;
proxy_set_header Host $host;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
server_name YOUR.DEDYN.IO;
listen 443 ssl http2 default_server;
root /var/www/nextcloud/;
access_log /var/log/nginx/nextcloud.access.log main;
error_log /var/log/nginx/nextcloud.error.log warn;
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;
}
#SOCIAL app enabled? Please uncomment the following three rows
#rewrite ^/.well-known/webfinger /public.php?service=webfinger last;
#rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
#rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;
client_max_body_size 10240M;
location / {
rewrite ^ /index.php$uri;
}
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
deny all;
}
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ \.(?:flv|mp4|mov|m4a)$ {
mp4;
mp4_buffer_size 100M;
mp4_max_buffer_size 1024M;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
include php_optimization.conf;
fastcgi_pass php-handler;
fastcgi_param HTTPS on;
}
location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
include php_optimization.conf;
fastcgi_pass php-handler;
fastcgi_param HTTPS on;
}
location ~ ^/(?:updater|ocs-provider)(?:$|/) {
try_files $uri/ =404;
index index.php;
}
location ~ \.(?:css|js|woff2?|svg|gif|png|html|ttf|ico|jpg|jpeg)$ {
try_files $uri /index.php$uri$is_args$args;
access_log off;
expires 360d;
}
}

If you want your Nextcloud running in a subdir like https://your.dedyn.io/nextcloud use this nextcloud.conf instead:

server {
server_name your.dedyn.io;
listen 80 default_server;
location ^~ /.well-known/acme-challenge {
proxy_pass http://127.0.0.1:81;
proxy_set_header Host $host;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
server_name your.dedyn.io;
listen 443 ssl http2 default_server;
root /var/www/;
access_log /var/log/nginx/nextcloud.access.log main;
error_log /var/log/nginx/nextcloud.error.log warn;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location = /.well-known/carddav {
return 301 $scheme://$host/nextcloud/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host/nextcloud/remote.php/dav;
}
#SOCIAL app enabled? Please uncomment the following three rows
#rewrite ^/.well-known/webfinger /nextcloud/public.php?service=webfinger last;
#rewrite ^/.well-known/host-meta /nextcloud/public.php?service=host-meta last;
#rewrite ^/.well-known/host-meta.json /nextcloud/public.php?service=host-meta-json last;
client_max_body_size 10240M;
location ^~ /nextcloud {
location /nextcloud {
rewrite ^ /nextcloud/index.php$uri;
}
location ~ ^/nextcloud/(?:build|tests|config|lib|3rdparty|templates|data)/ {
deny all;
}
location ~ ^/nextcloud/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ \.(?:flv|mp4|mov|m4a)$ {
mp4;
mp4_buffer_size 100M;
mp4_max_buffer_size 1024M;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
include php_optimization.conf;
fastcgi_pass php-handler;
fastcgi_param HTTPS on;
}
location ~ ^/nextcloud/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
include php_optimization.conf;
fastcgi_pass php-handler;
fastcgi_param HTTPS on;
}
location ~ ^/nextcloud/(?:updater|ocs-provider)(?:$|/) {
try_files $uri/ =404;
index index.php;
}
location ~ \.(?:png|html|ttf|ico|jpg|jpeg|css|js|woff2?|svg|gif)$ {
try_files $uri /nextcloud/index.php$uri$is_args$args;
access_log off;
expires 360d;
}
}
}

Create the letsencrypt.conf:

vi /etc/nginx/conf.d/letsencrypt.conf

Paste the following rows:

server {
server_name 127.0.0.1;
listen 127.0.0.1:81 default_server;
charset utf-8;
access_log /var/log/nginx/le.access.log main;
error_log /var/log/nginx/le.error.log warn;
location ^~ /.well-known/acme-challenge {
default_type text/plain;
root /var/www/letsencrypt;
}
}

Create the ssl.conf:

vi /etc/nginx/ssl.conf

Paste the following rows:

ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
ssl_trusted_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
#ssl_certificate /etc/letsencrypt/live/YOUR.DEDYN.IO/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/YOUR.DEDYN.IO/privkey.pem;
#ssl_trusted_certificate /etc/letsencrypt/live/YOUR.DEDYN.IO/chain.pem;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384';
ssl_ecdh_curve secp521r1:secp384r1:prime256v1;
ssl_prefer_server_ciphers on;
ssl_stapling on;
ssl_stapling_verify on;

OPTIONAL (If you compiled NGINX 1.15.8 with OpenSSL 1.1.1) add

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384';
ssl_early_data on;

Create the proxy.conf

vi /etc/nginx/proxy.conf

Paste the following rows:

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_connect_timeout 3600;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
proxy_redirect off;

OPTIONAL (If you compiled NGINX 1.15.8 with OpenSSL 1.1.1) add:

proxy_set_header Early-Data $ssl_early_data;

Create the header.conf:

vi /etc/nginx/header.conf

Paste the following rows:

add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer" always;
add_header Feature-Policy "geolocation 'self'";

Create the optimization.conf:

vi /etc/nginx/optimization.conf

Paste the following rows:

fastcgi_read_timeout 3600;
fastcgi_buffers 64 64K;
fastcgi_buffer_size 256k;
fastcgi_busy_buffers_size 3840K;
fastcgi_cache_key $http_cookie$request_method$host$request_uri;
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
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;
gzip_disable "MSIE [1-6]\.";

Create the php_optimization.conf:

vi /etc/nginx/php_optimization.conf

Paste the following rows:

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param modHeadersAvailable true;
fastcgi_param front_controller_active true;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
fastcgi_cache_valid 404 1m;
fastcgi_cache_valid any 1h;
fastcgi_cache_methods GET HEAD;

Enhance security:

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

To leave screen press STRG+A following by ‘d’ – to resume run screen -r. Please be patient, it will take a while.

Restart NGINX:

sed -i s/\#\include/\include/g /etc/nginx/nginx.conf && service nginx restart

Download and extract Nextcloud:

cd /usr/local/src
wget https://download.nextcloud.com/server/releases/latest.tar.bz2 && tar -xjf latest.tar.bz2 -C /var/www && chown -R www-data:www-data /var/www/ && rm latest.tar.bz2

Request your ssl-certificate(s):

letsencrypt certonly -a webroot --webroot-path=/var/www/letsencrypt --rsa-key-size 4096 -d YOUR.DEDYN.IO

Apply the permissions using a permissions.sh script:

vi /root/permissions.sh

Paste the following rows:

#!/bin/bash
find /var/www/ -type f -print0 | xargs -0 chmod 0640
find /var/www/ -type d -print0 | xargs -0 chmod 0750
chown -R www-data:www-data /var/www/
chown -R www-data:www-data /upload_tmp/
chown -R www-data:www-data /var/nc_data/
chmod 0644 /var/www/nextcloud/.htaccess
chmod 0644 /var/www/nextcloud/.user.ini
chmod 600 /etc/letsencrypt/live/YOUR.DEDYN.IO/fullchain.pem
chmod 600 /etc/letsencrypt/live/YOUR.DEDYN.IO/privkey.pem
chmod 600 /etc/letsencrypt/live/YOUR.DEDYN.IO/chain.pem
chmod 600 /etc/letsencrypt/live/YOUR.DEDYN.IO/cert.pem
chmod 600 /etc/ssl/certs/dhparam.pem
exit 0

Run the script:

chmod +x /root/permissions.sh && /root/permissions.sh

Modify the ssl.conf and restart NGINX:

sed -i '/ssl-cert-snakeoil/d' /etc/nginx/ssl.conf
sed -i s/\#\ssl/\ssl/g /etc/nginx/ssl.conf
service nginx restart

Create a certificate renewal automatism:

sed -i "s/SHELL=*/# &/" /etc/cron.d/certbot
sed -i "s/PATH=*/# &/" /etc/cron.d/certbot
sed -i "s/0 =*/# &/" /etc/cron.d/certbot
vi /root/renewal.sh

Paste the following rows

#!/bin/bash
cd /etc/letsencrypt
letsencrypt renew
result=$(find /etc/letsencrypt/live/ -type l -mtime -1 )
if [ -n "$result" ]; then
/usr/sbin/service nginx stop
/usr/sbin/service mysql restart
/usr/sbin/service redis-server restart
/usr/sbin/service php7.3-fpm restart
/usr/sbin/service nginx restart
fi
exit 0

Make it exectuable and create a cronjob

chmod +x /root/renewal.sh && crontab -e

Paste the red row below existing ones:

09,39 * * * * /usr/lib/php/sessionclean 2>&1
@monthly /root/renewal.sh 2>&1

Install Nextcloud silently

sudo -u www-data php /var/www/nextcloud/occ maintenance:install --database "mysql" --database-name "nextcloud" --database-user "nextcloud" --database-pass "nextcloud" --admin-user "YourNextcloudAdmin" --admin-pass "YourNextcloudAdminPasssword" --data-dir "/var/nc_data"

Information:

–database-user “nextcloud” : As set above while creating the database and user

–database-pass “nextcloud” : As set above while creating the database and user

–admin-user “YourNextcloudAdmin” : your free choice

–admin-pass “YourNextcloudAdminPasssword” : your free choice

Finish the installation, then make ammendments to your config.php as www-data:

sudo -u www-data php /var/www/nextcloud/occ config:system:set trusted_domains 1 --value=your.dedyn.io
sudo -u www-data php /var/www/nextcloud/occ config:system:set overwrite.cli.url --value=https://your.dedyn.io
sudo -u www-data cp /var/www/nextcloud/config/config.php /var/www/nextcloud/config/config.php.bak

Expand your Nextcloud config.php:

sudo -u www-data sed -i 's/^[ ]*//' /var/www/nextcloud/config/config.php
sudo -u www-data sed -i '/);/d' /var/www/nextcloud/config/config.php
sudo -u www-data cat <<EOF >>/var/www/nextcloud/config/config.php
'activity_expire_days' => 14,
'auth.bruteforce.protection.enabled' => true,
'blacklisted_files' => 
array (
0 => '.htaccess',
1 => 'Thumbs.db',
2 => 'thumbs.db',
),
'cron_log' => true,
'enable_previews' => true,
'enabledPreviewProviders' => 
array (
0 => 'OC\\Preview\\PNG',
1 => 'OC\\Preview\\JPEG',
2 => 'OC\\Preview\\GIF',
3 => 'OC\\Preview\\BMP',
4 => 'OC\\Preview\\XBitmap',
5 => 'OC\\Preview\\Movie',
6 => 'OC\\Preview\\PDF',
7 => 'OC\\Preview\\MP3',
8 => 'OC\\Preview\\TXT',
9 => 'OC\\Preview\\MarkDown',
),
'filesystem_check_changes' => 0,
'filelocking.enabled' => 'true',
'htaccess.RewriteBase' => '/',
'integrity.check.disabled' => false,
'knowledgebaseenabled' => false,
'logfile' => '/var/nc_data/nextcloud.log',
'loglevel' => 2,
'logtimezone' => 'Europe/Berlin',
'log_rotate_size' => 104857600,
'maintenance' => false,
'memcache.local' => '\\OC\\Memcache\\APCu',
'memcache.locking' => '\\OC\\Memcache\\Redis',
'overwriteprotocol' => 'https',
'preview_max_x' => 1024,
'preview_max_y' => 768,
'preview_max_scale_factor' => 1,
'redis' => 
array (
'host' => '/var/run/redis/redis-server.sock',
'port' => 0,
'timeout' => 0.0,
),
'quota_include_external_storage' => false,
'share_folder' => '/Shares',
'skeletondirectory' => '',
'theme' => '',
'trashbin_retention_obligation' => 'auto, 7',
'updater.release.channel' => 'stable',
);
EOF

Edit the .user.ini:

sudo -u www-data sed -i "s/upload_max_filesize=.*/upload_max_filesize=10240M/" /var/www/nextcloud/.user.ini
sudo -u www-data sed -i "s/post_max_size=.*/post_max_size=10240M/" /var/www/nextcloud/.user.ini
sudo -u www-data sed -i "s/output_buffering=.*/output_buffering='Off'/" /var/www/nextcloud/.user.ini
service php7.3-fpm restart && service redis-server restart && service nginx restart

Adjust Nextcloud

sudo -u www-data php /var/www/nextcloud/occ config:system:set 'auth.bruteforce.protection.enabled' --value=false
sudo -u www-data php /var/www/nextcloud/occ app:disable survey_client
sudo -u www-data php /var/www/nextcloud/occ app:disable firstrunwizard
sudo -u www-data php /var/www/nextcloud/occ app:enable admin_audit
sudo -u www-data php /var/www/nextcloud/occ app:enable files_pdfviewer

Logon to your brandly new Nextcloud in your browser

https://your.dedyn.io/login

If the integrity check within Nextcloud will fail, try to change the config.php

sudo -u www-data vi /var/www/nextcloud/config/config.php

and set :

'integrity.check.disabled' => true,

Then restart all services:

service php7.3-fpm restart && service redis-server restart && service nginx restart

Re-run the integrity check and set the value back to ‘false’:

sudo -u www-data vi /var/www/nextcloud/config/config.php
'integrity.check.disabled' => false,

Restart all services again.

service php7.3-fpm restart && service redis-server restart && service nginx restart

and the message should disappear!


Optimize your Nextcloud once (a) and regulary (b) using a script

(a)

/usr/sbin/service nginx stop
sudo -u www-data php /var/www/nextcloud/occ db:add-missing-indices
sudo -u www-data php /var/www/nextcloud/occ db:convert-filecache-bigint
/usr/sbin/service nginx start

(infos: BigInt, missing indices)

(b)

vi /root/optimize.sh
#!/bin/bash
redis-cli -s /var/run/redis/redis-server.sock <<EOF
FLUSHALL
quit
EOF
sudo -u www-data php /var/www/nextcloud/occ files:scan --all
sudo -u www-data php /var/www/nextcloud/occ files:scan-app-data
exit 0

Save the script and mark it as executable

chmod +x /root/optimize.sh

Issue the optimize.sh script initially:

/root/optimize.sh

Add Nextcloud cronjobs for www-data and root

For www-data:

crontab -u www-data -e

Paste the following rows

*/15 * * * * php -f /var/www/nextcloud/cron.php > /dev/null 2>&1

For root:

crontab -e

Paste the follwoing rows:

5 1 * * * /root/optimize.sh > /dev/null 2>&1

Don’t forget to switch from Ajax to Cron in Nextclouds-Adminpanel or use Nextcloud CLI to switch immediately:

sudo -u www-data php /var/www/nextcloud/occ background:cron

Finally verify your server security level

(1)

https://www.ssllabs.com/ssltest/analyze.html?d=your.dedyn.io

(2)

https://scan.nextcloud.com

(3)

https://observatory.mozilla.org/analyze/your.dedyn.io


6. Harden your System using fail2ban and ufw

First install and configure fail2ban and finally configure the firewall ufw to secure and harden Nextcloud.

Install and configure fail2ban:

sudo -s
apt update && apt install fail2ban -y

Create the Nextcloud-filter:

vi /etc/fail2ban/filter.d/nextcloud.conf

Paste the following rows to the fail2ban filter for Nextcloud (or download as txt file to avoid WordPress-code-issues!):

[Definition]
failregex=^{"reqId":".*","remoteAddr":".*","app":"core","message":"Login failed: '.*' \(Remote IP: '<HOST>'\)","level":2,"time":".*"}$
            ^{"reqId":".*","level":2,"time":".*","remoteAddr":".*","app":"core".*","message":"Login failed: '.*' \(Remote IP: '<HOST>'\)".*}$
            ^.*\"remoteAddr\":\"<HOST>\".*Trusted domain error.*$

Create a new jail:

vi /etc/fail2ban/jail.d/nextcloud.local

Paste the following rows:

[nextcloud]
backend = auto
enabled = true
port = 80,443
protocol = tcp
filter = nextcloud
maxretry = 3
bantime = 36000
findtime = 36000
logpath = /var/nc_data/nextcloud.log

[nginx-http-auth]
enabled = true

Re-start the fail2ban-service:

service fail2ban restart

Configure your ufw (uncomplicated firewall):

apt install ufw -y && ufw allow 80/tcp && ufw allow 443/tcp && ufw allow 22/tcp

Enable and restart ufw by running

ufw logging medium && ufw default deny incoming && ufw enable && service ufw restart

6.1 Harden your Nextcloud using Spamhaus Project and UFW

If you’d like to prevent “unprivileged visitors” just create the script /root/ufw-spamhaus.sh and block them by ufw directly.

vi /root/ufw-spamhaus.sh

Paste the following rows:

#!/bin/bash
# Thanks to @ank0m
EXEC_DATE=`date +%Y-%m-%d`
SPAMHAUS_DROP="/usr/local/src/drop.txt"
SPAMHAUS_eDROP="/usr/local/src/edrop.txt"
URL="https://www.spamhaus.org/drop/drop.txt"
eURL="https://www.spamhaus.org/drop/edrop.txt"
DROP_ADD_TO_UFW="/usr/local/src/DROP2.txt"
eDROP_ADD_TO_UFW="/usr/local/src/eDROP2.txt"
DROP_ARCHIVE_FILE="/usr/local/src/DROP_$EXEC_DATE"
eDROP_ARCHIVE_FILE="/usr/local/src/eDROP_$EXEC_DATE"
# All credits for the following BLACKLISTS goes to "The Spamhaus Project" - https://www.spamhaus.org
echo "Start time: $(date)"
echo " "
echo "Download daily DROP file:"
wget -q -O - "$URL" > $SPAMHAUS_DROP
grep -v '^;' $SPAMHAUS_DROP | cut -d ' ' -f 1 > $DROP_ADD_TO_UFW
echo " "
echo "Extract DROP IP addresses and add to UFW:"
cat $DROP_ADD_TO_UFW | while read line
do
/usr/sbin/ufw insert 1 deny from "$line" comment 'DROP_Blacklisted_IPs'
done
echo " "
echo "Downloading eDROP list and import to UFW"
echo " "
echo "Download daily eDROP file:"
wget -q -O - "$eURL" > $SPAMHAUS_eDROP
grep -v '^;' $SPAMHAUS_eDROP | cut -d ' ' -f 1 > $eDROP_ADD_TO_UFW
echo " "
echo "Extract eDROP IP addresses and add to UFW:"
cat $eDROP_ADD_TO_UFW | while read line
do
/usr/sbin/ufw insert 1 deny from "$line" comment 'eDROP_Blacklisted_IPs'
done
echo " "
#####
## To remove or revert these rules, keep the list of IPs!
## Run a command like so to remove the rules:
# while read line; do ufw delete deny from $line; done < $ARCHIVE_FILE
#####
echo "Backup DROP IP address list:"
mv $DROP_ADD_TO_UFW $DROP_ARCHIVE_FILE
echo " "
echo "Backup eDROP IP address list:"
mv $eDROP_ADD_TO_UFW $eDROP_ARCHIVE_FILE
echo " "
echo End time: $(date)

Make the script exutable by issuing

chmod +x /root/ufw-spamhaus.sh

and configure it in your crontab to be issued automatically.

(crontab -l ; echo "10 2 * * * /root/ufw-spamhaus.sh 2>&1") | crontab -u root -

Finally perform an initial run

/root/ufw-spamhaus.sh

and many UFW rules will be applied immediately. Be patient, it may take a while.


Monitor your entire system using netdata

Start download netdata – the directory ‘netdata’ will be created

apt install apache2-utils git gcc make autoconf automake pkg-config uuid-dev zlib1g-dev
cd /usr/local/src
git clone https://github.com/firehol/netdata.git --depth=1
cd netdata

Create a passwordfile to protect netdata:

htpasswd -c /etc/nginx/netdata-access YourName

Then run the script netdata-installer.sh with root privileges to build, install and start netdata

./netdata-installer.sh

Netdata is already installed. We will make smaller adjustementss to netdata’s configuration:

vi /etc/netdata/netdata.conf

First we change the value for “history” to e.g. 14400 (4 hours of chart data retention, uses about 60 MB of RAM) in the [global] section:

 history = 14400

Then we change the binding in the [web] section to localhost (127.0.0.1) only:

 bind to = 127.0.0.1

Finally we enhance the nextcloud.conf and nginx.conf file to include the netdata webserver-configuration:

vi /etc/nginx/conf.d/nextcloud.conf

Paste the red rows as shown below to the nextcloud.conf:

...
location / {
 rewrite ^ /index.php$uri;
 }
location /netdata {
 return 301 /netdata/;
 }
 location ~ /netdata/(?<ndpath>.*) {
 auth_basic "Restricted Area";
 auth_basic_user_file /etc/nginx/netdata-access;
 proxy_http_version 1.1;
 proxy_pass_request_headers on;
 proxy_set_header Connection "keep-alive";
 proxy_store off;
 proxy_pass http://netdata/$ndpath$is_args$args;
 gzip on;
 gzip_proxied any;
 gzip_types *;
 }
 location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
 deny all;
...

Your entire nextcloud.conf should look like:

server {
server_name your.dedyn.io;
listen 80 default_server;
location ^~ /.well-known/acme-challenge {
proxy_pass http://127.0.0.1:81;
proxy_set_header Host $host;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
server_name your.dedyn.io;
listen 443 ssl http2 default_server;
root /var/www/nextcloud/;
access_log /var/log/nginx/nextcloud.access.log main;
error_log /var/log/nginx/nextcloud.error.log warn;
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;
}
client_max_body_size 10240M;
location / {
rewrite ^ /index.php$uri;
}
location /netdata {
return 301 /netdata/;
}
location ~ /netdata/(?<ndpath>.*) {
auth_basic "Restricted Area";
auth_basic_user_file /etc/nginx/netdata-access;
proxy_http_version 1.1;
proxy_pass_request_headers on;
proxy_set_header Connection "keep-alive";
proxy_store off;
proxy_pass http://netdata/$ndpath$is_args$args;
gzip on;
gzip_proxied any;
gzip_types *;
}
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
deny all;
}
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ \.(?:flv|mp4|mov|m4a)$ {
mp4;
mp4_buffer_size 100M;
mp4_max_buffer_size 1024M;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
include php_optimization.conf;
fastcgi_pass php-handler;
fastcgi_param HTTPS on;
}
location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
include php_optimization.conf;
fastcgi_pass php-handler;
fastcgi_param HTTPS on;
}
location ~ ^/(?:updater|ocs-provider)(?:$|/) {
try_files $uri/ =404;
index index.php;
}
location ~ \.(?:css|js|woff2?|svg|gif|png|html|ttf|ico|jpg|jpeg)$ {
try_files $uri /index.php$uri$is_args$args;
access_log off;
expires 360d;
}
}

Create the new /etc/nginx/conf.d/stub_status.conf:

vi /etc/nginx/conf.d/stub_status.conf

Paste all the following rows:

server {
listen 127.0.0.1:80 default_server;
server_name 127.0.0.1;
location /stub_status {
stub_status on;
allow 127.0.0.1;
deny all;
}
}

Save and quit the file (:wq!) and modify the file /etc/nginx/nginx.conf:

...
http {
 server_names_hash_bucket_size 64;
 upstream php-handler {
 server unix:/run/php/php7.3-fpm.sock;
 }
 upstream netdata {
 server 127.0.0.1:19999;
 keepalive 64;
 }
...

Your nginx.conf should look like:

user www-data;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
multi_accept on;
use epoll;
}
http {
server_names_hash_bucket_size 64;
upstream php-handler {
server unix:/run/php/php7.3-fpm.sock;
}
upstream netdata {
server 127.0.0.1:19999;
keepalive 64;
}
set_real_ip_from 127.0.0.1;
set_real_ip_from 192.168.2.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
include /etc/nginx/mime.types;
include /etc/nginx/proxy.conf;
include /etc/nginx/ssl.conf;
include /etc/nginx/header.conf;
include /etc/nginx/optimization.conf;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'"$host" sn="$server_name" '
'rt=$request_time '
'ua="$upstream_addr" us="$upstream_status" '
'ut="$upstream_response_time" ul="$upstream_response_length" '
'cs=$upstream_cache_status' ;
access_log /var/log/nginx/access.log main;
sendfile on;
send_timeout 3600;
tcp_nopush on;
tcp_nodelay on;
open_file_cache max=500 inactive=10m;
open_file_cache_errors on;
keepalive_timeout 65;
reset_timedout_connection on;
server_tokens off;
resolver 208.67.222.222 208.67.220.220 valid=30s;
resolver_timeout 5s;
include /etc/nginx/conf.d/*.conf;
}

Save and quit the file (:wq!) and check NGINX

nginx -t

If no errors appear just restart netdata and nginx

service netdata restart && service nginx restart

and call netdata in your browser

https://your.dedyn.io/netdata

or as an external site in your Nextcloud.


Mount additonal storage to your Nextcloud

(a) …using a NAS

(b) …using an external/additional HDD

You may enhance your Nextcloud with data from your NAS-share or an external hdd.


(a) mount your NAS data to a specific Nextcloud-user

It is really simple to mount a NAS share to your Nextcloud using cifs. First install cifs-utils:

apt install cifs-utils -y

Then store your credentials to a special file (e.g. /root/.smbcredentials)

vi /root/.smbcredentials

Write down your username and password:

username=NASuser
password=NASPassword

Save and quit (:wq!) the file and change the permissions to 0600:

chmod 400 /root/.smbcredentials

Detect the ID of the webuser (www-data) using the id-command:

id www-data

and keep the id in mind to reuse it in /etc/fstab:

cp /etc/fstab /etc/fstab.bak
vi /etc/fstab

Paste the following to the end of fstab

//<NAS>/<share> /var/nc_data/next/files cifs user,uid=33,rw,iocharset=utf8,suid,credentials=/root/.smbcredentials,file_mode=0770,dir_mode=0770 0 0

Please substitue “//<NAS>/<share>“, next and if neccessary the uid=”33” and then try to mount your NAS manually first:

mount //<NAS>/<share>/

or

mount -a

To unmount your NAS manually run

umount //<NAS>/<share>/

or

umount -a

It will be neccessary to rescan your data for the first usage once. So change to your Nextcloud directory and execute Nextclouds files:scan for the relevant Nextcloud-user (e.g. next) or all (–all):

service nginx stop
cd /var/www/nextcloud
redis-cli -s /var/run/redis/redis-server.sock
FLUSHALL
quit
sudo -u www-data php occ files:scan --all -v
sudo -u www-data php occ files:scan-app-data -v
service nginx start

After Nextclouds files:scan all of your NAS data will appear in the Nextcloud file-app.
The permissions-script <permission.sh> should be enhanced to umount and mount the new mounted NAS share:

vi /root/permissions.sh

Add the red lines to the existing script:

#!/bin/bash
find /var/www/ -type f -print0 | xargs -0 chmod 0640
find /var/www/ -type d -print0 | xargs -0 chmod 0750
chown -R www-data:www-data /var/www/
chown -R www-data:www-data /upload_tmp/
umount //<NAS>/<share>
chown -R www-data:www-data /var/nc_data/
mount //<NAS>/<share>
chmod 0644 /var/www/nextcloud/.htaccess
chmod 0644 /var/www/nextcloud/.user.ini
chmod 600 /etc/letsencrypt/live/yourcloud.dedyn.io/fullchain.pem
chmod 600 /etc/letsencrypt/live/yourcloud.dedyn.io/privkey.pem
chmod 600 /etc/letsencrypt/live/yourcloud.dedyn.io/chain.pem
chmod 600 /etc/letsencrypt/live/yourcloud.dedyn.io/cert.pem
chmod 600 /etc/ssl/certs/dhparam.pem

Please substitute the red ones accordingly to your environment, then save and quit (:wq!) the file. From now, your NAS will always be available in Nextcloud for the specific user.


(b) mount an external hdd to your Nextcloud

We prepare the new drive ‘/dev/sda‘ for the use in Nextcloud. Please format it with an ‘ext4’ file system and mount it permanently with an entry in /etc/fstab.

Stop your server (NGINX, PHP, MariaDB, Redis) services and check the availability of the new drive:

sudo -s
service nginx stop && service php7.3-fpm stop && service redis-server stop && service mysql stop
fdisk -l /dev/sda

If available, make a new partition with the fdisk command.

fdisk /dev/sda
  1. Type ‘o’ to create a new partition table.
  2. Type ‘n’ to create a new partition.
  3. Choose the primary partition type, input ‘p’.
  4. Partition Number – we just need 1.
  5. Leave all default on the First sector and Last sector – Press Enter.
  6. Type ‘w’ and press enter to write the partition.

The ‘/dev/sda1’ partition has been created, now we have to format it to ‘ext4’ with the mkfs tool. Then check the volume size.

mkfs.ext4 /dev/sda1
fdisk -s /dev/sda1

Next, create a new local ‘nc_data’ directory and mount ‘/dev/sda1’ to that directory.

sudo mkdir -p /nc_data

To mount new disk permanently, we add the new mount configuration to the fstab file. Open fstab with vom:

vi /etc/fstab

Paste the configuration below at the end of the file.

/dev/sda1     /nc_data     ext4     defaults     0     1

Save fstab and exit:

Now mount the disk and make sure that there is no error.

mount -a
df -h

At least you have to move your current Nextcloud data direcory to the new mounted directory

chown -R www-data:www-data /nc_data
rsync -av /var/nc_data/ /nc_data

and point to it in Nextcloud’s config.php.

sudo -u www-data vi /var/www/nextcloud/config/config.php

Change the data-directory

...
'datadirectory' => '/nc_data',
...

Finally restart your server services and perform a new filescan:

service nginx stop && service php7.3-fpm restart && service redis-server restart && service mysql restart
cd /var/www/nextcloud
redis-cli -s /var/run/redis/redis-server.sock 
quit
sudo -u www-data php occ files:scan --all -v
sudo -u www-data php occ files:scan-app-data -v
service nginx restart

From now, your Nextcloud data will be stored on your external HDD.


Install POSTFIX to send server mails

(a) configure fail2ban system-notification mails

(b) install apticron and configure system update-notification mails


First install two packages: postfix and libsasl2-modules

apt install postfix libsasl2-modules mailutils -y

and start configuring your mailserver. When the postfix-Installationscreen appears select <sattelitesystem>

&copy; 2016, rieger::CLOUD

Postfix will ask you for the system emailname, you can confirm the shown entry e.g. yourcloud. Then you were asked for the smtp-relayservername e.g. w12345.kasserver.com. Please fill in your according mailservername.

&copy;2016, rieger::CLOUD

Finish the installation <OK>. Now edit the configuration of postfix

cp /etc/postfix/main.cf /etc/postfix/main.cf.bak
vi /etc/postfix/main.cf

and add the following lines

...
smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/sasl_password

Save and quit (:wq!) this file.

Our complete but exemplarily main.cf:

smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no
append_dot_mydomain = no
readme_directory = no
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
myhostname = your.dedyn.io
mydomain = your.dedyn.io
myorigin = $mydomain
smtp_tls_CApath = /etc/ssl/certs
smtpd_tls_CApath = /etc/ssl/certs
smtpd_tls_received_header = yes
smtp_tls_loglevel = 1
smtpd_tls_loglevel = 1
smtpd_use_tls=yes
smtp_use_tls=yes
smtpd_tls_protocols = TLSv1.2, !TLSv1.1, !SSLv2, !SSLv3
smtp_tls_protocols = TLSv1.2, !TLSv1.1, !SSLv2, !SSLv3
smtpd_tls_ciphers = high
smtp_tls_ciphers = high
smtpd_tls_cert_file = /etc/letsencrypt/live/your.dedyn.io/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/your.dedyn.io/privkey.pem
smtp_tls_cert_file = /etc/letsencrypt/live/your.dedyn.io/fullchain.pem
smtp_tls_key_file = /etc/letsencrypt/live/your.dedyn.io/privkey.pem
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mydestination = $myhostname, your.dedyn.io, localhost.localdomain, localhost
relayhost = your.mail-smtpserver.com:587
smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/sasl_password
sender_canonical_maps = hash:/etc/postfix/sender_canonical
mynetworks = 127.0.0.0/8
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = loopback-only
inet_protocols = all
compatibility_level=2

Create a new file containing your credentials to connect to your mailserver.

vi /etc/postfix/sasl_password

Enter your credentials like exemplarily shown

your.mail-smtpserver.com a987654:PassWorD

and change the access level of this file to 600.

chmod 600 /etc/postfix/sasl_password

At least we promote the information to postfix.

postmap hash:/etc/postfix/sasl_password

As default mails would be sent as user@hostname (e.g. root@localhost), but a lot of mailserver would reject those mails. That’s why we add a new row to postfix configuration file:

vi /etc/postfix/main.cf

If not exists add the following line to the config file

...
sender_canonical_maps = hash:/etc/postfix/sender_canonical

Save and quit (:wq!) the configuration and create the referred new file

vi /etc/postfix/sender_canonical

Add both lines and adjust the parameters according to your environment

root youremail@domain.com
www-data youremail@domain.com
<your-ubuntuuser-name> youremail@domain.com

This will assign your emailadress to the root and www-data users. We have to promote this information to postfix again

postmap /etc/postfix/sender_canonical

Finally we add postfix to the autostart and start the service

update-rc.d postfix defaults
service postfix restart

From now, you are already able to send system mails. Please verify the functionality

vi testmail.txt

Add any kind of text to your demofile, e.g.

My first system mail

Save and quit the testfile (:wq!) and send your first manual system mail

mail -s "Postfix-Testmail" yourmail@domain.com < testmail.txt

Check the logfile

cat /var/log/mail.log

and also check your mailclient if you already received that mail.

Postfix administration tasks:

[a] have a look in your actual mailqueue: mailq

[b] flush / re-send your mail(s)-queue: postfix flush

[c] delete all mails in your mailqueue: postsuper -d ALL


(a) configure fail2ban system-notification mails

We substitute the root-User in the fail2ban-config to receive status mails of fail2ban in the future. Those mails will contain both, the fail2ban-status (stopped/started) and in case of failed logins also the banned ip(‘s). Edit the fail2ban configuration file

cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.conf.bak
vi /etc/fail2ban/jail.conf

and substitute at least the red marked parameters according to your system:

...
destemail = yourmail@domain.com
...
sender = yourmail@domain.com
...
mta = mail
...
# action = %(action_)s
action = %(action_mwl)s
...

Save and quit (:wq!) the fail2ban configuration. To avoid (many) mails on every fail2ban-restart just create a new file and copy it as shown below:

vi /etc/fail2ban/action.d/mail-buffered.local

Paste the following rows

[Definition]
actionstart =
actionstop =

Copy the file

cp /etc/fail2ban/action.d/mail-buffered.local /etc/fail2ban/action.d/mail.local
cp /etc/fail2ban/action.d/mail-buffered.local /etc/fail2ban/action.d/mail-whois-lines.local
cp /etc/fail2ban/action.d/mail-buffered.local /etc/fail2ban/action.d/mail-whois.local
cp /etc/fail2ban/action.d/mail-buffered.local /etc/fail2ban/action.d/sendmail-buffered.local
cp /etc/fail2ban/action.d/mail-buffered.local /etc/fail2ban/action.d/sendmail-common.local

Re-start the fail2ban-service an you will (only) be informed if fail2ban blocked new IPs

service fail2ban restart

automatically.


(b) install apticron and configure system update-notification mails

If you use APTICRON, your system may send emails in case of available systemupdates either.

apt install apticron -y

After havin installed APTICRON you should edit the config and substitute at least your EMAIL, SYSTEM, NOTIFY_NO_UPDATES and CUSTOM_FROM.

cp /etc/apticron/apticron.conf /etc/apticron/apticron.conf.bak
vi /etc/apticron/apticron.conf
...
EMAIL="yourmail@domain.com"
...
SYSTEM="yourmail@domain.com"
...
NOTIFY_HOLDS="1"
...
NOTIFY_NO_UPDATES="1"
...
CUSTOM_SUBJECT='$SYSTEM: $NUM_PACKAGES package update(s)'
...
CUSTOM_NO_UPDATES_SUBJECT='$SYSTEM: no updates available'
...
CUSTOM_FROM="yourmail@domain.com"
...

To run and check APTICRON just call

apticron

and you will receive an email sent by APTICRON. Now you are a little bit more secure.

cp /etc/cron.d/apticron /etc/cron.d/apticron.bak
vi /etc/cron.d/apticron
30 7 * * * root if test -x /usr/sbin/apticron; then /usr/sbin/apticron --cron; else true; fi

Apticron will now be executed by cron.d. You can change the starttime e.g. to daily 7.30 AM.


A second factor for ssh (2FA – two factor authentication)

The following steps are system relevant (critical) and only recommended for advanced linux users. If the ssh configuration will fail, you won’t be able to login to your system via ssh anymore. The mandatory prerequisite is a ssh server that you can log on using private/public key only!

Install the software for 2FA (Two-Factor-Authentication) with your preferred OTP AUTH app

apt install libpam-google-authenticator -y

Leave the root-Shell and run the following command as your <your-ubuntu-user-name> and NOT as root:

exit
google-authenticator

You will be asked for:

Do you want authentication tokens to be time-based (y/n) y
&copy; 2016, c-rieger.de
Do you want me to update your "~/.google_authenticator" file (y/n) y
Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y
By default, tokens are good for 30 seconds and in order to compensate for
possible time-skew between the client and the server, we allow an extra
token before and after the current time. If you experience problems with poor
time synchronization, you can increase the window from its default
size of 1:30min to about 4min. Do you want to do so (y/n) n
If the computer that you are logging into isn't hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting (y/n) y

Change back to the root-Shell

sudo -s

Backup the current configuration and configure your ssh server

cp /etc/pam.d/sshd /etc/pam.d/sshd.bak
vi /etc/pam.d/sshd

Change the file to mine:

@include common-auth
@include common-password
auth required pam_google_authenticator.so
account required pam_nologin.so
@include common-account
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
session required pam_loginuid.so
session optional pam_keyinit.so force revoke
@include common-session
session optional pam_motd.so motd=/run/motd.dynamic
session optional pam_motd.so noupdate
session optional pam_mail.so standard noenv # [1]
session required pam_limits.so
session required pam_env.so # [1]
session required pam_env.so user_readenv=1 envfile=/etc/default/locale
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open

Save and quit (:wq!) the file.

If not already created please create your 4096 bit RSA Key (SSH) first:

cd ~
ssh-keygen -q -f /etc/ssh/ssh_host_rsa_key -N '' -b 4096 -t rsa

If you will be asked to overwrite the existing key, confirm with ‘Y’. Then backup, edit and change your SSH-config to examplarily mine

mv /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
vi /etc/ssh/sshd_config
# Port 22
Port 1234 #your decision, but keep UFW in mind!
Protocol 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
UsePrivilegeSeparation yes
KeyRegenerationInterval 3600
ServerKeyBits 4096
SyslogFacility AUTH
LogLevel INFO
LoginGraceTime 30s
PermitRootLogin no
StrictModes yes
RSAAuthentication yes
PubkeyAuthentication yes
IgnoreRhosts yes
UseDNS yes
RhostsRSAAuthentication no
HostbasedAuthentication no
IgnoreUserKnownHosts yes
PermitEmptyPasswords no
MaxAuthTries 3
MaxSessions 3
ChallengeResponseAuthentication yes
X11Forwarding yes
X11DisplayOffset 10
X11UseLocalhost no
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
Banner /etc/issue
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server
UsePAM yes
AllowTcpForwarding no
AllowUsers ubuntuuser #<your-ubuntu-user-name> for e.g. putty or ssh native
AuthenticationMethods publickey,password publickey,keyboard-interactive

If you changed the ssh-Port to e.g. 1234, please ensure having changed your ufw-configuration either and adjust the username in ‘AllowUsers ubuntuuser.

Paste your public key to the <ubuntuuser>’s keystore (ubuntu’s how-to):

vi ~/.ssh/authorized_keys

and set proper permissions:

sudo chown -R ubuntuuser:ubuntuuser ~/.ssh
sudo chmod 700 ~/.ssh
sudo chmod 600 ~/.ssh/authorized_keys

Then restart your ssh server

service ssh restart

and re-logon to your server using a new session-window. This is your final fallback, if you misconfigured your ssh server ;-). From now your privat key is needed, you will be prompted for your password and finally for your new second factor.

Public Key authentication and ssh-user password

Verification code (OTP 2FA)

Start your e.g. OTP AUTH or Google Authenticator app and read your second factor to gain access to your server.

Logged on

You will be logged on using your second factor.


Enjoy your personal data in your secured and hardened Nextcloud-Server!

Don’t forget to backup your Nextcloud

Find more instructions here: Nextcloud Backup and Restore



Carsten Rieger

Carsten Rieger

Carsten Rieger is a senior system engineer in full-time and also working as an IT freelancer. He is working with linux environments for more than 13 years, an Open Source enthusiast and highly motivated on linux installation and troubleshooting. Mostly working with Debian/Ubuntu Linux, Nginx and Apache web server, MariaDB/MySQL/PostgreSQL, PHP, Cloud infrastructure (e.g. Nextcloud) and other open source projects (e.g. Roundcube) and in voluntary work for the Dr. Michael & Angela Jacobi Stiftung for more than 7 years.

234 Responses

  1. Horst says:

    Hallo Herr Rieger,
    die Version 15.02 ist jetzt verfügbar. Müssen Ihre Änderungen Woff2? zu 15.01 trotzdem ausgeführt werden? Danke

  2. giulio says:

    hello carsten
    I state that I am not very practical but I have already followed your guide and I have already installed nextcloud perfectly. Now
    I had to take a nas synology (192.168.1.3 mydomain.ddns.net) and I’m doing the reverse proxy for my vm with nextcloud on another computer on the 192.168.1.10 network (nextmydomain.ddns.net). Synology has obtained the letsencrypt certificate for its applications. Nextcloud works well with your guide but I can not get the certificate letsencrypt. After several attempts I managed to put a certificate but it is synology (mydomain.ddns.net) so I receive an error message. I tried to follow your reverse proxy guide but I broke everything. What can it be? Thank you

    • what has crashed in detail? i didn’t get you: synology received ssl certificates successfully but nextcloud not? what happened on LE + Nextcloud side while obtaining the ssl certificates?

      • giulio says:

        when i try to get the certificate as per your guide i keep getting this error:
        letencrypt Domain: nextmydomain.ddns.net Type: unauthorized Detail: Invalid response from ecc..

        • Does your DNS point to your server ip correctly – is your server reachable using port 80 and 443?

          • giulio says:

            yes, by reverse proxy of my synology dsm 6.
            now I restarted everything from the beginning by just following your ubuntu nextcloud guide. I would like to tell you that the ppa for php7.3 is missing and in the nginx.conf file there is an opendns address with a 3 instead of 2. When you get to letsencrypt, I found the same error:
            The following errors were reported by the server:

                Domain: myreversedomain.ddns.net
                Type: unauthorized
                Detail: Invalid response from
                http://myreversedomain.ddns.net/.well-known/acme-challenge/o41-oxuAXsnEOSblPRyhXRit9UfWO1xUWT2WGBNOLDM:
                ” \ n \ n \ n \ n body {font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-alig ”

                To fix these errors, please make sure that your domain name was
                entered correctly and the DNS A / AAAA record (s) for that domain
                contain (s) the right IP address.

            • I changed the resolver entries already to resolver 208.67.222.222 208.67.220.220 valid=30s; – thank you! Regarding letsencrypt, ensiure your Firewall (e.g. router, ufw) are forwarding bot ports (80 and 443 to your server. That seems to be the root cause, as far as the A record was set properly?!

  3. Alex says:

    Hallo Carsten,
    wieder einmal eine exzellente Anleitung, Danke für Deine Mühen.
    Ich würde gerne ein bestehendes RAID1 aus 2 Platten als data directory benutzen, wie würde ich da (high level) am Besten vorgehen?
    Danke Dir und einen guten Start ins neue Jahr!

  4. Ludgerus says:

    Frohe Weihnachten wünsche ich Dir und Deiner Familie!
    Vielen Dank für deine unermüdliche Arbeit sie hat mir sehr geholfen!

    Ludgerus

  5. isaac says:

    Hi Carsten,

    Happy Holidays!

    I followed your instructions and installed nextcloud on an odroid c2 running ubuntu minimal on an 8gb emmc card. Then i ran a sync job from my synology nas to the odroid c2 nextcloud server via webdav and it was running fine until it suddenly stopped working. I found out that the 8gb emmc has been filled out with logs especially mysql and nginx logs and also turn logs for the TALK app. The webdav sync from the synology was configured not to erase files on the odroid c2 if they were deleted from the synolgoy.

    Isn’t there suppose to be a logrotate that removes the old logs and replace it with a new one? I ran the same webdav sync from the synology to an odroidc2 with ubunutu minimal 16.04 with nextcloud13 and its 8gb emmc card never got filled up.

    Any thoughts?

    Thanks very much again

    • Please verify lograte is installed – which logrotate. That should not happen.

      • isaac says:

        Thanks very much Carsten

        I’ll have to figure out what went wrong because logrotate is indeed installed, only i noticed that the Turn log are not included in /etc/logrotate.d. The turn logs dont seem to get compressed and rotated. Or maybe it was not the logs that was the culprit because now i cant start the mysql service and this event happened after a powerfailure. thanks again.

  6. Albert Hoffmann says:

    Hallo, ich hab leider ein Problem mit der Social App.
    .well-known/webfinger isn’t properly set up!
    Social needs the .well-known automatic discovery to be properly set up. If Nextcloud is not installed in the root of the domain, it is often the case that Nextcloud can’t configure this automatically. To use Social, the admin of this Nextcloud instance needs to manually configure the .well-known redirects: Open documentation ↗

    Weißt du zufällig wie ich das richtig konfiguriere? ich bin eigentlich schritt für schritt deiner anleitung gefolgt und hatte bisher keine Probleme.
    Danke schön

  7. Henning Schulze says:

    Hallo Carsten,

    vielen Dank für den Guide.

    Mich interessiert ob dieser Guide auch mit 16.04 funktioniert. Gibt es hier vielleicht auch ein passendes Repository für Ngnix?
    Gibt es sonst noch bekannte Fallstricke?

    Grüße Henning

    • Grundsätzlich schon …das Repo für NGINX wäre:
      deb http://nginx.org/packages/mainline/ubuntu/ xenial nginx
      deb-src http://nginx.org/packages/mainline/ubuntu/ xenial nginx

      MariaDB:
      sudo apt-get install software-properties-common
      sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
      sudo add-apt-repository 'deb [arch=amd64,arm64,i386,ppc64el] https://mirror.herrbischoff.com/mariadb/repo/10.3/ubuntu xenial main'

      PHP:
      sudo add-apt-repository -y ppa:ondrej/php
      Achtung: REDIS-Pfad muss mindestens in der config.php und ggf. im optimization.sh angepasst werden:
      'host' => '/var/run/redis/redis.sock',
      Grüße, Carsten

  8. Vladyslav says:

    I set up the server without fail2ban.

  9. Vladyslav says:

    I configured everything according to your instructions, everything works fine, but the Logging Log Reader (white sheet) does not work through the Admin account.

  10. Thomas says:

    Many thanks for this great tutorial! My new nextcloud works like a charm

  11. Peter says:

    After an update, I had to add to my.cnf:

    [mysqld]
    default_authentication_plugin=mysql_native_password

    • Why and what version are you operating on? What have been updated?
      My environment is based on Ubuntu 18.04 and 10.3.10-MariaDB – i don’t have to add it!

      • Peter says:

        mysql Ver 15.1 Distrib 10.1.34-MariaDB

        I was getting this error PHP message: PHP Fatal error: Uncaught DoctrineDBALDBALException: Failed to connect to the database: An exception occured in driver: SQLSTATE[HY000] [2002] No such file or directory in /var/www/…………/nextcloud/lib/private/DB/Connection.php:64

        (YOUR.DEDYN.IO removed)

  12. isaac says:

    Hi Carsten,,

    Should we still install postfix(smtp) based on you previous guide, if next cloud 14 asks us to configure smtp for the email service of our server?
    Thanks very much again

  13. Lars van Ravenzwaaij says:

    Hi Carsten,

    I finally got the time to secure my nextcloud with fail2ban as in your guide.

    But, … fail2ban refuses to restart ;-(

    The path for the nextcloud.log in your guide is /var/nc_data. In my installation the path is /var/data/nextcloud, so I made that amendment in the jail.d/nextcloud.local, but that doesn’t work.
    As soon as I remove the “logpath = “-statement completely, fail2ban can be started. Can you help me to solve this?

    Thanks Lars

    • Strange. Did you apply the proper permissions before and what error has been thrown if you changed the path? Does the nextcloud.log already exists while altering fail2ban?

  14. Vincent says:

    First, thank you for this write-up. I’m migrating from 16.04 and using this guide for a fresh install on a Hyper V environment with Ubuntu.

    I am however stuck at the step:

    Restart NGINX:

    sed -i s/#include/include/g /etc/nginx/nginx.conf && service nginx restart

    After this command, it returns:

    Job for nginx.service failed because the control process exited with error code.
    See “systemctl status nginx.service” and “journalctl -xe” for details.

    and:

    ● nginx.service – nginx – high performance web server
    Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
    Active: failed (Result: exit-code) since Thu 2018-11-01 03:30:20 EDT; 3min 10s ago
    Docs: http://nginx.org/en/docs/
    Process: 1962 ExecStop=/bin/kill -s TERM $MAINPID (code=exited, status=0/SUCCESS)
    Process: 2043 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=1/FAILURE)
    Main PID: 892 (code=exited, status=0/SUCCESS)

    Nov 01 03:30:20 Ubuntu-NextCloud systemd[1]: Starting nginx – high performance web server…
    Nov 01 03:30:20 Ubuntu-NextCloud nginx[2043]: nginx: [emerg] BIO_new_file(“/etc/ssl/certs/ssl-cert-snakeoil.pem”) failed (SSL: error:02001002:system library:
    Nov 01 03:30:20 Ubuntu-NextCloud systemd[1]: nginx.service: Control process exited, code=exited status=1
    Nov 01 03:30:20 Ubuntu-NextCloud systemd[1]: nginx.service: Failed with result ‘exit-code’.
    Nov 01 03:30:20 Ubuntu-NextCloud systemd[1]: Failed to start nginx – high performance web server.

    and:

    — The result is RESULT.
    Nov 01 03:24:08 Ubuntu-NextCloud systemd[1]: Starting nginx – high performance web server…
    — Subject: Unit nginx.service has begun start-up
    — Defined-By: systemd
    — Support: http://www.ubuntu.com/support

    — Unit nginx.service has begun starting up.
    Nov 01 03:24:08 Ubuntu-NextCloud nginx[1973]: nginx: [emerg] BIO_new_file(“/etc/ssl/certs/ssl-cert-snakeoil.pem”) failed (SSL: error:02001002:system library:
    Nov 01 03:24:08 Ubuntu-NextCloud systemd[1]: nginx.service: Control process exited, code=exited status=1
    Nov 01 03:24:08 Ubuntu-NextCloud systemd[1]: nginx.service: Failed with result ‘exit-code’.
    Nov 01 03:24:08 Ubuntu-NextCloud systemd[1]: Failed to start nginx – high performance web server.
    — Subject: Unit nginx.service has failed
    — Defined-By: systemd
    — Support: http://www.ubuntu.com/support

    — Unit nginx.service has failed.

    — The result is RESULT.
    Nov 01 03:27:29 Ubuntu-NextCloud systemd[1]: Starting nginx – high performance web server…
    — Subject: Unit nginx.service has begun start-up
    — Defined-By: systemd
    — Support: http://www.ubuntu.com/support

    — Unit nginx.service has begun starting up.
    Nov 01 03:27:29 Ubuntu-NextCloud nginx[1979]: nginx: [emerg] BIO_new_file(“/etc/ssl/certs/ssl-cert-snakeoil.pem”) failed (SSL: error:02001002:system library:
    Nov 01 03:27:29 Ubuntu-NextCloud systemd[1]: nginx.service: Control process exited, code=exited status=1
    Nov 01 03:27:29 Ubuntu-NextCloud systemd[1]: nginx.service: Failed with result ‘exit-code’.
    Nov 01 03:27:29 Ubuntu-NextCloud systemd[1]: Failed to start nginx – high performance web server.
    — Subject: Unit nginx.service has failed
    — Defined-By: systemd
    — Support: http://www.ubuntu.com/support

    — Unit nginx.service has failed.

    I am not an Ubuntu expert and only really know my way around Windows. Any help is much appreciated!

    I’ve tried this several times from scratch already and I’ve read thru the thread and comment and I haven’t seen others with the same issue.

    • It seems you forgot to install ssl-cert as mentioned at the early beginning of this guide. Please verify the self signed certificates do exist, e.g.: ls /etc/ssl/certs/ssl-cert-snakeoil.pem – if not issue sudo apt install ssl-cert -y && service nginx restart. Cheers Carsten

      • Vincent says:

        Thank you for your quick reply.

        I did as you suggested. ls did not find the file.

        I then issues the second command and it returned:

        Building dependency tree
        Reading state information… Done
        ssl-cert is already the newest version (1.0.39).
        The following packages were automatically installed and are no longer required:
        app-install-data apt-clone archdetect-deb btrfs-tools cryptsetup-bin
        dmeventd dmraid dpkg-repack gir1.2-timezonemap-1.0 gir1.2-xkl-1.0
        grub-pc-bin kpartx kpartx-boot libdebian-installer4 libdevmapper-event1.02.1
        libdmraid1.0.0.rc16 libido3-0.1-0 liblvm2app2.2 liblvm2cmd2.02
        libtimezonemap-data libtimezonemap1 lvm2 python3-pam rdate u-boot-tools
        Use ‘sudo apt autoremove’ to remove them.
        0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
        ==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ===
        Authentication is required to restart ‘nginx.service’.
        Authenticating as: vincent,,, (vincent)
        Password:
        ==== AUTHENTICATION COMPLETE ===
        Job for nginx.service failed because the control process exited with error code.
        See “systemctl status nginx.service” and “journalctl -xe” for details.

        and:

        ● nginx.service – nginx – high performance web server
        Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
        Active: failed (Result: exit-code) since Thu 2018-11-01 05:05:35 EDT; 1min 39s ago
        Docs: http://nginx.org/en/docs/
        Process: 2913 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=1/FAILURE)

        Nov 01 05:05:35 Ubuntu-NextCloud systemd[1]: Starting nginx – high performance web server…
        Nov 01 05:05:35 Ubuntu-NextCloud nginx[2913]: nginx: [emerg] BIO_new_file(“/etc/ssl/certs/ssl-cert-snakeoil.pem”) failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen(‘/etc/ssl/certs/ssl-cert-snakeoil.pem’,’r’) error:2006D080:BIO routines:BIO_new_file:no such file)
        Nov 01 05:05:35 Ubuntu-NextCloud systemd[1]: nginx.service: Control process exited, code=exited status=1
        Nov 01 05:05:35 Ubuntu-NextCloud systemd[1]: nginx.service: Failed with result ‘exit-code’.
        Nov 01 05:05:35 Ubuntu-NextCloud systemd[1]: Failed to start nginx – high performance web server.

        and:

        Nov 01 05:05:26 Ubuntu-NextCloud sudo[2897]: pam_unix(sudo:session): session ope
        Nov 01 05:05:27 Ubuntu-NextCloud sudo[2897]: pam_unix(sudo:session): session clo
        Nov 01 05:05:27 Ubuntu-NextCloud polkitd(authority=local)[766]: Registered Authe
        Nov 01 05:05:35 Ubuntu-NextCloud polkitd(authority=local)[766]: Operator of unix
        Nov 01 05:05:35 Ubuntu-NextCloud systemd[1]: Starting nginx – high performance w
        — Subject: Unit nginx.service has begun start-up
        — Defined-By: systemd
        — Support: http://www.ubuntu.com/support

        — Unit nginx.service has begun starting up.
        Nov 01 05:05:35 Ubuntu-NextCloud nginx[2913]: nginx: [emerg] BIO_new_file(“/etc/
        Nov 01 05:05:35 Ubuntu-NextCloud systemd[1]: nginx.service: Control process exit
        Nov 01 05:05:35 Ubuntu-NextCloud systemd[1]: nginx.service: Failed with result ‘
        Nov 01 05:05:35 Ubuntu-NextCloud systemd[1]: Failed to start nginx – high perfor
        — Subject: Unit nginx.service has failed
        — Defined-By: systemd
        — Support: http://www.ubuntu.com/support

        — Unit nginx.service has failed.

        — The result is RESULT.
        Nov 01 05:05:35 Ubuntu-NextCloud polkitd(authority=local)[766]: Unregistered Aut
        Nov 01 05:06:51 Ubuntu-NextCloud dmeventd[2965]: Cannot open lockfile [/run/dmev
        lines 2593-2615/2615 (END)
        Nov 01 05:05:26 Ubuntu-NextCloud sudo[2897]: pam_unix(sudo:session): session opened for user root by vincent(uid=0)
        Nov 01 05:05:27 Ubuntu-NextCloud sudo[2897]: pam_unix(sudo:session): session closed for user root
        Nov 01 05:05:27 Ubuntu-NextCloud polkitd(authority=local)[766]: Registered Authentication Agent for unix-process:2901:451994 (system bus name :1.72 [/usr/bin/pkttyagent –notify-fd 5 –fallback], object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale en_CA.UTF-8)
        Nov 01 05:05:35 Ubuntu-NextCloud polkitd(authority=local)[766]: Operator of unix-process:2901:451994 successfully authenticated as unix-user:vincent to gain ONE-SHOT authorization for action org.freedesktop.systemd1.manage-units for system-bus-name::1.73 [systemctl restart nginx.service] (owned by unix-user:vincent)
        Nov 01 05:05:35 Ubuntu-NextCloud systemd[1]: Starting nginx – high performance web server…
        — Subject: Unit nginx.service has begun start-up
        — Defined-By: systemd
        — Support: http://www.ubuntu.com/support

        — Unit nginx.service has begun starting up.
        Nov 01 05:05:35 Ubuntu-NextCloud nginx[2913]: nginx: [emerg] BIO_new_file(“/etc/ssl/certs/ssl-cert-snakeoil.pem”) failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen(‘/etc/ssl/certs/ssl-cert-snakeoil.pem’,’r’) error:2006D080:BIO routines:BIO_new_file:no such file)
        Nov 01 05:05:35 Ubuntu-NextCloud systemd[1]: nginx.service: Control process exited, code=exited status=1
        Nov 01 05:05:35 Ubuntu-NextCloud systemd[1]: nginx.service: Failed with result ‘exit-code’.
        Nov 01 05:05:35 Ubuntu-NextCloud systemd[1]: Failed to start nginx – high performance web server.
        — Subject: Unit nginx.service has failed
        — Defined-By: systemd
        — Support: http://www.ubuntu.com/support

        — Unit nginx.service has failed.

        — The result is RESULT.
        Nov 01 05:05:35 Ubuntu-NextCloud polkitd(authority=local)[766]: Unregistered Authentication Agent for unix-process:2901:451994 (system bus name :1.72, object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale en_CA.UTF-8) (disconnected from bus)
        Nov 01 05:06:51 Ubuntu-NextCloud dmeventd[2965]: Cannot open lockfile [/run/dmeventd.pid], error was [Permission denied]

        Just a note. I had thought I followed every step, double checking along the way.

        • Something went wrong – what has been logged during the installation of ssl-certs? From my perspective the installation failed or your permissions are not properly applied.
          As long as the ssl-certs are not created nginx won’t start following my guide. Please first ensure your self signed certificates are installed properly following UBUNTU Howto.
          Please also verify the permissions on /etc/ssl.

  15. Hirsyandi says:

    Thx for your tutorial, now it perfectly running on my dedicated server. But now came some confusing trouble, my server use 7x Hdd, and formated with raid, total space available approx 7Tb at least, but i see in space available in nextcloud monitoring menu, the space remaing 600Mb, why nextcloud not use all my available storage space? And how to make nextcloud to use all space available? Raid controlled by server, i use ubuntu 18.04 with guided partition and lvm, thx for your help sir, i’m sory for my bad english sir

  16. Mario says:

    Hi,

    bei Punkt 1 sollte die Zeile
    “deb http://nginx.org/packages/mainline/ubuntu/ bionic nginx”

    besser

    “deb [arch=amd64] http://nginx.org/packages/mainline/ubuntu/ bionic nginx”

    heissen, sonst bekommt man folgende Meldung beim update:
    “N: Skipping acquire of configured file ‘nginx/binary-i386/Packages’ as repository ‘http://nginx.org/packages/mainline/ubuntu bionic InRelease’ doesn’t support architecture ‘i386′”

    Gruss

  17. Marco says:

    Hi, kurze Frage zu deinen Guides. Ist es kein Risiko wenn alle das gleiche SQL DB Passwort „Nextcloud“ verwenden?
    Oder sollte dies geändert werden?
    Danke. Deine Guides sind wirklich klasse!

    • Danke! Ja, prinzipiell sollen Passwörter aus den Guides immer geändert werden, wobei die DB-Passwörter leider immer Klartext in der Nextcloud-Konfiguration stehen…Grüße, Carsten

  18. Stefan Seligmann says:

    Hi Carsten,
    my nextcloud actually is running on ubuntu 16.04. What would be the strategy tu upgrade to 18.04? Did you ever try an ‘in place’ upgrade (apt dist-upgrade)?
    Stefan

  19. Darek says:

    Great and complete tutorial. The first of those that I found on the Internet. Thank you.
    It would be useful to have information about the configuration of the case when the data folder is on an external disk (USB).

  20. Hartmut Funk says:

    Hallo Herr Rieger,

    vielen Dank für diese Anleitung. Habe es zusammen mit Ihrem Beitrag für Collabora installieren können, funktioniert alles prima.

    Nach vielen Versuchen der erste Beitrag, der auch funktioniert. SOllten wir es produktiv nutzen, würde ich gern Ihre Hilfe in Anspruch nehmen.

    Viele Grüße
    Hartmut Funk

  21. Thomas says:

    Hi I added the app circles to my nextcloud 14.
    I created some users in that circle and as described a fileshare should work.
    You can share files with that users from the circle but they never will get the share.
    There will be errormessages in nextcloud and I think it is about the configuration.
    I have made the configuration like you described here and tried a lot to solve it but without success.
    Maybe you can support me to solve my problem.

    Error message of nextcloud:

    Error index OCUserNoUserException: 2018-10-01T16:35:05+0200
    Error PHP Undefined index: circle_owner at /var/www/domain/nextcloud/apps/circles/lib/ShareByCircleProvider.php#651 2018-10-01T16:35:05+0200
    Error PHP Undefined index: circle_type at /var/www/domain/nextcloud/apps/circles/lib/ShareByCircleProvider.php#650

  22. Robin Johansson says:

    Hi,
    The Spamhouse configuration in this guide, can I use it on my WordPress site also?
    And maybe also in my Proxy?

  23. Klaus says:

    Hallo Hr. Rieger, wie funktioniert denn die Installation auf einem Odroid HC-1 ? Es gab von Ihnen mal eine Anleitung, die das Kompilieren des Nginx zeigte. So läuft meine NC 13 derzeit.
    Binärpakete von nginx.org sind für armhf wohl nicht verfügbar. Ich scheitere bereits bei Schritt mit einer entsprechenden Fehlermeldung. Danke und viele Grüße.

  24. Olle says:

    All of the PHP-packets does not exist in the standard repo. Where do I get them?

    • sudo -s
      mv /etc/apt/sources.list /etc/apt/sources.list.bak && vi /etc/apt/sources.list


      deb http://archive.ubuntu.com/ubuntu bionic main multiverse restricted universe
      deb http://archive.ubuntu.com/ubuntu bionic-security main multiverse restricted universe
      deb http://archive.ubuntu.com/ubuntu bionic-updates main multiverse restricted universe

      apt update

  25. Malte says:

    Hallo Herr Rieger,

    ich habe Nextcloud 14 und Nextcloud Talk nach der Anleitung installiert.
    Es funktioniert auch alles bis auf eine Fehlermeldung bestens.

    Jedes mal, wenn ein Viedeo hochgeladen wird und das entsprechende Vorschaubild generiert wird, kommt folgende Fehlermeldung:

    unlink(/upload_tmp/oc_tmp_MtwwCC): No such file or directory at /var/www/nextcloud/lib/private/Preview/Movie.php#111

    In der Dateiansicht ist das Vorschaubild auch vorhanden, also alles gut.
    Was hat es mit der Fehlermeldung auf sich? Was habe ich übersehen?

    Vielen Dank im Voraus.

  26. Andreas says:

    Hallo Herr Rieger,

    ich bekomme immer folgende Fehlermeldung:

    Die folgenden Pakete haben unerfüllte Abhängigkeiten:
    letsencrypt : Hängt ab von: certbot soll aber nicht installiert werden
    E: Probleme können nicht korrigiert werden, Sie haben zurückgehaltene defekte Pakete.

    Es handelt sich um eine frisch installierte Ubuntu 18.04.1 LTS in einer VMware ESXi Umgebung.

    • Hallo Andreas, es lässt sich bei mir nicht reproduzieren. Hast Du alle Befehle ausgeführt?
      apt update && apt upgrade -y && apt install software-properties-common zip unzip screen curl ffmpeg libfile-fcntllock-perl -y
      add-apt-repository ppa:certbot/certbot -y && apt update && apt upgrade -y && apt install letsencrypt -y

      Gab es Fehler dabei (mit Ausnahme des von Dir geposteten)?

      • Andreas says:

        die Befehle habe ich ausgeführt, beim ersten kommt nur dass für das Paket ffmpeg kein Installationskandidat zur Verfügung steht.

  27. Robin says:

    Can’t see that 14 is released yet at Nextcloud page – latest stable release is 13.0.6 or do I miss something?

  28. Felix says:

    Hi, Mr. Rieger.

    Is there any workaround for an ISP blocking 443 port? Actually, can listen on 80 port. Asked DDNS provider (No-IP) if there’s any possibility of forwarding traffic from port 443 to 80, support ticket still open.

    Thanks in advance for all the great work. If ever on Chile, def could invite you a beer. 🙂

    • Wow…thanky you … unfortunately it depends on your ISP and forward 443 to 80 is not recommended.

      • Felix says:

        After some struggling, able to open 443. Works like a charm!

        However, need to point nc_data to a mirrored ZFS dataset, rather than the SSD where OS is running. Can nc_data path be changed during install, or should rather be using another approach?
        According to NC documentation, moving nc_data after install is unsupported, and according to users, it can be quite a bumpy road.

        Tried both to install and move /var/www to such dataset via rsync, but could not make it work. BTW: Have you considered, or is possible to select NC data folder during install instructions /script, or, it’s just me missing something here?

        Thank you, again.

  29. Damir says:

    Hello Carsten,

    thank you for the great guide! 🙂

    I followed your guide and installed all successfully at first try and also installed Collabora.

    At first day all running flawlessly, at second day i got the error that Collabora can not load the files from storage
    i tried to access with the Filesync App but got Authentication Header Baerer not found so i try to solve this issues.

    So i checked the /etc/nginx/nginx.conf and located this
    #include /etc/nginx/proxy.conf;
    #include /etc/nginx/ssl.conf;
    #include /etc/nginx/header.conf;
    #include /etc/nginx/optimization.conf;

    In the guide this files were created, but in the nginx.conf are these files disabled is therefor a reason ?

    Best,
    Damir

  30. Hdsee says:

    Hi is this guide work with raspberry pi 3 ?

  31. Jan says:

    …Ah, i answered it by myself. TLS 1.3 is only possible with OpenSSL 1.1.1, which is in “Beta” at the moment.

    Regards, Jan

  32. Jan says:

    Hi Carsten,

    why is SSLlabs and other sites like this only showing that TLS1.2 is working, but not v1.3? My browsers are connecting via 1.2 too.
    Is it not working at the moment or is there an error somewhere in the config? I can’t see any error messages in the logs.

    Best regards
    Jan

  33. Matthias says:

    That’s right. I’ve moved my logfile to /var/log/nextcloud/nextcloud log. The path in the jail is correct and the logfile is written correctly. Should that be a problem?

    • Chung says:

      I had the same problem with you, and after some research, I am able to fix it by add the tag to the failregex lines.

      According to Fail2ban’s wiki page (https://www.fail2ban.org/wiki/index.php/MANUAL_0_8#Filters), the tag has to be present in every line of failregex.

      My Nextcloud filter is now like following:

      ^{“reqId”:”.*”,”remoteAddr”:”.*”,”app”:”core”,”message”:”Login failed: ‘.*’ (Remote IP: ”)”,”level”:2,”time”:”.*”}$
      ^{“reqId”:”.*”,”level”:2,”time”:”.*”,”remoteAddr”:”.*”,”app”:”core”.*”,”message”:”Login failed: ‘.*’ (Remote IP: ”)”.*}$
      ^.*”remoteAddr”:””.*Trusted domain error.*$

  34. Daniel says:

    Great tutorial –> good job!

  35. Matthias Kern says:

    Hi,
    with fail2ban I get the following error message, when trying the regex:

    fail2ban-regex /var/log/nextcloud/ /etc/fail2ban/filter.d/nextcloud.conf

    ERROR: No failure-id group in ‘^{“reqId”:”.*”,”remoteAddr”:”.*”,”app”:”core”,”message”:”Login failed: ‘.*’ (Remote IP: ”)”,”level”:2,”time”:”.*”}$’

    I copied the jail from this website but fail2ban doesn’t seem to like it.
    It’s Ubuntu 18.04, fail2ban 0.10.2.

    Do you also get that error?

    • Please check the path to Nextclouds log. If you followed my guide the path would be /var/nc_data/nextcloud.log. But you pointed to /var/log/nextcloud, Or amend your files to your path/environment properly.

  1. 6. January 2019

    […] doing that I also did a fresh install of Nextcloud and migrated data. For install I followed this guide by riegercloud and after discovered he has a GitHub script to automate the process […]

Leave a Reply

Your email address will not be published. Required fields are marked *