Nextcloud 15 installation guide (Debian/NGINX)


Nextcloud installation guide


Following this guide you will be able to install and configure Nextcloud 15 latest based on Debian 9.5 Stretch, NGINX 1.15.8 , TLSv1.2 or TLSv1.3, PHP 7.3, 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. 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 Debian Stretch 9.x (64Bit).

Last Updates:

February, 14th 2019:
– added 127.0.0.1 to chapter 12: geoip

… the entire update history


Table of content

  1. Install NGINX 1.15.8
  2. Install PHP 7.3
  3. Install MariaDB 10.3
  4. Install Redis-Server
  5. Preparations for Nextcloud
  6. Hardenings (fail2ban and 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)
  11. Analyze your server using logwatch
  12. Add nginx geoip filter to protect your server by origin-ip

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.

su -
cd /usr/local/src
apt install apt-transport-https git wget gnupg2 dirmngr lsb-release ssl-cert ca-certificates -y
mv /etc/apt/sources.list /etc/apt/sources.list.bak && touch /etc/apt/sources.list
cat <<EOF >>/etc/apt/sources.list
deb http://deb.debian.org/debian stretch main
deb http://security.debian.org/debian-security stretch/updates main
deb [arch=amd64] http://nginx.org/packages/mainline/debian/ stretch nginx
deb-src [arch=amd64] http://nginx.org/packages/mainline/debian/ stretch nginx
deb [arch=amd64] http://mirror2.hs-esslingen.de/mariadb/repo/10.3/debian stretch main
deb https://packages.sury.org/php/ stretch main
deb http://ftp.debian.org/debian stretch-backports main
EOF
wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
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 0xF1656F24C74CD1D8
apt update && apt upgrade -y
apt install software-properties-common zip unzip screen curl git ffmpeg libfile-fcntllock-perl -y
apt remove nginx nginx-common nginx-full -y --allow-change-held-packages
apt update && 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

Paste the following rows:

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/sessions /usr/local/tmp/apc
chown -R www-data:www-data /var/nc_data /var/www
chown -R www-data:root /usr/local/tmp/sessions /usr/local/tmp/apc

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 -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_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_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/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/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

Install MariaDB

apt update && apt install mariadb-server -y

Verify your database server version:

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

A version like …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]
default-character-set = utf8mb4
port = 3306
socket = /var/run/mysqld/mysqld.sock

[mysqld_safe]
log_error=/var/log/mysql/mysql_error.log
nice = 0
socket = /var/run/mysqld/mysqld.sock

[mysqld]
basedir = /usr
bind-address = 127.0.0.1
binlog_format = ROW
bulk_insert_buffer_size = 16M
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
concurrent_insert = 2
connect_timeout = 5
datadir = /var/lib/mysql
default_storage_engine = InnoDB
expire_logs_days = 10
general_log_file = /var/log/mysql/mysql.log
general_log = 0
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
key_buffer_size = 128M
lc_messages_dir = /usr/share/mysql
lc_messages = en_US
log_bin = /var/log/mysql/mariadb-bin
log_bin_index = /var/log/mysql/mariadb-bin.index
log_error=/var/log/mysql/mysql_error.log
log_slow_verbosity = query_plan
log_warnings = 2
long_query_time = 1
max_allowed_packet = 16M
max_binlog_size = 100M
max_connections = 200
max_heap_table_size = 64M
myisam_recover_options = BACKUP
myisam_sort_buffer_size = 512M
port = 3306
pid-file = /var/run/mysqld/mysqld.pid
query_cache_limit = 2M
query_cache_size = 64M
query_cache_type = 1
query_cache_min_res_unit = 2k
read_buffer_size = 2M
read_rnd_buffer_size = 1M
skip-external-locking
skip-name-resolve
slow_query_log_file = /var/log/mysql/mariadb-slow.log
slow-query-log = 1
socket = /var/run/mysqld/mysqld.sock
sort_buffer_size = 4M
table_open_cache = 400
thread_cache_size = 128
tmp_table_size = 64M
tmpdir = /tmp
transaction_isolation = READ-COMMITTED
user = mysql
wait_timeout = 600

[mysqldump]
max_allowed_packet = 16M
quick
quote-names

[isamchk]
!include /etc/mysql/mariadb.cnf
!includedir /etc/mysql/conf.d/
key_buffer = 16M

Restart and connect to MariaDB

service mysql restart && mysql -uroot -p

Create the database and the user

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; quit;

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.


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

Nextcloud: Create the nextcloud.conf

su -
mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak && 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$request_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$request_uri;
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$request_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$request_uri;
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 "accelerometer 'none'; autoplay 'self'; geolocation 'none'; midi 'none'; notifications 'self'; push 'self'; sync-xhr 'self' https://your.dedyn.io; microphone 'self'; camera 'self'; magnetometer 'none'; gyroscope 'none'; speaker 'self'; vibrate 'self'; fullscreen 'self'; payment 'none'; usb 'none'";

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

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):

apt update
apt install certbot -t stretch-backports -y 
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 /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

su - www-data -s /bin/bash -c '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

su - www-data -s /bin/bash -c 'php /var/www/nextcloud/occ config:system:set trusted_domains 1 --value=your.dedyn.io'
su - www-data -s /bin/bash -c 'php /var/www/nextcloud/occ config:system:set overwrite.cli.url --value=https://your.dedyn.io'
cp /var/www/nextcloud/config/config.php /var/www/nextcloud/config/config.php.bak

Expand your Nextcloud config.php:

sed -i 's/^[ ]*//' /var/www/nextcloud/config/config.php
sed -i '/);/d' /var/www/nextcloud/config/config.php
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.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 Nextcloud .user.ini

sed -i "s/upload_max_filesize=.*/upload_max_filesize=10240M/" /var/www/nextcloud/.user.ini
sed -i "s/post_max_size=.*/post_max_size=10240M/" /var/www/nextcloud/.user.ini
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 Apps

su - www-data -s /bin/bash -c 'php /var/www/nextcloud/occ app:disable survey_client'
su - www-data -s /bin/bash -c 'php /var/www/nextcloud/occ app:disable firstrunwizard'
su - www-data -s /bin/bash -c 'php /var/www/nextcloud/occ app:enable admin_audit'
su - www-data -s /bin/bash -c 'php /var/www/nextcloud/occ app:enable files_pdfviewer'

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

(a)

/usr/sbin/service nginx stop
su - www-data -s /bin/bash -c 'php /var/www/nextcloud/occ db:add-missing-indices'
su - www-data -s /bin/bash -c '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.sock <<EOF
FLUSHALL
quit
EOF
su - www-data -s /bin/bash -c 'php /var/www/nextcloud/occ files:scan --all'
su - www-data -s /bin/bash -c '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 once:

/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 2>&1

Switch Nextcloud to use cron.php

su - www-data -s /bin/bash -c 'php /var/www/nextcloud/occ background:cron'

Restart all services

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

Logon to your brandly new Nextcloud in your browser

https://your.dedyn.io/login

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

apt update && apt install fail2ban -y

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

vi /etc/fail2ban/filter.d/nextcloud.conf
[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.*$

Paste the following rows to the fail2ban jail for Nextcloud:

vi /etc/fail2ban/jail.d/nextcloud.local
[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
ufw allow 80/tcp && ufw allow 443/tcp && ufw allow 22/tcp && 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

(c) … using Nextclouds external storage app

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.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/
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.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.


(c) Nextclouds external storage app

As an enhancement for (a) and (b) you can enable the external storage app and participate of many benefits:

  • files can be created, edited and deleted on both sides: witihin and outside Nextcloud
  • you are enabled to mount external storage services and devices as secondary Nextcloud storage devices
  • users are allowed to mount their own external storage services

In case you want to use Samba, issue the following statement

apt install php-smbclient smbclient -y

and restart PHP

service php7.3-fpm restart


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.


Analyze your server using logwatch

First install logwatch

apt update && apt install logwatch -y

then copy the default configuration files to the logwatch folder:

cp /usr/share/logwatch/default.conf/logfiles/http.conf /etc/logwatch/conf/logfiles/nginx.conf
cp /usr/share/logwatch/default.conf/services/http.conf /etc/logwatch/conf/services/nginx.conf
cp /usr/share/logwatch/scripts/services/http /usr/share/logwatch/scripts/services/nginx
cp /usr/share/logwatch/default.conf/services/http-error.conf /etc/logwatch/conf/services/nginx-error.conf
cp /usr/share/logwatch/scripts/services/http-error /etc/logwatch/scripts/services/nginx-error
cp /etc/logwatch/conf/logfiles/nginx.conf /etc/logwatch/conf/logfiles/nginx.conf.org.bak

Edit the /etc/logwatch/conf/logfiles/nginx.conf to mine

vi /etc/logwatch/conf/logfiles/nginx.conf

Substitute the entire file to:

########################################################
# Define log file group for NGINX
########################################################

# What actual file? Defaults to LogPath if not absolute path....
#LogFile = httpd/*access_log
#LogFile = apache/*access.log.1
#LogFile = apache/*access.log
#LogFile = apache2/*access.log.1
#LogFile = apache2/*access.log
#LogFile = apache2/*access_log
#LogFile = apache-ssl/*access.log.1
#LogFile = apache-ssl/*access.log
LogFile = nginx/*access.log
LogFile = nginx/*error.log
LogFile = nginx/*access.log.1
LogFile = nginx/*error.log.1

# If the archives are searched, here is one or more line
# (optionally containing wildcards) that tell where they are...
#If you use a "-" in naming add that as well -mgt
#Archive = archiv/httpd/*access_log.*
#Archive = httpd/*access_log.*
#Archive = apache/*access.log.*.gz
#Archive = apache2/*access.log.*.gz
#Archive = apache2/*access_log.*.gz
#Archive = apache-ssl/*access.log.*.gz
#Archive = archiv/httpd/*access_log-*
#Archive = httpd/*access_log-*
#Archive = apache/*access.log-*.gz
#Archive = apache2/*access.log-*.gz
#Archive = apache2/*access_log-*.gz
#Archive = apache-ssl/*access.log-*.gz
Archive = nginx/*access.log.*.gz
Archive = nginx/*error.log.*.gz

# Expand the repeats (actually just removes them now)
*ExpandRepeats

# Keep only the lines in the proper date range...
*ApplyhttpDate

# vi: shiftwidth=3 tabstop=3 et

Save and quit (:wq!) this file and edit /etc/logwatch/conf/services/nginx.conf:

cp /etc/logwatch/conf/services/nginx.conf /etc/logwatch/conf/services/nginx.conf.org.bak
vi /etc/logwatch/conf/services/nginx.conf

Change the name from http to NGINX or substitute the entire file to mine:

###########################################################################
# Configuration file for NGINX filter
###########################################################################

Title = "NGINX"

# Which logfile group...
LogFile = NGINX

# Define the log file format
#
# This is now the same as the LogFormat parameter in the configuration file
# for httpd. Multiple instances of declared LogFormats in the httpd
# configuration file can be declared here by concatenating them with the
# '|' character. The default, shown below, includes the Combined Log Format,
# the Common Log Format, and the default SSL log format.
#$LogFormat = "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"|%h %l %u %t \"%r\" %>s %b|%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

# The following is supported for backwards compatibility, but deprecated:
# Define the log file format
#
# the only currently supported fields are:
# client_ip
# request
# http_rc
# bytes_transfered
# agent
#
#$HTTP_FIELDS = "client_ip ident userid timestamp request http_rc bytes_transfered referrer agent"
#$HTTP_FORMAT = "space space space brace quote space space quote quote"
# Define the field formats
#
# the only currently supported formats are:
# space = space delimited field
# quote = quoted ("..") space delimited field
# brace = braced ([..]) space delimited field

# Flag to ignore 4xx and 5xx error messages as possible hack attempts
#
# Set flag to 1 to enable ignore
# or set to 0 to disable
$HTTP_IGNORE_ERROR_HACKS = 0

# Ignore requests
# Note - will not do ANY processing, counts, etc... just skip it and go to
# the next entry in the log file.
# Note - The match will be case insensitive; e.g. /model/ == /MoDel/
# Examples:
# 1. Ignore all URLs starting with /model/ and ending with 1 to 10 digits
# $HTTP_IGNORE_URLS = ^/model/\d{1,10}$
#
# 2. Ignore all URLs starting with /model/ and ending with 1 to 10 digits and
# all URLS starting with /photographer and ending with 1 to 10 digits
# $HTTP_IGNORE_URLS = ^/model/\d{1,10}$|^/photographer/\d{1,10}$
# or simply:
# $HTTP_IGNORE_URLS = ^/(model|photographer)/\d{1,10}$

# To ignore a range of IP addresses completely from the log analysis,
# set $HTTP_IGNORE_IPS. For example, to ignore all local IP addresses:
#
# $HTTP_IGNORE_IPS = ^10\.|^172\.(1[6-9]|2[0-9]|3[01])\.|^192\.168\.|^127\.
#

# For more sophisticated ignore rules, you can define HTTP_IGNORE_EVAL
# to an arbitrary chunk of code.
# The default is not to filter anything:
$HTTP_IGNORE_EVAL = 0
# Example:
# $HTTP_IGNORE_EVAL = "($field{http_rc} == 401) && ($field{client_ip}=~/^192\.168\./) && ($field{url}=~m%^/protected1/%)"
# See the "scripts/services/http" script for other variables that can be tested.

# The variable $HTTP_USER_DISPLAY defines which user accesses are displayed.
# The default is not to display user accesses:
$HTTP_USER_DISPLAY = 0
# To display access failures:
# $HTTP_USER_DISPLAY = "$field{http_rc} >= 400"
# To display all user accesses except "Unauthorized":
# $HTTP_USER_DISPLAY = "$field{http_rc} != 401"

# To raise the needed level of detail for one or more specific
# error codes to display a summary instead of listing each
# occurrence, set a variable like the following ones:
# Raise 403 codes to detail level High
#$http_rc_detail_rep_403 = 10
# Always show only summary for 404 codes
#$http_rc_detail_rep_404 = 20

# vi: shiftwidth=3 tabstop=3 et

Save and quit the file (:wq!) and disable the default apache-configuration files:

cd /usr/share/logwatch/default.conf/services
mv http-error.conf http-error.conf.bak && mv http.conf http.conf.bak

At least we create a cronjob to send the result from logwatch automatically:

crontab -e

Paste the following row:

@daily /usr/sbin/logwatch --output mail --mailto your@mail.com --format html --detail high --range yesterday > /dev/null 2>&1

Save and quit crontab and check if logwatch is configured properly:

/usr/sbin/logwatch --output mail --mailto your@mail.com --format html --detail high --range yesterday

You should receive an email from logwatch that looks like this:

From now you will receive daily mails containing your system summary.

12. Add nginx geoip filter to protect your server by origin-ip

Add the required software modules to your NGINX

apt install nginx-module-geoip geoip-database libgeoip1 -y

and change your nginx.conf to mine:

user www-data;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
### START GEOIP ###
load_module modules/ngx_http_geoip_module.so;
load_module modules/ngx_stream_geoip_module.so;
### END GEOIP ###
events {
worker_connections 1024;
multi_accept on;
use epoll;
}
http {
### START GEOIP ###
geoip_country /usr/share/GeoIP/GeoIP.dat;
### END GEOIP ###
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;
}

Instruct nginx to block requests except e.g. DE|AT and your localnet in your new config file /etc/nginx/geoipblock

vi /etc/nginx/geoipblock
set $geoipblock 0;
if ($geoip_country_code !~ (DE|AT)) { set $geoipblock 1; }
if ($localnet = 1){ set $geoipblock 0; }
if ($geoipblock = 1){ return 444; }

and in your /etc/nginx/conf.d/nextcloud.conf:

### START GEOIP ###
geo $localnet {
default 0;
192.168.2.0/24 1; #adjust to your private lan
127.0.0.1 1;
}
### END GEOIP ###
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;
### START GEOIP ###
include /etc/nginx/geoipblock;
### END GEOIP ###
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$request_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$request_uri;
access_log off;
expires 360d;
}
}

Restart your webserver

service nginx restart

and the geoip module is already in use. You find all country codes here. NGINX will return a 444 HTTP error code for a blocked country but feel free to set other HTTP status codes e.g. 404 (not found) or 403 (access denied) as well.


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.

163 Responses

  1. Arne says:

    Hi Carsten,
    ich habe debian und Nextcloud nach deiner Anleitung frisch installiert, jedoch wenn ich zu dem Punkt komme “Logon to your brandly new Nextcloud in your browser” erscheint mir nur eine weiße Seite auf der kurz das Wort “Ansehen” erscheint und dann ganz weiß bleibt. Ich finde den Fehler leider nicht :/. Hast du eine Idee?

    • Laufen nginx, php , redis und mysql?

    • Arne says:

      I just reinstalled nextcloud. Now everything is fine. I’m just thinking about installing netdata or not because it maybe needs too much resources? Also the second level authenticator, is there another option than using google? Thanks!

      • Arne says:

        Nur als Info, vielleicht haben den Fehler auch andere:
        Ich musste noch die Datenbank convertieren in 64 Bit mit dem Befehl “sudo -u www-data php occ db:convert-filecache-bigint” . Vorher den Pfad mit cd /var/www/nextcloud wechseln und auch vorher noch nginx stoppen und Nextcloud in Maintance Zustand versetzen. Nach dem Neustart ist jetzt alles perfekt. 🙂
        Wichtig ist dabei zu beachten das bei dem vorgeschlagenen Befehl von der Nextcloud Seite der Pfad anders ist und das php im Befehl fehlt.

  2. Ed says:

    Hi Carsten,

    Thanks for the guide. Your guides are the gold standard! 🙂

    For netdata, I suggest adding a hardening to disallow access from the internet or at least mention it as an option. I do not want this accessible on the internet. The intranet lan is just fine.

    satisfy all;
    deny 192.168.1.2;
    allow 192.168.1.1/24;
    allow 127.0.0.1;

    Now, when I access https://mydomain/netdata from the internet I immediately get a Forbidden page.

  3. Stephan says:

    Hallo Carsten,
    zuerst mal: Super Anleitung!
    Kurze Verständnisfrage: Warum installierst Du postfix und nicht nur sowas wie ssmtp? Wäre das nicht ausreichend?
    Grüße
    Stephan

  4. Felix says:

    Hi Carsten,
    vielen Dank erst einmal für dieses klasse Tutorial.
    Ich bekomme immer den Fehler nginx: [emerg] bind() to 172.0.0.1:81 failed (99: Cannot assign requested address)
    Kannst du mir hier weiter helfen?
    LG Felix

  5. ALex says:

    Können Sie mir bitte sagen, wie ich den Datumsordner in den Abschnitt / home / user / nc_data verschieben kann?

    • (1) Stoppe PHP und den Webserver: service nginx stop && service php7.2-fpm stop
      (2) Ändere das data-directory der Nextcloud: vi /var/www/nextcloud/config/config.php
      (2.1) 'logfile' => '/var/user/nc_data/nextcloud.log',
      (2.2) 'datadirectory' => '/var/user/nc_data',
      (3) Verschieben des Ordners: mv /var/nc_data /home/user/
      (4) Setze die Berechtigungen: chown -R www-data /home/user/nc_data
      (5) Indiziere neu:
      (5.1) redis-cli -s /var/run/redis/redis.sockFLUSHALLquit
      (5.2) su - www-data -s /bin/bash -c 'php /var/www/nextcloud/occ files:scan --all -v' && su - www-data -s /bin/bash -c 'php /var/www/nextcloud/occ files:scan-app-data'
      (6) Starte die Dienste wieder: service php7.2-fpm restart && service nginx restart

  6. Markus says:

    Hallo Carsten,

    ich hoffe, ich bekomme noch eine Antwort von Dir.
    Ich bin seit Stunden am suchen und ich glaube, ich habe eine Ursache für das Problem gefunden.
    Ich habe bei Server4you einen Server gebucht und habe dort die Adresse eingegeben, unter der der Server aus dem Netz erreichbar sein sollte:
    Alle Fehlermeldungen, die ich bekomme beziehen sich auf die Zeilen, in denen “euve26XXXX.serverprofi24.de” steht. Meinem Verständnis nach muss ich Diese Adresse für alle “YOUR.DEDYN.IO” einsetzen, oder?

    Frage: Was muss ich nun tun und wie kann ich das alles wieder gerade ziehen?
    Ich würde mich sehr über eine Antwort auf email-anonymisiert freuen.

    Gruß Markus.

    • Auf der Webseite sind alle Stellen rot markiert: ssl.conf, nextcloud.conf, renewal.sh fallen mir adhoc ein.

      Ich unterstütze Dich gern, aber auf Stundenbasis: €57,60 auf Rechnung – wenn das i.O. ist, dann kontaktiere mich bitte per Mail. Dann benötige ich auch noch die SSH-Zugangsdaten und einen Benutzer+PWD mit sudo Berechtigungen. Diese Infos kannst Du bitte hier sicher hochladen. Danke und Grüße, Carsten

  7. Markus says:

    Hallo Carsten,

    sorry wenn ich hier noch eimal Poste – aber ich habe eine Fehlermeldung, bei der ich offensichtlich nicht weiter komme:
    root@xxxxx:~# service nginx restart
    Job for nginx.service failed because the control process exited with error code.
    See “systemctl status nginx.service” and “journalctl -xe” for details.

    … ich kann die Logs nicht finden bzw. nichts mit den Logs anfangen.
    Ich hoffe Du kannst mir helfen? Das währe total super!
    Gruß Markus

  8. Markus says:

    Hallo Carsten,

    darf ich Dir dieses Log einmal senden mit der Frage, ob die Errors ignoriert werden können?

    root@xxxxxxxxx:~# apt update && apt install redis-server php-redis -y
    Hit:1 http://security.debian.org stretch/updates InRelease
    Hit:2 http://mirror2.hs-esslingen.de/mariadb/repo/10.3/debian stretch InRelease
    Hit:3 https://packages.sury.org/php stretch InRelease
    Ign:4 http://cdn-fastly.deb.debian.org/debian stretch InRelease
    Hit:5 http://nginx.org/packages/mainline/debian stretch InRelease
    Hit:6 http://cdn-fastly.deb.debian.org/debian stretch-updates InRelease
    Hit:7 http://cdn-fastly.deb.debian.org/debian stretch Release
    Reading package lists… Done
    Building dependency tree
    Reading state information… Done
    3 packages can be upgraded. Run ‘apt list –upgradable’ to see them.
    Reading package lists… Done
    Building dependency tree
    Reading state information… Done
    The following packages were automatically installed and are no longer required:
    libbind9-90 libdns100 libisc95 libisccc90 libisccfg90 liblwres90
    Use ‘apt autoremove’ to remove them.
    The following additional packages will be installed:
    php-igbinary redis-tools
    Suggested packages:
    ruby-redis
    The following NEW packages will be installed:
    php-igbinary php-redis redis-server redis-tools
    0 upgraded, 4 newly installed, 0 to remove and 3 not upgraded.
    Need to get 1329 kB of archives.
    After this operation, 5728 kB of additional disk space will be used.
    Get:1 http://cdn-fastly.deb.debian.org/debian stretch/main amd64 redis-tools amd64 3:3.2.6-3+deb9u2 [463 kB]
    Get:2 http://cdn-fastly.deb.debian.org/debian stretch/main amd64 redis-server amd64 3:3.2.6-3+deb9u2 [413 kB]
    Get:3 https://packages.sury.org/php stretch/main amd64 php-igbinary amd64 2.0.7-2+0~20181024064424.5+stretch~1.gbpb66628 [102 kB]
    Get:4 https://packages.sury.org/php stretch/main amd64 php-redis amd64 4.2.0~rc2-1+0~20181103182700.8+stretch~1.gbp7a20b8 [352 kB]
    Fetched 1329 kB in 0s (3130 kB/s)
    perl: warning: Setting locale failed.
    perl: warning: Please check that your locale settings:
    LANGUAGE = (unset),
    LC_ALL = (unset),
    LANG = “de_DE.UTF-8”
    are supported and installed on your system.
    perl: warning: Falling back to the standard locale (“C”).
    locale: Cannot set LC_CTYPE to default locale: No such file or directory
    locale: Cannot set LC_MESSAGES to default locale: No such file or directory
    locale: Cannot set LC_ALL to default locale: No such file or directory
    debconf: unable to initialize frontend: Dialog
    debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 76, line 4.)
    debconf: falling back to frontend: Readline
    Selecting previously unselected package php-igbinary.
    (Reading database … 31296 files and directories currently installed.)
    Preparing to unpack …/php-igbinary_2.0.7-2+0~20181024064424.5+stretch~1.gbpb66628_amd64.deb …
    Unpacking php-igbinary (2.0.7-2+0~20181024064424.5+stretch~1.gbpb66628) …
    Selecting previously unselected package php-redis.
    Preparing to unpack …/php-redis_4.2.0~rc2-1+0~20181103182700.8+stretch~1.gbp7a20b8_amd64.deb …
    Unpacking php-redis (4.2.0~rc2-1+0~20181103182700.8+stretch~1.gbp7a20b8) …
    Selecting previously unselected package redis-tools.
    Preparing to unpack …/redis-tools_3%3a3.2.6-3+deb9u2_amd64.deb …
    Unpacking redis-tools (3:3.2.6-3+deb9u2) …
    Selecting previously unselected package redis-server.
    Preparing to unpack …/redis-server_3%3a3.2.6-3+deb9u2_amd64.deb …
    Unpacking redis-server (3:3.2.6-3+deb9u2) …
    Setting up redis-tools (3:3.2.6-3+deb9u2) …
    Setting up php-igbinary (2.0.7-2+0~20181024064424.5+stretch~1.gbpb66628) …
    Setting up php-redis (4.2.0~rc2-1+0~20181103182700.8+stretch~1.gbp7a20b8) …
    Processing triggers for systemd (232-25+deb9u6) …
    Processing triggers for man-db (2.7.6.1-2) …
    Setting up redis-server (3:3.2.6-3+deb9u2) …
    Created symlink /etc/systemd/system/redis.service → /lib/systemd/system/redis-server.service.
    Created symlink /etc/systemd/system/multi-user.target.wants/redis-server.service → /lib/systemd/system/redis-server.service.
    Job for redis-server.service failed because the control process exited with error code.
    See “systemctl status redis-server.service” and “journalctl -xe” for details.
    invoke-rc.d: initscript redis-server, action “start” failed.
    ● redis-server.service – Advanced key-value store
    Loaded: loaded (/lib/systemd/system/redis-server.service; enabled; vendor preset: enabled)
    Active: activating (auto-restart) (Result: exit-code) since Thu 2018-12-06 10:27:07 CET; 9ms ago
    Docs: http://redis.io/documentation,
    man:redis-server(1)
    Process: 4995 ExecStart=/usr/bin/redis-server /etc/redis/redis.conf (code=exited, status=226/NAMESPACE)
    Process: 4992 ExecStartPre=/bin/run-parts –verbose /etc/redis/redis-server.pre-up.d (code=exited, status=226/NAMESPACE)
    dpkg: error processing package redis-server (–configure):
    subprocess installed post-installation script returned error exit status 1
    Processing triggers for systemd (232-25+deb9u6) …
    Errors were encountered while processing:
    redis-server
    E: Sub-process /usr/bin/dpkg returned an error code (1)

  9. Markus says:

    Hallo Carsten,

    erst einmal vielen Dank für die tolle Anleitung. Ich bin gerade dabei Deine Anleitung “nach zu installieren” und bin ebenfalls an dem Punkt mit php7.2 gestrandet.
    Nachdem ich folgenden befehle ausgeführt hatte, konnte ich php installieren.
    Ich hoffe dass hilft in der Zwischenzeit!?!

    wget -q -O- https://packages.sury.org/php/apt.gpg | apt-key add –
    echo “deb https://packages.sury.org/php/ stretch main” | tee /etc/apt/sources.list.d/php.list
    apt-get update

  10. Andree Heinzig says:

    Hallo Carsten,
    hab den Fehler beheben können. In der Datei

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

    [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

    muss einfach in der ersten zeile anstatt ‘backend = auto’ ‘backend = systemd’ stehen, dann kommt im Bootvorgang keien Fehlermeldung und nach dem Starten ist fail2ban aktiv und funktioniert.

    LG Andree

  11. Andree Heinzig says:

    Hallo Carsten,
    die Installation lief super. Eine ganz feine Anleitung.Ich habe den Nextcloud Data Ordner über fstab auf meinem NAS eingebunden. Es wird beim booten gewartet bis das Netzwerk eingebunden ist. Beim Booten habe ich mehrere Male die Meldung ‘Failed to start Fail2Ban.service’. Zwischendurch wird F2b gestartet und wieder beendet, zum Schluss des Bootvorganges jedoch nicht mehr gestartet. Ich habe alles in den aktuellen Versionen installiert (24.11.18, Debian Stretch). Kennst Du das Problem, würde es helfen mit rc.local und einer Verzögerung für den Start von Fail2ban zu arbeiten?

    Vielen Dank für deine Antwort, liebe Grüße Andree

    Das steht unter ‘systemctl status fail2ban.service’:

    ● fail2ban.service – Fail2Ban Service
    Loaded: loaded (/lib/systemd/system/fail2ban.service; enabled; vendor preset: enabled)
    Active: failed (Result: exit-code) since Fri 2018-11-23 23:32:44 CET; 48min ago
    Docs: man:fail2ban(1)
    Process: 832 ExecStart=/usr/bin/fail2ban-client -x start (code=exited, status=255)

    Nov 23 23:32:44 nuc systemd[1]: fail2ban.service: Unit entered failed state.
    Nov 23 23:32:44 nuc systemd[1]: fail2ban.service: Failed with result ‘exit-code’.
    Nov 23 23:32:44 nuc systemd[1]: fail2ban.service: Service hold-off time over, scheduling restart.
    Nov 23 23:32:44 nuc systemd[1]: Stopped Fail2Ban Service.
    Nov 23 23:32:44 nuc systemd[1]: fail2ban.service: Start request repeated too quickly.
    Nov 23 23:32:44 nuc systemd[1]: Failed to start Fail2Ban Service.
    Nov 23 23:32:44 nuc systemd[1]: fail2ban.service: Unit entered failed state.
    Nov 23 23:32:44 nuc systemd[1]: fail2ban.service: Failed with result ‘exit-code’.

    • Servus. Ja entweder RC nutzen oder du legst das nextcloud.log lokal ab und greifst dort mittels fail2ban drauf zu. Ändere dafür in der config.php den logpath. Ist m. E. nach der bessere Weg. Grüße Carsten

  12. Chris says:

    Hi Carsten,

    Very, very good and detailed tutorial. Many thanks for that. I sent You an e-mail about would be possible to do section in this tutorial with self signed certs for internal use only on lan network?
    Thanks again.

    • Just don’t request certificates from Let’s Encryt and as well don’t issue sed -i '/ssl-cert-snakeoil/d' /etc/nginx/ssl.conf … that would fit your request already 😉

  13. Franz says:

    super tutorial ! Danke Carsten.
    Eine Frage: Wenn ich z.B in der NC App mir die “Medien” anschaue, geht von der VM (4 vcpus, 6GB RAM) die Memory Auslastung auf 100%. php-fpm frisst dann den memory. Ist das normal?
    Ich habe schon die “pm.max_children” runter gedreht – das reicht wohl nicht.
    Hast du einen Tipp?

  14. Chris says:

    Hallo Carsten,
    erst einmal vielen Dank für diese Anleitung. Sie hat den Anstoß gegeben, dass ich endlich eine eigene Cloud aufsetze.
    Leider erhalte ich bei dem Installationsprozewss folgende Fehlermeldung und weiß nicht wie ich damit umgehen soll.
    Nachdem ich Nextcloud heruntergeladen habe und mein ssl Certifikat holen möchte kommt:
    “Waiting for verification…
    Cleaning up challenges
    Failed authorization procedure. [meineurl].dedyn.io (http-01): urn:acme:error:connection :: The server could not connect to the client to verify the domain :: Fetching http://[meineurl].dedyn.io/.well-known/acme-challenge/%5BZiffern und Buchstaben-Wirrwar]: Error getting validation data”

    Weißt du wie ich das beheben kann?

    • Ist der Port 80 offen und wurde gem. meines Guides installiert?

      • Chris says:

        Ahhhh Danke 😀 Das hat geholfen!
        Aber darauf wäre ich nie gekommen, ich verstehe leider nicht alles von dem, was sie bereit stellen. Vlt könnte man noch eine Anmerkung zu diesem Schritt schreiben, dass dieser Port geöffnet werden muss.

        • Super, dass es geholfen hat. Ich habe Pre-Requirements anolog des Guides mit Ubuntu ergänzt. Danke und viel Spaß damit…

          • Chirs says:

            Leider stoße ich schon wieder auf meine Grenzen… 🙁
            Beim Punkt “Adjust Nextcloud Apps”
            Wenn ich folgenden Befehl eingebe kommt eine Permission denied Fehlermeldung …
            su – www-data -s /bin/bash -c ‘php /var/www/nextcloud/occ app:disable survey_client’
            Fehlermeldung:
            “An unhandled exception has been thrown:
            RedisException: Permission denied in /var/www/nextcloud/lib/private/RedisFactory.php:84
            Stack trace:
            #0 /var/www/nextcloud/lib/private/RedisFactory.php(84): Redis->connect(‘/var/run/redis/…’, 0, 0)
            #1 /var/www/nextcloud/lib/private/RedisFactory.php(100): OCRedisFactory->create()
            #2 /var/www/nextcloud/lib/private/Memcache/Redis.php(42): OCRedisFactory->getInstance()
            #3 /var/www/nextcloud/lib/private/Memcache/Factory.php(136): OCMemcacheRedis->__construct(‘54127b7f2a01e16…’)
            #4 /var/www/nextcloud/lib/private/Server.php(849): OCMemcacheFactory->createLocking(‘lock’)
            #5 /var/www/nextcloud/3rdparty/pimple/pimple/src/Pimple/Container.php(118): OCServer->OC{closure}(Object(OCServer))
            #6 /var/www/nextcloud/lib/private/AppFramework/Utility/SimpleContainer.php(117): PimpleContainer->offsetGet(‘OCP\Lock\ILocki…’)
            #7 /var/www/nextcloud/lib/private/ServerContainer.php(132): OCAppFrameworkUtilitySimpleContainer->query(‘OCP\Lock\ILocki…’)
            #8 /var/www/nextcloud/lib/private/AppFramework/Utility/SimpleContainer.php(165): OCServerContainer->query(‘OCP\Lock\ILocki…’)
            #9 /var/www/nextcloud/3rdparty/pimple/pimple/src/Pimple/Container.php(114): OCAppFrameworkUtilitySimpleContainer->OCAppFrameworkUtility{closure}(Object(OCServer))
            #10 /var/www/nextcloud/lib/private/AppFramework/Utility/SimpleContainer.php(117): PimpleContainer->offsetGet(‘LockingProvider’)
            #11 /var/www/nextcloud/lib/private/ServerContainer.php(132): OCAppFrameworkUtilitySimpleContainer->query(‘LockingProvider’)
            #12 /var/www/nextcloud/lib/private/Server.php(1784): OCServerContainer->query(‘LockingProvider’)
            #13 /var/www/nextcloud/lib/private/Files/View.php(115): OCServer->getLockingProvider()
            #14 /var/www/nextcloud/lib/private/Server.php(214): OCFilesView->__construct()
            #15 /var/www/nextcloud/3rdparty/pimple/pimple/src/Pimple/Container.php(118): OCServer->OC{closure}(Object(OCServer))
            #16 /var/www/nextcloud/lib/private/AppFramework/Utility/SimpleContainer.php(117): PimpleContainer->offsetGet(‘EncryptionManag…’)
            #17 /var/www/nextcloud/lib/private/ServerContainer.php(132): OCAppFrameworkUtilitySimpleContainer->query(‘EncryptionManag…’)
            #18 /var/www/nextcloud/lib/private/Server.php(1257): OCServerContainer->query(‘EncryptionManag…’)
            #19 /var/www/nextcloud/lib/base.php(845): OCServer->getEncryptionManager()
            #20 /var/www/nextcloud/lib/base.php(730): OC::registerEncryptionWrapper()
            #21 /var/www/nextcloud/lib/base.php(1068): OC::init()
            #22 /var/www/nextcloud/console.php(46): require_once(‘/var/www/nextcl…’)
            #23 /var/www/nextcloud/occ(11): require_once(‘/var/www/nextcl…’)
            #24 {main}#”

            Kannst du mir nochmal weiterhelfen?
            Der Server an sich läuft übrigens schon, aber noch mit der Meldung: “Interner Serverfehler. Der Server konnte die Anfrage nicht fertig stellen.”

            Beste Grüße
            Chris

          • Chris says:

            Es funktioniert! Tatsächlich hat mit Redis etwas nicht gestimmt.
            Ich möchte mich gerne für deine Hilfe bedanken. Kann man dir per Paypal oder so ein paar Kaffee ausgeben?

            Beste Grüße
            Chris

  15. Neil F says:

    This tutorial KICKS ASS!!! Managed all the way through on 10/11/18, completed everything start to finish, and it works SPECTACULARLY!!! Great work Carsten!

    A couple of questions. First, I have a small, semi-production site on 13.0.1 and curious to know the best way to migrate it to this instance, installed from the above tutorial. Secondly, would like to any guidance on changes to make in order to host multiple instances, domian.nc1.com, domain.nc2.com.

    Again, great work!

  16. lee says:

    Hi Carsten,

    I have enable External storages & able to access the shared data (folders/files) in ext4 file-system.

    When I run /root/optimize.sh, it display:-
    mkdir failed on directory /var/run/samba/msg.lock: Permission denied

    May I know how to resolve this error ?

    Thanks

    • Lee, the script does not create a directory. So the error is caused somewhere else! As the error message explains: /var/run/samba – did you verify your smb and external storage already?

  17. yu says:

    my local isp prevents all inbound connections through port 80, thus letsencrypt is completely dysfunctional. other than skipping that step, is there anything you suggest i do?

  18. lee says:

    Hi Carsten,

    Finally I managed to installed Nextcloud successfully base on your tutorial. Thanks !

    Additionally, I also tried to install ONLYOffice base on the link:-
    https://helpcenter.onlyoffice.com/server/linux/document/linux-installation.aspx

    But I encounter problem when installing apt-get install nginx-extras.
    The following packages have unmet dependencies:
    nginx : Conflicts: nginx-common but 1.10.3-1+deb9u1 is to be installed

    I Google search for answer but unable to find any result related to the situation I’m facing.

    Appreciated if you could help up and if possible to have another tutorial to cover ONLYOffice app installation

    Thanks.

    • Caused by OnlyOffice your NGINX is corrupted. OnlyOffice leads to NGINX 1.10.3-1 vs. Nextcloud NGINX 1.15.4. I would suggest to remove the OO one and ammend the current NGINX 1.15.4 with regards to OO.

  19. Tobias says:

    Hey, ich glaube da ist ein Problem drin. Wenn ich es 1:1 so durchführe, kann ich nicht in Ordner gehen:

    PROPFIND https://HIERMEINEURL/remote.php/dav/files/MEINUSER/remote.php/dav/files/MEINUSER/DERORDNERNAME 500

    client.js?v=7f473d3f-2:431 Uncaught (in promise) TypeError: Cannot read property ‘getElementsByTagNameNS’ of null
    at Client._getSabreException (client.js?v=7f473d3f-2:431)
    at client.js?v=7f473d3f-2:495

    Das liegt offenbar an der NGINX Konfiguration, mit der originalen geht es nach paar Anpassungen. Irgendeine Idee?

    • Stimmen die Berechtigungen an den Ordnern? Die NGINX-konfig hat sich vielfach bewährt, daran liegt es ziemlich sicher nicht. Sehe es mir Montag gern direkt per SSH an, Interesse?

      • Tobias says:

        Gerne kann man sich das einmal anschauen.

        Am Handy via APP geht es, via Browser (Chrome / Opera) nicht, daher gehe ich nicht direkt von Rechten aus.

  20. teigaff says:

    I’ve a Sheevaplug (ARM architecture) and followed this guide. Unfortunately, it won’t work for armel processors.
    OpenSSL 1.1.0h was no problem. The repository http://nginx.org/packages/mainline/debian/ has no packages for armel. Also https://packages.sury.org/php/ has no installation candidate.
    Is there a way to install it anyway on the secure way?

  21. xAnder79 says:

    Hi guys! Help to connect a nextcloud as a network drive in windows that would work as a shared folder, do everything according to the instructions, do not pass authorization, alternative clients work well, but I need just like a network drive

  22. alex says:

    Danke für die Anleitung
    ich hab allerdings das problem, dass ich außerhalb meines Netzwerks keine Verbindung zur Nextcloud bekomm, ich seh zwar die Verbindung mit netstat, bekomme aber keine Antwort

  23. joassamapple says:

    Ich habe eine Frage, manchmal finde ich im Log folgende Meldung:

    Aug 31 05:09:01 somebody sessionclean[28661]: find: ‘/usr/local/tmp/sessions/sess_1fmg49osmg3db03t1mln5gdnr2’ kann nicht gelöscht werden.: Das Dateisystem ist nur lesbar
    Aug 31 05:09:01 somebody sessionclean[28661]: find: ‘/usr/local/tmp/sessions/sess_48v8bfjaj8pcnk5q5mlgar9va1’ kann nicht gelöscht werden.: Das Dateisystem ist nur lesbar
    Aug 31 05:09:01 somebody sessionclean[28661]: find: ‘/usr/local/tmp/sessions/sess_09l9dr7frh0tm8tboqabgc4mve’ kann nicht gelöscht werden.: Das Dateisystem ist nur lesbar
    Aug 31 05:09:01 somebody sessionclean[28661]: find: ‘/usr/local/tmp/sessions/sess_h4o86a19ejig2f7tf3n9up8qce’ kann nicht gelöscht werden.: Das Dateisystem ist nur lesbar
    Aug 31 05:09:01 somebody systemd[1]: phpsessionclean.service: Main process exited, code=exited, status=1/FAILURE
    Aug 31 05:09:01 somebody systemd[1]: Failed to start Clean php session files.
    Aug 31 05:09:01 somebody systemd[1]: phpsessionclean.service: Unit entered failed state.
    Aug 31 05:09:01 somebody systemd[1]: phpsessionclean.service: Failed with result ‘exit-code’.

    Woran könnte das liegen?
    Gruß joassamapple

    • Ist der cron.d deaktiviert und der manuell erzeugte Cronjob aktiv? Wie sehen denn die Berechtigungen aus? Was passiert, wenn als ROOT /usr/lib/php/sessionclean ausgeführt wird?

      • joassamapple says:

        /etc/cron.d/php ist auskommentiert, und der erzeugte cronjob ist angelegt ( als root mit crontab -e editiert, 09,39 * * * * /usr/lib/php/sessionclean 2>&1).
        Wenn ich als root /usr/lib/php/sessionclean ausführe, kommt keine Fehlermeldung. Es ist auch schwierig zu reproduzieren, da der Fehler nur manchmal auftritt.
        Die Berechtigung im Verzeichnis /usr/local/tmp/sessions/ ist auf www-data:root gesetzt. So wie Sie in der Tutorial beschrieben haben.

        Hier ist nochmal ein Ausschnitt aus dem Log:

        Sep 5 09:09:02 somebody systemd[1]: Starting Clean php session files…
        Sep 5 09:09:02 somebody systemd[1]: Started Clean php session files.
        Sep 5 09:15:01 somebody CRON[12208]: (www-data) CMD (php -f /var/www/nextcloud/cron.php > /dev/null 2>&1)
        Sep 5 09:17:01 somebody CRON[12219]: (root) CMD ( cd / && run-parts –report /etc/cron.hourly)
        Sep 5 09:30:01 somebody CRON[12354]: (www-data) CMD (php -f /var/www/nextcloud/cron.php > /dev/null 2>&1)
        Sep 5 09:39:01 somebody CRON[12467]: (root) CMD (/usr/lib/php/sessionclean 2>&1)
        Sep 5 09:39:02 somebody systemd[1]: Starting Clean php session files…
        Sep 5 09:39:03 somebody sessionclean[12530]: find: ‘/usr/local/tmp/sessions/sess_suf8nqmrn1pqssvm2i01g2q8bj’ kann nicht gelöscht werden.: $
        Sep 5 09:39:03 somebody sessionclean[12530]: find: ‘/usr/local/tmp/sessions/sess_0ortams70r5lv9c9vngklg3h3t’ kann nicht gelöscht werden.: $
        Sep 5 09:39:03 somebody systemd[1]: phpsessionclean.service: Main process exited, code=exited, status=1/FAILURE
        Sep 5 09:39:03 somebody systemd[1]: Failed to start Clean php session files.
        Sep 5 09:39:03 somebody systemd[1]: phpsessionclean.service: Unit entered failed state.
        Sep 5 09:39:03 somebody systemd[1]: phpsessionclean.service: Failed with result ‘exit-code’.
        Sep 5 09:45:01 somebody CRON[12644]: (www-data) CMD (php -f /var/www/nextcloud/cron.php > /dev/null 2>&1)
        Sep 5 10:00:01 somebody CRON[12757]: (www-data) CMD (php -f /var/www/nextcloud/cron.php > /dev/null 2>&1)
        Sep 5 10:09:01 somebody CRON[13839]: (root) CMD (/usr/lib/php/sessionclean 2>&1)
        Sep 5 10:09:03 somebody systemd[1]: Starting Clean php session files…
        Sep 5 10:09:03 somebody systemd[1]: Started Clean php session files.

        Gruß joassamapple

  24. Thomas says:

    Vielen Dank erstmal für den sehr kompakten Guide.
    Bei mir aber ist ein komischer Fehler zustande gekommen.
    Während der Installation sowie die darauf folgenden 3 Stunden (Einrichtung von Nextcloud) verlief alles wunderbar und funktionierte.

    Gegen Abend hin startete ich den kompletten Server neu und siehe da Nextcloud geht nicht.
    nginx läuft (port 80, willkommens page läuft), redis,mysql,php alles läuft.
    Die logs zeigen keinen fehler, /var/log/nginx/…

    Deine variante die nginx sites zu konfigurieren, hab ich so noch nie gesehen weswegen ich dich fragen wollte ob es vielleicht daran liegen könnte das die configs irgendwie falsch abgerufen werden?
    Freue mich auf jeden Tipp. Danke

    • Die Beschreibung deutet auf ein Problem mit der default.conf hin, denn sonst gäbe es keine Willkommens-Seite mehr 😉
      Bitte folgendes ausführen:
      mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak && touch /etc/nginx/conf.d/default.conf && service nginx restart
      Geht es dann?

  25. Lee says:

    Hi Carsten,

    Appreciated your effort on this detail tutorial.

    I faced some challenges while doing the Redis & hardening portion.

    Redis client cannot connect to server:-
    # /root/optimize.sh
    Could not connect to Redis at /var/run/redis/redis-server.sock: No such file or directory

    # redis-cli
    Could not connect to Redis at 127.0.0.1:6379: Connection refused
    Could not connect to Redis at 127.0.0.1:6379: Connection refused
    not connected>

    # service redis-server status
    Active: active (running)

    Hardening script error
    # /root/ufw-spamhaus.sh
    Start time: Sun Aug 26 13:35:02 UTC 2018

    Download daily DROP file:

    Extract DROP IP addresses and add to UFW:
    ERROR: Invalid position ‘1’
    ERROR: Invalid position ‘1’
    …..

    Any idea ?

  26. Danke für die sehr gute Anleitung.
    Habe mit der Hilfe meine (gerade zerlegte..) uralte Installation (Owncloud 9, 10, NC 10, 11, 12, 13) komplett neu gemacht.
    Und noch einiges an Linux know-how gelernt.

    Vielen Dank dafür!

  27. SuperK2 says:

    Ok, Let’s try this guide, Thanks in advance!

    I will report my experiences here.

    Regards

  28. Philipp says:

    Hi Carsten,

    Vielen Dank für diesen tollen guide! 🙂
    Es funktioniert soweit alles. Nur fail2ban macht Probleme bei der nextcloud config. Ich bekomme diesen Fehler:

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

    Hast du eine Ahnung woran das liegen könnte? Meine fail2ban version ist 0.9.6.

    Danke im Voraus.

    LG Philipp

    • jhot says:

      Das selbe passiert hier auch – bin noch auf der Suche warum, melde mich falls ich was finde.

    • Karsten says:

      Hi,

      hatte auch das Problem. Sollte hier mit behoben sein:

      [Definition]
      failregex = ^{“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.*$
      ignoreregex =

  29. jhot says:

    Hallo zusammen,

    vielen Dank für den großartigen Guide, habe ihn bis auf kleinste Detail befolgt und es funktioniert fantastisch hier auf debian stretch (9.5).
    Allerdings läuft TLS v1.3 hier noch nicht – sowohl beim ssllabs Test wie im Firefox 61.0.1 wird nur TLS v1.2 angezeigt.
    Woran könnte das liegen?

    Freundliche Grüße

    jhot

  30. KArsten says:

    Hallo,

    nachdem ich die letzten updates eingespielt habe, bekomme ich nur noch eine leere Seite angezeigt? kein Login/Passwort mehr. Woran kann das liegen?

    Grüße

    Karsten

  31. Sisim says:

    Hello Carsten,
    Thank you again for this support. Since I installed PHP7.2 FPM as you advised, APCU is not working anymore. I have this in logs:
    > Info cli Memcache OCMemcacheAPCu not available for local cache
    > Info cli Memcache OCMemcacheAPCu not available for distributed cache
    Can APCU work with PHP7.2? I read somewhere that I should run pecl install apcu`
    Thank you!

  32. Joas Samapple says:

    Perfekt, vielen Dank! Läuft alles bestens!
    Nur eine Frage: Ist es überhaupt sinnvoll, von MariaDB 10.1 (Debian-Paket) auf MariaDB 10.3 upzugraden?
    Hat man da mehr Sicherheitsvorteile oder Leistung?
    Gruß joassamapple

  33. Rémy says:

    Hello,

    Is it suposed to work with Debian 9.5 also ?
    Unfortunately I tried to install Nextcloud following this guide on fresh Debian 9.5 (twice) with no error during procedure but when I try to connect in my browser I get a timeout, not responding.

    Am I missing something ?

    Thanks

    • In general yes. Please verify if all services are running, in particular nginx and redis. Ubuntu changed the redis socket from Ubuntu 16 to Ubuntu 18 – please have a look and adjust the config.php if necessary.

      • DEBIAN 9.5 – Updates to NGINX necessary!
        Please remove the old entries for NGINX in the /etc/apt/sourc.list.
        Then issue:
        apt remove nginx nginx-common nginx-full -y --allow-change-held-packages
        sed -i '$adeb http://nginx.org/packages/mainline/debian/ stretch nginx' /etc/apt/sources.list
        sed -i '$adeb-src http://nginx.org/packages/mainline/debian/ stretch nginx' /etc/apt/sources.list
        wget http://nginx.org/keys/nginx_signing.key && apt-key add nginx_signing.key
        apt update && apt install nginx -y

        Work in Progress…I will update the blog asap!

      • Rémy says:

        Thanks for your fast support !

        I performed a fresh install with your updated guide. My problem is still there but I’m close to the solution :

        – when I try to acces my server from the browser with cloud.domain.com or with my IP adress –> time out
        – when I try to acces my server from the browser with the local IP adress 192.168.0.10 —> it works (ssl not secure adverts)

        I suppose my problem comes from the nginx server block configuration (I simply edited the red lines with cloud.domain.com but …. )

        I will work on it asap.

  34. Karsten says:

    Hallo,

    zu aller erst einmal vielen Dank für dieses tolle howto/tutorial. Realy awesome!

    Leider habe ich Problem mit dem Cert renewal und finde den Fehler leider nicht und die Zeit rennt… Klar geht es auch per Hand. Aber würde gerne das Script benutzen für das renewal.

    Ich habe auch schon versucht einige Fehler zu finden. Aber bis dato ohne Erfolg.

    1. /var/www/letsencrypt/.well-known
    www gehört www-data, letsencrypt -> www-data, .well-known allerdings root? ist das absicht?
    Wird der Ordner acme-challenge sonst automatisch erstellt? Habe den auch per Hand erstellt, weil da war sonst kein Ordner mit dem Namen

    2. ich habe es auch schon mit “ssl off;” in der letsencrypt.conf sowie nextcloud.conf versucht. Auch leider ohne Erfolg.

    Als Fehler bekomme ich diesen Angezeigt:

    ##############
    ./renewal.sh
    Saving debug log to /var/log/letsencrypt/letsencrypt.log

    ——————————————————————————-
    Processing /etc/letsencrypt/renewal/domain.domain.com.conf
    ——————————————————————————-
    Cert is due for renewal, auto-renewing…
    Renewing an existing certificate
    Performing the following challenges:
    http-01 challenge for domain.domain.com
    Waiting for verification…
    Cleaning up challenges
    Attempting to renew cert from /etc/letsencrypt/renewal/domain.domain.com.conf produced an unexpected error: Failed authorization procedure. domain.domain.com (http-01): urn:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://domain.domain.com/.well-known/acme-challenge/CHANLANGEREMOVED_KINDLY_REMOVED: ”
    400 The plain HTTP request was sent to HTTPS port

    400 B”. Skipping.

    All renewal attempts failed. The following certs could not be renewed:
    /etc/letsencrypt/live/domain.domain.com/fullchain.pem (failure)
    1 renew failure(s), 0 parse failure(s)

    IMPORTANT NOTES:
    – The following errors were reported by the server:

    Domain: domain.domain.com
    Type: unauthorized
    Detail: Invalid response from
    http://domain.domain.com/.well-known/acme-challenge/CHANLANGEREMOVED_KINDLY_REMOVED:

    400 The plain HTTP request was sent to HTTPS
    port

    400 B”

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

    Nebenher wäre es schön, wenn Sie ebenfalls dokumentieren können, wie man die einzelnen per Hand hinzugefügten Pakete updaten kann um so auf dem neusten Stand zu sein. Zwecks Security Patches die Vulnerabilities schließen sollen.

    Grüße

    Karsten

    • Besitzer von /var/www bitte auf www-data:www-data korrigieren. Kann ich mir das mal remote (SSH) ansehen?

      • Karsten says:

        Hallo,

        /var gehört root.root
        /var/www gehört www-data.www-data
        /var/www/.well-known gehört wiederum root.root
        Allerdings:
        drwxr-xr-x 2 root root 4.0K Jul 24 19:51 .well-known

        Sollte also passen mit den Berechtigungen.

        Die Maschine ist im Web per SSH nicht erreichbar. Kann Ihnen aber gerne Logs zur Verfügung stellen. Gerne auch per Jabber/xmmp. Oder auch configs. Allerdings habe ich mich strikt an das Tutotrial gehalten. Als OS kommt ein aktuelles Debian zum Einsatz.

        Grüße

        Karsten

      • Karsten says:

        Hallo,

        ich habe heute noch ein wenig getestet. Merkwürdig ist, dass mein http request direkt nach https umgeleitet wird.
        Ich habe testweise eine Datei unter “/var/www/letsencrypt/.well-known/acme-challenge/” erstellt.
        Die Datei trägt den namen test und der inhalt ist ebenfalls “test”
        Wenn ich nun versuche die Datei aufzurufen mit “http://subdomain.domain.com/.well-known/acme-challenge/test”, werde ich direkt nach https umgeleitet und bekomme “403 Forbidden”

        Haben Sie eventuell noch eine Idee?

        Grüße

        Karsten

      • Karsten says:

        Hallo,

        doch ein wenig peinlich…. Ich habe den Fehler gefunden. Port 80 wurde falsch genattet… und zwar auf 443. Dazu kam noch, dass die Firewall auf der Maschine selbst Port 80 blocked hatte.

        Grüße

        Karsten

  35. Alex says:

    Danke für dieses super Tutorial! Einen kleinen Fehler habe ich vermutlich gefunden:

    Nextcloud: 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

    Ich denke, hier wird das touch auf die nextcloud.conf gedacht sein. 🙂

  36. Adam says:

    Great job! Everything working like a charm!

  37. Ed says:

    Hi Carsten,

    I got all the way to the end of this tutorial which took a long time. I had to try many times to get it right, but finally got to the end without errors. Then when I go to my site, I get 500 bad gateway. I’ve googled, but to no avail. I just can’t get it to work. Please help if you can. Thank you in advance!

    • What was written to your corresponding logfiles? Did you cover all steps of my guide exactly? What kind oy a server (on-prem, hosted, full hosted…)

      • Ed says:

        Hi Carsten,
        Thanks for the quick reply.

        I was able to correct the issue. As I’m using Raperian Stretch 9.4 on a PI3 I was unable to use PHP 7.2. It’s not in the package repo and even adding your packages didn’t work. I simply did a fallback to 7.0. As such, it was necessary to change all the references in your tutorial from 7.2 to 7.0.

        Unfortunately, I had forgotten to change the single line in the nginx.conf file: server unix:/run/php/php7.2-fpm.sock; Simply changing it to server unix:/run/php/php7.0-fpm.sock; did the trick. Thanks again!

  38. Ed says:

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

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

    cat /var/log/nginx/error.log
    2018/07/04 16:31:41 [warn] 899#899: invalid value “TLSv1.3” in /etc/nginx/ssl.conf:8

    I’m doing this tutorial on my Raspberry Pi 3. I was unable to do the first step upgrading to Openssl 1.1.0h as the 64 bit packages were incompatible. I’m currently on
    openssl version
    OpenSSL 1.1.0f 25 May 2017

    I also was unable to use PHP 7.2 as even when adding your packages first, it resulted in errors so I substituted PHP 7.0.
    I don’t know if either of these has something to do with the error above.

    Please advise. Thank you!

    • Are you really operating with Debian 9.4 on RPI? Please provide the output of: “systemctl status nginx.service”

      • Ed says:

        Hi Carsten,
        Thanks for the quick reply!

        I’m using Rasperian Stretch 9.4 on my PI3, which I believe is based on Debian so I chose this tutorial as it was closest to my system. Hence, I had to make a few tweaks to get it to work. Your tutorial is awesome by the way. Best on the Internet by far. You are one super smart guy.

        Here are the tweaks I made to correct the errors mentioned above.

        First, I had to change 2 lines in ssl.conf:
        These 2 lines were causing errors:

        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ‘ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK:!AES128’;

        I had to change it to this:
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256;

        And in the nextcloud.conf, I had to comment out the mp4 location section:
        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;
        }

        Once I did these changes, I was able to start the services per this line:
        sed -i s/#include/include/g /etc/nginx/nginx.conf && service nginx restart

        I’m unsure the effect of these changes. I did run the Qualys SSL Labs test and rec’d an A+ rating.

        Note, I am in the process of documenting the changes I had to make to get your tutorial to work on my RPI3 and if you’re interested I can send it to you. Perhaps others running nextlcloud on a PI would benefit.

        It’s also worth noting that this is a new nextcloud build. I have been running nextcloud on my PI3 for about 6 months. I setup that server using a series of tutorials found on the web. The old server is running Apache. I have been wanting to migrate to Nginx. I’m seriously in awe of how much faster and responsive the PI3 is when built using this tutorial with Nginx all your optimizations.

        Thanks again for sharing these fantastic nextcloud tutorials. I’m no expert and could not do it without you!

        • I guess, your issues are relates to the ARM/RPi infrastructure. Beyond that you had to comment the mp4 section because of your NGINX version. I assume, you have choosen the NGINX from the default repos which don’t consists of this module by default (nginx -V)?! Thanks for sharing…i would really appreciate your documentation to be published here 😉

        • Daniel says:

          Thanks a lot for sharing your solution how you got it running on a Raspberry Pi! I had the same two problems with the configuration files. And this tutorial truly is awesome 🙂

  39. Andi says:

    Hallo Carsten

    Kurze Frage: Wo liegt wohl das Problem, wenn das Update auf 13.0.3, einer nach dieser Anleitung erstellten Nextcloud-Instanz, fehlschlägt, weil das Backup nicht erstellt werden kann?

    Danke und Gruss

    • Das lässt sich so pauschal nicht beantworten. Was steht denn im Log?

    • Karsten says:

      Hallo,

      ich vermute, dass es dasselbe Problem war wie bei mir. Wenn dies der Fall ist, liegt ein Rechteproblem vor. Nextcloud kann die Dateien nicht schreiben. Dementsprechend in das Log schauen wohin das Backup gehen soll. Bin momentan nicht zu Hause, sonst könnte ich genau nachschauen. Sobald die Probleme mit den Schreibrechten behoben sind, sollte das Backup eigentlich durchlaufen.

      Grüße

      Karsten

  40. Abner Silva says:

    works perfectly! thanks

  41. Justin says:

    Guten tag, ich hätte da drei Probleme 🙁

    1. Nginx konnte nicht gestartet werden “Directory mp4 doesn’t exsist” (nextcloud.conf).
    Ich habe ihre anleitung auf einem frischen system Installiert muss der Codeblock bleiben? (habe sie erstmal entfernt, seit dem funktioniert Nginx)
    2. Browser meldet gesicherte verbingung fehlgeschlagen (Chrome und Firefox) ich habe ssl.conf nginx.conf und die pfade überprüft, hätten sie eine Idee?
    3. Da der Server neu ist und mehere Domains zu diesem führen (heißt verschiedene Hosts und SSL Zertifikate), wie kann ich mit ihrer ssl.conf mehere Zertifikate einrichten?

    auf hilfe würde ichmich sehr freuen, ich bedanke mich für das HowTo ; )
    Lg. Justin

    • Hallo Justin, bitte prüfen Sie, welche Module von NGINX bereitgestellt werden: nginx -V. Im Stanard ist das MP4-Modul nicht enthalten, haben Sie meinen Guide strikt befolgt? Bitte senden Sie mir Ihre Konfigurationsfiles (nginx.conf, ssl.conf, nextcloud.conf) sowie die Ausgabe “nginx -V” per Mail zu. Ich sehe es mir dann gern an. Verschiedene Zertifikate weren in NGINX via sogenannter SNI’s ghandelt. Sofern ich Ihre Absicht richtig verstehe, so benötigen Sie verschiedene Servereinträge mit den entsprechenden ssl.con-Dateien je Server. Servus, Carsten

  42. Christian says:

    Hi Carsten, hab grad mal versucht alles Up2date zu bringen, jedoch bekomm ich nach der OpenSSL aktualisierung immer noch diese Versionsanzeige..

    root@brainmazing:/usr/local/src# openssl version
    OpenSSL 1.1.0g 2 Nov 2017

    Aber:

    root@brainmazing:/usr/local/src# apt-cache policy openssl
    openssl:
    Installiert: 1.1.0h-4
    Installationskandidat: 1.1.0h-4
    Versionstabelle:
    *** 1.1.0h-4 100
    100 /var/lib/dpkg/status
    1.1.0f-3+deb9u2 500
    500 http://security.debian.org/debian-security stretch/updates/main amd64 Packages
    1.1.0f-3+deb9u1 500
    500 http://ftp.de.debian.org/debian stretch/main amd64 Packages
    1.0.2j-1+0~20161013114109.8+stretch~1.gbpac057a 500
    500 https://packages.sury.org/php stretch/main amd64 Packages

  43. Chris says:

    Hi i think i have the same issue with php..
    i run odroid hc1 on debian9 (armhf)
    and i think i solved it by adding [ deb http://ftp.de.debian.org/debian buster main ] to the sources.list

  44. Georg says:

    Hallo Carsten, will nur sagen das ist mit Abstand eines der besten HowTo´s das ich seit langem gesehen habe
    Ein Traum. lg Georg

  45. Chris says:

    Hallo Carsten,

    Wenn ich den nginx Server neu starten möchte kommt folgende Fehlermeldung:

    Process: 3403 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=1/FAILURE)

    An was kann das liegen? lg Chris

    • Hallo Chris, bitte gib nginx -t ein, das gibt möglicherweise einen Hinwweis auf die Ursache. Deine Ausgabe besagt nur, dass die Konfigurationübersprüfung Fehler entdeckt hat. Was hast Du zuletzt (NGINX) verändert? Servus, Carsten

      • Arne says:

        Hi Carsten,
        ich habe wohl das gleiche Problem wie Chris. Wenn ich nginx -t eingebe kommt folgendes:

        nginx: [emerg] a duplicate default server for 0.0.0.0:80 in /etc/nginx/conf.d/nextcloud.conf:3
        nginx: configuration file /etc/nginx/nginx.conf test failed

        Möglicherweise hatte ich zwischendurch die nginx.conf geändert bei dem Punkt, wo ich begann nextcloud einzurichten, da ich zwar zugriff auf den Server im Heimnetzwerk hatte, aber nicht übers Internet. Nun jedoch kann ich nginx gar nicht mehr starten… Ich hoffe du kannst mir helfen.

        • Der Eintrag “listen 80 default_server;” und listen 443 ssl http2 default_server; darf nur einmal je SNI vorkommen. Kommt es mehrfach in den vhost-Dateien (*.conf) vor, entferne default_server und teste es erneut.
          Sonst lade mir die *.conf-Dateien aus /etc/nginx/conf.d/ hoch: HIER
          Servus, Carsten

          • Arne says:

            Sorry, ich habe es nun doch alles zum Laufen bekommen. Offenbar hat die Fritzbox einen Fehler gehabt. Nachdem ich die Portfreigaben die eigentlich schon richtig eingerichtet waren, gelöscht und wieder neu erstellt habe, lief alles einwandfrei. Danke für dein super Tutorial! Kann ich dir irgendwie einen Kaffee spendieren?

  46. Are we dealing with some live update here? If so, I will refrain from spamming you any further than this:
    The section where you update openssl is missing, but the chapter header is there. The easiest way for me was:

    root@odroid-stretch64:~# openssl version
    OpenSSL 1.1.0f 25 May 2017

    apt purge openssl

    cd /usr/local/src/

    wget http://ftp.nl.debian.org/debian/pool/main/o/openssl/libssl1.1_1.1.0h-2_arm64.deb
    dpkg -i ./libssl1.1_1.1.0h-2_arm64.deb

    wget http://ftp.nl.debian.org/debian/pool/main/o/openssl/openssl_1.1.0h-2_arm64.deb
    dpkg -i openssl_1.1.0h-2_arm64.deb

    root@odroid-stretch64:/usr/local/src# openssl version
    OpenSSL 1.1.0h 27 Mar 2018

  47. ufw commands will result in “Error need ‘to’ or ‘from’ clause.
    This is caused by a missing ‘&&’:
    ufw allow 80/tcp && ufw allow 443/tcp && ufw allow 22/tcp ufw logging medium
    should be:
    ufw allow 80/tcp && ufw allow 443/tcp && ufw allow 22/tcp && ufw logging medium

  48. Franko says:

    Fehler gefunden
    echo “deb https://packages.sury.org/php/ $(lsb_release -sc) main” | tee /etc/apt/sources.list.d/php.list
    danach muss ein ->
    apt update
    kommen

  49. Franko says:

    Hallo Carsten

    mit PHP stimmt was nich bekeomme folgende Meldung:
    Paket php7.2-fpm kann nicht gefunden werden … usw

    MFG Franko

  1. 24. June 2018

    […] Nextcloud 13 installation guide (Debian 9.4 stretch) […]

Leave a Reply

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