Nextcloud in less than 20 minutes

RaspberryPi/oDroidC2, Ubuntu 16.04.03 LTS 64 Bit, NGINX 1.13.6, PHP 7.1, MariaDB, Redis, Nextcloud 12.03, additionally hardened with fail2ban.
(Just adjust or substitute the red marked values: (YOUR.DEDYN.IO and 192.168.2.x))

  1. NGINX
  2. PHP
  3. MariaDB
  4. Redis
  5. Nextcloud (SSL enabled, A+)
  6. fail2ban

Install NGINX:

sudo -s
apt update && apt upgrade -y && apt install zip unzip screen curl ffmpeg libfile-fcntllock-perl -y
apt remove nginx nginx-common nginx-full -y --allow-change-held-packages

Download: NGINX 1.13.6 with ngx_cache_purge (ARM 64Bit)
Download: NGINX 1.13.6 with ngx_cache_purge (AMD 64Bit)

dpkg --install nginx_1.13.6-1~xenial_arm64.deb

Modify NGINX:

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

Change NGINX configuration:

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


user www-data;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/;
events {
 worker_connections 1024;
 multi_accept on;
 use epoll;
http {
 server_names_hash_bucket_size 64;
 upstream php-handler {
 server unix:/run/php/php7.1-fpm.sock;
 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 IP is your Router-IP (e.g. your FritzBox)
 resolver_timeout 10s;
 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 /upload_tmp && chown -R www-data:www-data /upload_tmp /var/nc_data /var/www

Install PHP:

sudo -s
apt install language-pack-en-base -y && sudo LC_ALL=en_US.UTF-8 add-apt-repository ppa:ondrej/php -y
apt update && apt install php7.1-fpm php7.1-gd php7.1-mysql php7.1-curl php7.1-xml php7.1-zip php7.1-intl php7.1-mcrypt php7.1-mbstring php-apcu php-imagick php7.1-json php7.1-bz2 php7.1-zip -y

Awesome, PHP 7.1 is already installed.

Configure PHP:

cp /etc/php/7.1/fpm/pool.d/www.conf /etc/php/7.1/fpm/pool.d/www.conf.bak
cp /etc/php/7.1/cli/php.ini /etc/php/7.1/cli/php.ini.bak
cp /etc/php/7.1/fpm/php.ini /etc/php/7.1/fpm/php.ini.bak
cp /etc/php/7.1/fpm/php-fpm.conf /etc/php/7.1/fpm/php-fpm.conf.bak
sed -i "s/;env\[HOSTNAME\] = /env[HOSTNAME] = /" /etc/php/7.1/fpm/pool.d/www.conf
sed -i "s/;env\[TMP\] = /env[TMP] = /" /etc/php/7.1/fpm/pool.d/www.conf
sed -i "s/;env\[TMPDIR\] = /env[TMPDIR] = /" /etc/php/7.1/fpm/pool.d/www.conf
sed -i "s/;env\[TEMP\] = /env[TEMP] = /" /etc/php/7.1/fpm/pool.d/www.conf
sed -i "s/;env\[PATH\] = /env[PATH] = /" /etc/php/7.1/fpm/pool.d/www.conf
sed -i "s/pm.max_children = .*/pm.max_children = 240/" /etc/php/7.1/fpm/pool.d/www.conf
sed -i "s/pm.start_servers = .*/pm.start_servers = 20/" /etc/php/7.1/fpm/pool.d/www.conf
sed -i "s/pm.min_spare_servers = .*/pm.min_spare_servers = 10/" /etc/php/7.1/fpm/pool.d/www.conf
sed -i "s/pm.max_spare_servers = .*/pm.max_spare_servers = 20/" /etc/php/7.1/fpm/pool.d/www.conf
sed -i "s/;pm.max_requests = 500/pm.max_requests = 500/" /etc/php/7.1/fpm/pool.d/www.conf
sed -i "s/output_buffering =.*/output_buffering = Off/" /etc/php/7.1/cli/php.ini
sed -i "s/max_execution_time =.*/max_execution_time = 1800/" /etc/php/7.1/cli/php.ini
sed -i "s/max_input_time =.*/max_input_time = 3600/" /etc/php/7.1/cli/php.ini
sed -i "s/post_max_size =.*/post_max_size = 10240M/" /etc/php/7.1/cli/php.ini
sed -i "s/;upload_tmp_dir =.*/upload_tmp_dir = \/upload_tmp/" /etc/php/7.1/cli/php.ini
sed -i "s/upload_max_filesize =.*/upload_max_filesize = 10240M/" /etc/php/7.1/cli/php.ini
sed -i "s/max_file_uploads =.*/max_file_uploads = 100/" /etc/php/7.1/cli/php.ini
sed -i "s/;date.timezone.*/date.timezone = Europe\/\Berlin/" /etc/php/7.1/cli/php.ini
sed -i "s/;session.cookie_secure.*/session.cookie_secure = True/" /etc/php/7.1/cli/php.ini
sed -i '$aapc.enable_cli = 1' /etc/php/7.1/cli/php.ini
sed -i "s/output_buffering =.*/output_buffering = Off/" /etc/php/7.1/fpm/php.ini
sed -i "s/max_execution_time =.*/max_execution_time = 1800/" /etc/php/7.1/fpm/php.ini
sed -i "s/max_input_time =.*/max_input_time = 3600/" /etc/php/7.1/fpm/php.ini
sed -i "s/post_max_size =.*/post_max_size = 10240M/" /etc/php/7.1/fpm/php.ini
sed -i "s/;upload_tmp_dir =.*/upload_tmp_dir = \/upload_tmp/" /etc/php/7.1/fpm/php.ini
sed -i "s/upload_max_filesize =.*/upload_max_filesize = 10240M/" /etc/php/7.1/fpm/php.ini
sed -i "s/max_file_uploads =.*/max_file_uploads = 100/" /etc/php/7.1/fpm/php.ini
sed -i "s/;date.timezone.*/date.timezone = Europe\/\Berlin/" /etc/php/7.1/fpm/php.ini
sed -i "s/;session.cookie_secure.*/session.cookie_secure = True/" /etc/php/7.1/fpm/php.ini
sed -i "s/;opcache.enable=.*/opcache.enable=1/" /etc/php/7.1/fpm/php.ini
sed -i "s/;opcache.enable_cli=.*/opcache.enable_cli=1/" /etc/php/7.1/fpm/php.ini
sed -i "s/;opcache.memory_consumption=.*/opcache.memory_consumption=128/" /etc/php/7.1/fpm/php.ini
sed -i "s/;opcache.interned_strings_buffer=.*/opcache.interned_strings_buffer=8/" /etc/php/7.1/fpm/php.ini
sed -i "s/;opcache.max_accelerated_files=.*/opcache.max_accelerated_files=10000/" /etc/php/7.1/fpm/php.ini
sed -i "s/;opcache.revalidate_freq=.*/opcache.revalidate_freq=1/" /etc/php/7.1/fpm/php.ini
sed -i "s/;opcache.save_comments=.*/opcache.save_comments=1/" /etc/php/7.1/fpm/php.ini
sed -i "s/;emergency_restart_threshold =.*/emergency_restart_threshold = 10/" /etc/php/7.1/fpm/php-fpm.conf
sed -i "s/;emergency_restart_interval =.*/emergency_restart_interval = 1m/" /etc/php/7.1/fpm/php-fpm.conf
sed -i "s/;process_control_timeout =.*/process_control_timeout = 10s/" /etc/php/7.1/fpm/php-fpm.conf

Restart PHP and NGINX:

service php7.1-fpm restart && service nginx restart


sudo -s
apt update && apt install mariadb-server -y

Secure MariaDB:


Configure MariaDB:

cp /etc/mysql/my.cnf /etc/mysql/my.cnf.bak && vi /etc/mysql/my.cnf

Change the entire my.cnf-file to:

innodb_buffer_pool_size = 128M
innodb_buffer_pool_instances = 1
innodb_flush_log_at_trx_commit = 2
innodb_log_buffer_size = 32M
innodb_max_dirty_pages_pct = 90
query_cache_type = 1
query_cache_limit = 2M
query_cache_min_res_unit = 2k
query_cache_size = 64M
tmp_table_size= 64M
max_heap_table_size= 64M
slow-query-log = 1
slow-query-log-file = /var/log/mysql/slow.log
long_query_time = 1

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

default-character-set = utf8mb4

character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
binlog_format = MIXED

Restart and connect to MariaDB:

service mysql restart && mysql -uroot

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;


sudo -s
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

Modify /etc/sysctl.conf and /etc/rc.local:

cp /etc/sysctl.conf /etc/sysctl.conf.bak && sed -i '$avm.overcommit_memory = 1' /etc/sysctl.conf
cp /etc/rc.local /etc/rc.local.bak && sed -i '$i \sysctl -w net.core.somaxconn=65535' /etc/rc.local

Reboot your server:

shutdown -r now

Create the nextcloud.conf:

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:

fastcgi_cache_path /usr/local/tmp/cache levels=1:2 keys_zone=NEXTCLOUD:100m inactive=60m;
map $request_uri $skip_cache {
 default 1;
 ~*/thumbnail.php 0;
 ~*/apps/galleryplus/ 0;
 ~*/apps/gallery/ 0;
server {
 listen 80 default_server;
 server_name YOUR.DEDYN.IO;
 #Your DDNS adress, (e.g. from or
 location ^~ /.well-known/acme-challenge {
 location / {
 return 301 https://$host$request_uri;
server {
 listen 443 ssl http2 default_server;
 server_name YOUR.DEDYN.IO;
 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 ~ ^/(?: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;
 fastcgi_cache_bypass $skip_cache;
 fastcgi_no_cache $skip_cache;
 fastcgi_cache NEXTCLOUD;
 location ~ ^/(?:updater|ocs-provider)(?:$|/) {
 try_files $uri/ =404;
 index index.php;
 location ~ \.(?:css|js|woff|svg|gif)$ {
 try_files $uri /index.php$uri$is_args$args;
 add_header Cache-Control "public, max-age=15778463";
 access_log off;
 expires 30d;
 location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ {
 try_files $uri /index.php$uri$is_args$args;
 access_log off;
 expires 30d;

Create the letsencrypt.conf:

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

Paste the following rows:

server {
listen 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/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/fullchain.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_ecdh_curve secp384r1;
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;
proxy_buffering off;
proxy_max_temp_file_size 1024m;

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 "same-origin" always;

Create the optimization.conf:

vi /etc/nginx/optimization.conf

Paste the following rows:

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

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

Please be patient, it will take a while.

Restart NGINX:

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

Download and extract Nextcloud:

cd /usr/local/src && wget && tar -xjf nextcloud-12.0.3.tar.bz2 -C /var/www && chown -R www-data:www-data /var/www/

Install letsencrypt and request your ssl-certificates:

add-apt-repository ppa:certbot/certbot -y && apt update && apt install letsencrypt -y
letsencrypt certonly -a webroot --webroot-path=/var/www/letsencrypt --rsa-key-size 4096 -d YOUR.DEDYN.IO

Apply the permissions using a script:

vi /root/

Paste the following rows:

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

Run the script:

chmod +x /root/ && /root/

Modify the ssl.conf and restart NGINX:

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

Open your browser and call:


to configure Nextcloud. Enter the following values:

Username: cloudroot
Password*: Your-NC_Password!
Data folder: /var/nc_data
Datenbankuser: nextcloud
DB-Passwort*: nextcloud
Datenbank-Name: nextcloud
Host: localhost

Finish the installation in your browser, then open the config.php as www-data:

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

Adjust your config.php:

$CONFIG = array (
'instanceid' => '...keep your values...',
'passwordsalt' => '...keep your values...',
'secret' => '...keep your values...',
'trusted_domains' =>
array (
'datadirectory' => '/var/nc_data',
'dbtype' => 'mysql',
 'version' => '',
 'dbname' => 'nextcloud',
 'dbhost' => 'localhost',
 'dbport' => '',
 'dbtableprefix' => 'oc_',
 'mysql.utf8mb4' => true,
 'dbuser' => 'nextcloud',
 'dbpassword' => 'nextcloud',
 'installed' => true,
 'htaccess.RewriteBase' => '/',
 'overwriteprotocol' => 'https',
 'loglevel' => 1,
 'logtimezone' => 'Europe/Berlin',
 'logfile' => '/var/nc_data/nextcloud.log',
 'log_rotate_size' => 104857600,
 'cron_log' => true,
 'filesystem_check_changes' => 1,
 'quota_include_external_storage' => false,
 'knowledgebaseenabled' => false,
 'memcache.local' => '\\OC\\Memcache\\APCu',
 'filelocking.enabled' => 'true',
 'memcache.locking' => '\\OC\\Memcache\\Redis',
 'redis' =>
 array (
 'host' => '/var/run/redis/redis.sock',
 'port' => 0,
 'timeout' => 0.0,
 'maintenance' => false,
 'theme' => '',
 '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',
 'preview_max_x' => 1024,
 'preview_max_y' => 768,
 'preview_max_scale_factor' => 1,

Edit the .user.ini:

sudo -u www-data sed -i "s/upload_max_filesize=.*/upload_max_filesize=10240M/" /var/www/nextcloud/.user.ini
sudo -u www-data sed -i "s/post_max_size=.*/post_max_size=10240M/" /var/www/nextcloud/.user.ini
sudo -u www-data sed -i "s/output_buffering=.*/output_buffering='Off'/" /var/www/nextcloud/.user.ini

Configure and enable a Nextcloud cron-job:

crontab -u www-data -e

Paste the following row:

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

Don’t forget to switch from Ajax to Cron in Nextclouds-Adminpanel.

Harden your System using fail2ban:

Install fail2ban:

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

Create the Nextcloud-filter:

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

Paste the following lines:

failregex = ^.*Login failed: '.*' \(Remote IP: '<HOST>'.*$
ignoreregex =

Create a new jail:

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

Paste the following rows:

ignoreip =
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

Find more details, renewal- and backup-scripts and more tweaks & hardenings on my Nextcloud installation guide.

Carsten Rieger

Leave a Reply

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