Nextcloud 14 installation guide (Debian 9.5 stretch)


Following this guide you will be able to install and configure Nextcloud 14 latest based on Debian 9.5 stretch, NGINX 1.15.3, openssl 1.1.0, TLSv1.2, PHP 7.2, MariaDB 10.3, Redis, fail2ban, firewall (ufw) and will achieve an A+ rating from as well Nextcloud as Qualys SSL Labs. We will request and implement the ssl certificate from Let’s Encrypt in chapter X.

You only have to ammend the red marked values (YOUR.DEDYN.IO, 192.168.2.x, 22) regarding your environment!


Last Updates:

September, 21st 2018:
– ammendments to nginx.conf: resolver 208.67.222.222 valid=30s; resolver_timeout 5s;

… the entire update history


Table of content

  1. Update to openssl 1.1.0h
  2. Install NGINX
  3. Install PHP
  4. Install MariaDB
  5. Install Redis-Server
  6. Preparations for Nextcloud
  7. Hardenings

Update to openssl 1.1.0h

su -
apt purge openssl && cd /usr/local/src/
wget http://ftp.nl.debian.org/debian/pool/main/o/openssl/libssl1.1_1.1.0h-4_amd64.deb
dpkg -i ./libssl1.1_1.1.0h-4_amd64.deb
wget http://ftp.nl.debian.org/debian/pool/main/o/openssl/openssl_1.1.0h-4_amd64.deb
dpkg -i openssl_1.1.0h-4_amd64.deb
root@debian:/usr/local/src# openssl version
OpenSSL 1.1.0h 27 Mar 2018
root@debian:/usr/local/src#

Install NGINX

cd /usr/local/src/
apt update && apt upgrade -y && apt install apt-transport-https lsb-release ca-certificates software-properties-common zip unzip screen curl ffmpeg libfile-fcntllock-perl -y
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
wget http://nginx.org/keys/nginx_signing.key && apt-key add nginx_signing.key
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.2-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 valid=30s;
#openDNS-IP (208.67.222.222) or choose e.g. your fritz.box IP like 192.168.2.1 instead
resolver_timeout 5s;
include /etc/nginx/conf.d/*.conf;
}

Start NGINX

service nginx restart

Create folders and apply permissions

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

Install PHP

apt install apt-transport-https lsb-release ca-certificates -y
wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | tee /etc/apt/sources.list.d/php.list
apt update
apt install php7.2-fpm php7.2-gd php7.2-mysql php7.2-curl php7.2-xml php7.2-zip php7.2-intl php7.2-mbstring php7.2-json php7.2-bz2 php7.2-ldap php-apcu imagemagick php-imagick -y

Configure PHP

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

Modify /etc/fstab

Determine the uid of your www-data user by issuing

id www-data

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

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

OPTIONAL:

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

Mount tmpfs and then restart both, PHP and NGINX

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

Install MariaDB

apt install software-properties-common dirmngr -y
apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xF1656F24C74CD1D8
add-apt-repository 'deb [arch=amd64,i386,ppc64el] https://mirror.herrbischoff.com/mariadb/repo/10.3/debian stretch main'
apt update && apt install mariadb-server -y && mysql_secure_installation
Enter current password for root (enter for none): 
Set root password? [Y/n] Y
Remove anonymous users? [Y/n] Y
Disallow root login remotely? [Y/n] Y
Remove test database and access to it? [Y/n] Y
Reload privilege tables now? [Y/n] Y

Configure MariaDB

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

Paste the following rows:

[client]
port = 3306
socket = /var/run/mysqld/mysqld.sock
default-character-set = utf8mb4

[mysqld_safe]
socket = /var/run/mysqld/mysqld.sock
nice = 0

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

[mysqldump]
quick
quote-names
max_allowed_packet = 16M

[mysql]
#no-auto-rehash    # faster start of mysql but no tab completion

[isamchk]
key_buffer = 16M

!include /etc/mysql/mariadb.cnf
!includedir /etc/mysql/conf.d/

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

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 && touch /etc/nginx/conf.d/default.conf
vi /etc/nginx/conf.d/nextcloud.conf

Paste the following rows:

server {
server_name YOUR.DEDYN.IO;
#Your DDNS adress, (e.g. from desec.io or no-ip.com) 
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 ~ ^/(?: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|woff|svg|gif|png|html|ttf|ico|jpg|jpeg)$ {
try_files $uri /index.php$uri$is_args$args;
access_log off;
expires 360d;
}
}

Create the letsencrypt.conf

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

Paste the following rows:

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

Create the ssl.conf

vi /etc/nginx/ssl.conf

Paste the following rows

ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
ssl_trusted_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
#ssl_certificate /etc/letsencrypt/live/YOUR.DEDYN.IO/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/YOUR.DEDYN.IO/privkey.pem;
#ssl_trusted_certificate /etc/letsencrypt/live/YOUR.DEDYN.IO/chain.pem;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
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;

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;

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;

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

apt install ssl-cert -y && 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

Install letsencrypt and request your ssl-certificates

apt update && apt install letsencrypt -y
letsencrypt certonly -a webroot --webroot-path=/var/www/letsencrypt --rsa-key-size 4096 -d YOUR.DEDYN.IO
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:

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

Nextcloud installation 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"'

–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.2-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 > /dev/null 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.2-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:

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

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

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.


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

79 Responses

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

  2. 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?

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

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

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

  6. 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?

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

  8. 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!

  9. SuperK2 says:

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

    I will report my experiences here.

    Regards

  10. 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 =

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

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

  13. 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 \OC\Memcache\APCu not available for local cache
    > Info cli Memcache \OC\Memcache\APCu not available for distributed cache
    Can APCU work with PHP7.2? I read somewhere that I should run pecl install apcu`
    Thank you!

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

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

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

  17. 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. 🙂

  18. Adam says:

    Great job! Everything working like a charm!

  19. 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!

  20. 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 🙂

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

  22. Abner Silva says:

    works perfectly! thanks

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

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

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

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

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

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

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

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

  31. 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 *