Nextcloud 15 installation guide (Ubuntu/Apache2)

Nextcloud HowTo

Following this guide you will be able to install and configure Nextcloud 15 (latest) based on Ubuntu 18.04.1 LTS, Apache 2.4.x (mpm_event, http2), PHP 7.3, MariaDB 10.3, Redis, fail2ban, ufw and achieve an A+ rating from both, Nextcloud and Qualys SSL Labs. We will request and implement the ssl certificate from Let’s Encrypt in this guide. You only have to ammend the red marked values (YOUR.DEDYN.IO, 192.168.2.x, 22) regarding your environment!

Last Updates:

January, 17th 2019:
– made changes to the feature policy in the header.conf

… the entire update history


sudo -s
apt update && apt upgrade -y
apt install software-properties-common && apt install -y zip unzip screen curl ffmpeg
add-apt-repository -y ppa:ondrej/php && add-apt-repository -y ppa:ondrej/apache2 && add-apt-repository -y ppa:certbot/certbot
apt update && apt upgrade -y && apt autoremove -y && apt autoclean -y

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
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
mkdir -p /var/www /var/nc_data /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
mount -a


If you are interested in Postgresql instead of MariaDB please have a look here.
First we add the MariaDB repository to gain long term support using MariaDB 10.3 – maintained until 2023:

apt-key adv --recv-keys --keyserver hkp:// 0xF1656F24C74CD1D8
add-apt-repository 'deb [arch=amd64,arm64] bionic main'

Update your system and install MariaDB:

apt update && apt install mariadb-server -y

Verify your database server version:

mysql --version

An output like

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

should appear.

Secure MariaDB:

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

Change the entire my.cnf-file to:

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

socket = /var/run/mysqld/mysqld.sock
nice = 0

user = mysql
pid-file = /var/run/mysqld/
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
bind-address =
max_connections = 200
connect_timeout = 5
wait_timeout = 600
max_allowed_packet = 16M
thread_cache_size = 128
sort_buffer_size = 4M
bulk_insert_buffer_size = 16M
tmp_table_size = 64M
max_heap_table_size = 64M
myisam_recover_options = BACKUP
key_buffer_size = 128M
#open-files-limit = 2000
table_open_cache = 400
myisam_sort_buffer_size = 512M
concurrent_insert = 2
read_buffer_size = 2M
read_rnd_buffer_size = 1M
query_cache_limit = 2M
query_cache_size = 64M
query_cache_type = 1
query_cache_min_res_unit = 2k
log_warnings = 2
slow_query_log_file = /var/log/mysql/mariadb-slow.log
long_query_time = 1
log_slow_verbosity = query_plan
slow-query-log = 1
slow-query-log-file = /var/log/mysql/slow.log
log_bin = /var/log/mysql/mariadb-bin
log_bin_index = /var/log/mysql/mariadb-bin.index
expire_logs_days = 10
max_binlog_size = 100M
default_storage_engine = InnoDB
innodb_buffer_pool_size = 1024M
innodb_buffer_pool_instances = 1
innodb_flush_log_at_trx_commit = 2
innodb_log_buffer_size = 32M
innodb_max_dirty_pages_pct = 90
innodb_file_per_table = 1
innodb_open_files = 400
innodb_io_capacity = 4000
innodb_flush_method = O_DIRECT
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
transaction_isolation = READ-COMMITTED
binlog_format = ROW

max_allowed_packet = 16M

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

key_buffer = 16M

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

Restart MariaDB:

service mysql restart

Create the database and the user:

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

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

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

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

Install Apache2, PHP and Redis-Server:

apt install libapache2-mod-php7.3 php7.3-cli php7.3-common php7.3-mbstring php7.3-gd php7.3-intl php7.3-xml php7.3-mysql php7.3-zip php7.3-dev php7.3-curl php7.3-fpm php7.3-json php7.3-bz2 php7.3-ldap php-dompdf php-apcu imagemagick php-imagick php-smbclient redis-server php-redis unzip -y

Disable PHP 7.3 and mpm_prefork and enable php7.3-fpm with mpm_event:

a2dismod php7.3 && a2dismod mpm_prefork && a2enmod proxy_fcgi setenvif mpm_event && service apache2 restart
a2enconf php7.3-fpm && service apache2 restart

Download and extract the latest Nextcloud Release:

unzip && mv nextcloud/ /var/www/html/ && chown -R www-data:www-data /var/www/html/nextcloud && rm


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

Enable further Apache modules:

a2enmod rewrite headers env dir mime && service apache2 restart

Prepare your server for Let’s Encrypt:

apt install python-certbot-apache -y
cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/001-nextcloud.conf
rm /etc/apache2/sites-available/000-default.conf && rm /etc/apache2/sites-enabled/000-default.conf

Modify the initial Nextcloud vhost:

vi /etc/apache2/sites-available/001-nextcloud.conf

Make ammendments to the following rows:

DocumentRoot /var/www/html/nextcloud

Request your certificates by issuing

a2ensite 001-nextcloud.conf && service apache2 restart && certbot --apache

Choose ‘1’, then ‘2’ as shown in the screenshot:

Make further adjustements to the intial vhost:

mv /etc/apache2/sites-available/001-nextcloud.conf /etc/apache2/sites-available/001-nextcloud.conf.le-bak
vi /etc/apache2/sites-available/001-nextcloud.conf

Paste all the following rows and replace the red ones:

<VirtualHost *:80>
DocumentRoot /var/www/html/nextcloud
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
RewriteEngine on
RewriteCond %{SERVER_NAME}
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

Make further adjustements to the intial vhost:

cp /etc/apache2/sites-available/001-nextcloud-le-ssl.conf /etc/apache2/sites-available/001-nextcloud-le-ssl.conf.bak
vi /etc/apache2/sites-available/001-nextcloud-le-ssl.conf

Paste all the following rows and replace the red ones:

<IfModule mod_ssl.c>
<VirtualHost *:443>
SSLEngine on
SSLOptions +StrictRequire
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined
LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common
DocumentRoot /var/www/html/nextcloud
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLCertificateFile /etc/letsencrypt/live/
SSLCACertificateFile /etc/letsencrypt/live/
SSLCertificateKeyFile /etc/letsencrypt/live/
<Directory /var/www/html/nextcloud/>
Options +FollowSymlinks
AllowOverride All
<IfModule mod_dav.c>
Dav off
SetEnv HOME /var/www/html/nextcloud
SetEnv HTTP_HOME /var/www/html/nextcloud
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=15768000; preload"
Header set Referrer-Policy "strict-origin-when-cross-origin"
Header set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Feature-Policy "accelerometer 'none'; autoplay 'self'; geolocation 'none'; midi 'none'; notifications 'self'; push 'self'; sync-xhr 'self'; microphone 'self'; camera 'self'; magnetometer 'none'; gyroscope 'none'; speaker 'self'; vibrate 'self'; fullscreen 'self'; payment 'none'; usb 'none'"
SSLProtocol TLSv1.2
SSLHonorCipherOrder on
SSLCompression off
SSLSessionTickets off
SSLUseStapling on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
SSLStaplingCache shmcb:/var/run/ocsp(128000)
SSLOpenSSLConfCmd Curves secp384r1
SSLOpenSSLConfCmd DHParameters "/etc/ssl/certs/dhparam.pem"

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. When dhparam was generated just modify the apache.conf:

vi /etc/apache2/apache2.conf

At the beginning of this file add the following new row


and replace ‘AllowOverride None‘ to ‘All‘ as follows in the shown section:

<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted

Restart apache by issuing

service apache2 restart

Tune your PHP:

cp /etc/php/7.3/fpm/pool.d/www.conf /etc/php/7.3/fpm/pool.d/www.conf.bak
cp /etc/php/7.3/cli/php.ini /etc/php/7.3/cli/php.ini.bak
cp /etc/php/7.3/fpm/php.ini /etc/php/7.3/fpm/php.ini.bak
cp /etc/php/7.3/fpm/php-fpm.conf /etc/php/7.3/fpm/php-fpm.conf.bak
sed -i "s/;env\[HOSTNAME\] = /env[HOSTNAME] = /" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/;env\[TMP\] = /env[TMP] = /" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/;env\[TMPDIR\] = /env[TMPDIR] = /" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/;env\[TEMP\] = /env[TEMP] = /" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/;env\[PATH\] = /env[PATH] = /" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/pm.max_children = .*/pm.max_children = 240/" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/pm.start_servers = .*/pm.start_servers = 20/" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/pm.min_spare_servers = .*/pm.min_spare_servers = 10/" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/pm.max_spare_servers = .*/pm.max_spare_servers = 20/" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/;pm.max_requests = 500/pm.max_requests = 500/" /etc/php/7.3/fpm/pool.d/www.conf
sed -i "s/output_buffering =.*/output_buffering = 'Off'/" /etc/php/7.3/cli/php.ini
sed -i "s/max_execution_time =.*/max_execution_time = 1800/" /etc/php/7.3/cli/php.ini
sed -i "s/max_input_time =.*/max_input_time = 3600/" /etc/php/7.3/cli/php.ini
sed -i "s/post_max_size =.*/post_max_size = 10240M/" /etc/php/7.3/cli/php.ini
sed -i "s/;upload_tmp_dir =.*/upload_tmp_dir = \/upload_tmp/" /etc/php/7.3/cli/php.ini
sed -i "s/upload_max_filesize =.*/upload_max_filesize = 10240M/" /etc/php/7.3/cli/php.ini
sed -i "s/max_file_uploads =.*/max_file_uploads = 100/" /etc/php/7.3/cli/php.ini
sed -i "s/;date.timezone.*/date.timezone = Europe\/\Berlin/" /etc/php/7.3/cli/php.ini
sed -i "s/;session.cookie_secure.*/session.cookie_secure = True/" /etc/php/7.3/cli/php.ini
sed -i "s/;session.save_path =.*/session.save_path = \"N;700;\/usr\/local\/tmp\/sessions\"/" /etc/php/7.3/cli/php.ini
sed -i '$aapc.enable_cli = 1' /etc/php/7.3/cli/php.ini
sed -i "s/memory_limit = 128M/memory_limit = 512M/" /etc/php/7.3/fpm/php.ini
sed -i "s/output_buffering =.*/output_buffering = 'Off'/" /etc/php/7.3/fpm/php.ini
sed -i "s/max_execution_time =.*/max_execution_time = 1800/" /etc/php/7.3/fpm/php.ini
sed -i "s/max_input_time =.*/max_input_time = 3600/" /etc/php/7.3/fpm/php.ini
sed -i "s/post_max_size =.*/post_max_size = 10240M/" /etc/php/7.3/fpm/php.ini
sed -i "s/;upload_tmp_dir =.*/upload_tmp_dir = \/upload_tmp/" /etc/php/7.3/fpm/php.ini
sed -i "s/upload_max_filesize =.*/upload_max_filesize = 10240M/" /etc/php/7.3/fpm/php.ini
sed -i "s/max_file_uploads =.*/max_file_uploads = 100/" /etc/php/7.3/fpm/php.ini
sed -i "s/;date.timezone.*/date.timezone = Europe\/\Berlin/" /etc/php/7.3/fpm/php.ini
sed -i "s/;session.cookie_secure.*/session.cookie_secure = True/" /etc/php/7.3/fpm/php.ini
sed -i "s/;opcache.enable=.*/opcache.enable=1/" /etc/php/7.3/fpm/php.ini
sed -i "s/;opcache.enable_cli=.*/opcache.enable_cli=1/" /etc/php/7.3/fpm/php.ini
sed -i "s/;opcache.memory_consumption=.*/opcache.memory_consumption=128/" /etc/php/7.3/fpm/php.ini
sed -i "s/;opcache.interned_strings_buffer=.*/opcache.interned_strings_buffer=8/" /etc/php/7.3/fpm/php.ini
sed -i "s/;opcache.max_accelerated_files=.*/opcache.max_accelerated_files=10000/" /etc/php/7.3/fpm/php.ini
sed -i "s/;opcache.revalidate_freq=.*/opcache.revalidate_freq=1/" /etc/php/7.3/fpm/php.ini
sed -i "s/;opcache.save_comments=.*/opcache.save_comments=1/" /etc/php/7.3/fpm/php.ini
sed -i "s/;session.save_path =.*/session.save_path = \"N;700;\/usr\/local\/tmp\/sessions\"/" /etc/php/7.3/fpm/php.ini
sed -i "s/;emergency_restart_threshold =.*/emergency_restart_threshold = 10/" /etc/php/7.3/fpm/php-fpm.conf
sed -i "s/;emergency_restart_interval =.*/emergency_restart_interval = 1m/" /etc/php/7.3/fpm/php-fpm.conf
sed -i "s/;process_control_timeout =.*/process_control_timeout = 10s/" /etc/php/7.3/fpm/php-fpm.conf
sed -i '$aapc.enabled=1' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.file_update_protection=2' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.optimization=0' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.shm_size=256M' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.include_once_override=0' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.shm_segments=1' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.ttl=7200' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.user_ttl=7200' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.gc_ttl=3600' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.num_files_hint=1024' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.enable_cli=0' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.max_file_size=5M' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.cache_by_default=1' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.use_request_time=1' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.slam_defense=0' /etc/php/7.3/fpm/php.ini
sed -i '$aapc.mmap_file_mask=/usr/local/tmp/apc/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 -

Nextcloud Installation:

Open your browser and call to configure Nextcloud. Enter the following values:

Username: Your-NC-Admin
Password*: Your-NC_Password!

Data folder: /var/nc_data
Datenbankuser: nextcloud
DB-Passwort*: nextcloud
Datenbank-Name: nextcloud
Host: localhost

After a few seconds Nexcloud will be installed and you will be redirected to Nextclouds file app. Please log out directly and make further ammendments.

sudo -u www-data vi /var/www/html/nextcloud/.htaccess

Paste or replace the red ones:

<IfModule mod_php7.c>
php_value upload_max_filesize 10240M
php_value post_max_size 10240M
php_value memory_limit 512M
php_value mbstring.func_overload 0
php_value default_charset 'UTF-8'
php_value output_buffering 'Off'
<IfModule mod_env.c>
ErrorDocument 403 //
ErrorDocument 404 //
<IfModule mod_rewrite.c>
  Options -MultiViews
  RewriteRule ^core/js/oc.js$ index.php [PT,E=PATH_INFO:$1]
  RewriteRule ^core/preview.png$ index.php [PT,E=PATH_INFO:$1]
  RewriteCond %{REQUEST_FILENAME} !\.(css|js|svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$
  RewriteCond %{REQUEST_FILENAME} !core/img/favicon.ico$
  RewriteCond %{REQUEST_FILENAME} !core/img/manifest.json$
  RewriteCond %{REQUEST_FILENAME} !/remote.php
  RewriteCond %{REQUEST_FILENAME} !/public.php
  RewriteCond %{REQUEST_FILENAME} !/cron.php
  RewriteCond %{REQUEST_FILENAME} !/core/ajax/update.php
  RewriteCond %{REQUEST_FILENAME} !/status.php
  RewriteCond %{REQUEST_FILENAME} !/ocs/v1.php
  RewriteCond %{REQUEST_FILENAME} !/ocs/v2.php
  RewriteCond %{REQUEST_FILENAME} !/robots.txt
  RewriteCond %{REQUEST_FILENAME} !/updater/
  RewriteCond %{REQUEST_FILENAME} !/ocs-provider/
  RewriteCond %{REQUEST_URI} !^/.well-known/(acme-challenge|pki-validation)/.*
  RewriteRule . index.php [PT,E=PATH_INFO:$1]
  RewriteBase /
  <IfModule mod_env.c>
    SetEnv front_controller_active true
    <IfModule mod_dir.c>
      DirectorySlash off

Then adjust Nextclouds config.php.

sudo -u www-data cp /var/www/html/nextcloud/config/config.php /var/www/html/nextcloud/config/config.php.bak

Expand your Nextcloud config.php:

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

Edit the .user.ini:

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

Adjust Nextcloud

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

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


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

(infos: BigInt, missing indices)


vi /root/
redis-cli -s /var/run/redis/redis-server.sock <<EOF
sudo -u www-data php /var/www/html/nextcloud/occ files:scan --all
sudo -u www-data php /var/www/html/nextcloud/occ files:scan-app-data
exit 0

Save the script and mark it as executable

chmod +x /root/

Issue the script initially:


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/html/nextcloud/cron.php > /dev/null 2>&1

For root:

crontab -e

Paste the follwoing rows:

5 1 * * * /root/ > /dev/null 2>&1

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

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

Modify the mpm_event.conf

vi /etc/apache2/mods-available/mpm_event.conf

Change the “MaxConnectionsPerChild” value to 1000:

StartServers 2
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxRequestWorkers 150
MaxConnectionsPerChild 1000

At least we will enable http2 by issuing

a2enmod http2 && service php7.3-fpm restart && service apache2 restart

and create a http2.conf with few settings:

vi /etc/apache2/conf-available/http2.conf

Paste all the following rows:

<IfModule http2_module>
Protocols h2 h2c http/1.1
H2Direct on
H2StreamMaxMemSize 5120000000

and enable this configuration by issuing

a2enconf http2 && service apache2 restart

Finally we will secure Apache to a minimum level by diasbaling Apaches status module (as long as you won’t need it in particular) and altering the security.conf:

a2dismod status && vi /etc/apache2/conf-available/security.conf

Change the values to the red ones:

ServerTokens Prod
ServerSignature Off
TraceEnable Off

and restart PHP, Apache2 and Redis one last time.

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

Nextcloud is now already secured, up and running! Beyond that we will harden the system using fail2ban and ufw. First we install and configure fail2ban and finally we will configure the firewall (ufw).

Install and configure fail2ban:

apt update && apt install fail2ban -y

Create the Nextcloud-filter:

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

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

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

Create a new jail:

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

Paste the following rows:

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

ufw allow 80/tcp && ufw allow 443/tcp && ufw allow 22/tcp

Enable and restart ufw by running

ufw enable && service ufw restart

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.

42 Responses

  1. Micha says:

    Hallo Carsten

    ich nutze ubuntu 18.04.1 auf einem arm System (odroid c2)
    Es ist leider kein PHP7.3 zu finden. Bis zur Grundeinrichtung (anlegen NC Admin User) läuft die Installation. Nach den weiteren Anpassungen wird kein Inhalt mehr auf der Website angezeigt (File not found).
    Im Apache Logfile erscheint: “AH01071: Got error ‘Primary script unknown\n” und” proxy_fcgi:error”.
    Kann das am fehlenden PHP7.3 liegen (wir haben anstelle dessen PHP7.2 installiert).

    Das Versionsproblem betrifft auch Maria-DB. Hier haben wir die Version mariadb-server-10.1 installiert, weil 10.3 ebenfalls nicht auffindbar ist.

    Danke und VG

    • PHP:
      sudo apt install software-properties-common && sudo add-apt-repository ppa:ondrej/php
      sudo apt update

      Dann kann PHP 7.3 nachinstalliert werden.

      sudo apt-key adv --recv-keys --keyserver hkp:// 0xF1656F24C74CD1D8
      sudo add-apt-repository 'deb [arch=amd64,arm64] bionic main'
      sudo apt update

      Dann kann MariaDB 10.3 installiert werden.

      Ggf. die vorherigen Installationsversuche entfernen und nach einer Bereinigung von vorne beginnen: apt purge apache2* mysql* php* redis* -y
      Ggf. vorab die Daten und die DB sichern:

  2. Siggi.d says:

    Thank you very much for this how-to, I followed it and I have a working nextcloud server! I did just copy and paste, but it would be nice to know what I did there¯\_(ツ)_/¯ Happy New Year! Frohes neues!

  3. Whisht says:

    Hello there.
    I have cofig my sites according your 001-nextcloud.conf and 001-nextcloud-le-ssl.conf. And I have encountered this Problem “HTTP headers do not setting to “X-Frame-Options” 。 But in 001-nextcloud-le-ssl.conf, I have this config line:

    **Header always set X-Frame-Options “SAMEORIGIN”**

    Just same as you.
    It seems a little confused. Thanks for your help~

  4. Inside Void says:

    After a system restart… nothing is loading up…

    I have done a small mistake, instead of changing the database folder to /var/nc_data, i left it as it is(actually forgot to see that) but everything was working fine until i planned for a restart…

    Thank you in advance

  5. Mark Johnson says:

    Awesome tutorial! Just done NextCloud 15 on Ubuntu 18.04 LTS and all went reasonably well. But the admin UI does say:

    Some columns in the database are missing a conversion to big int. Due to the fact that changing column types on big tables could take some time they were not changed automatically. By running ‘occ db:convert-filecache-bigint’ those pending changes could be applied manually. This operation needs to be made while the instance is offline.

    Which is strange because the steps to fix this are in the tutorial under “Optimize your Nextcloud once (a) and regulary (b) using a script” and I did execute them. I manually ran

    sudo -u www-data php /var/www/html/nextcloud/occ db:add-missing-indices
    sudo -u www-data php /var/www/html/nextcloud/occ db:add-missing-indices

    again and they executed without errors but then the warning is still showing in Nextcloud UI.

    The other warning is “The “Referrer-Policy” HTTP header is not set to “no-referrer”, “no-referrer-when-downgrade”, “strict-origin”, “strict-origin-when-cross-origin” or “same-origin”. This can leak referer information. ” but that, too was covered in the tutorial.

    I will spin up a sandbox VPS and start again from top to bottom to see if the sandbox would also keep throwing these warning messages.

    Other than that the tutorial saved a lot of time. It is very comprehensive and unlike others it pays a lot of attention to security. Much better than a sloppy docker or snap install 🙂

    • Please don’t hesitate to contact me (MAIL) directly if these messages will remain on your second server either. Cheers, Carsten

    • Please change /etc/apache2/sites-available/001-nextcloud-le-ssl.conf with regards to the current guide update from today.
      1. Solution for referrer: here.
      2. Solution for database: issue sudo -u www-data php /var/www/html/nextcloud/occ db:convert-filecache-bigint manually again.

  6. Matthias says:

    Hi Carsten, ich habe meine Nextcloud Installation nach deinem Beispiel durchgeführt. Respekt und vielen Dank für die tolle Anleitung. Heute habe ich das Update auf die Version 13.0.2 über die CLI eingespielt. Das einspielen hat ohne Probleme funktioniert. Auch kann ich über meinen Client der auf meinem Notebook läuft meine Daten wieder sauber synchronisieren. Allerdings kann ich die Weboberfläche nicht mehr erreichen. Als Fehlermeldung erschein
    “Forbidden You don’t have permission to access /index.php on this server.”

    Hattest du schon mal ein ähnliches Problem?

  7. dongha28 says:

    When trying to enable php7.2-fpm, a2enmod says it does not exist
    root@ubuntu01:~# a2enmod php7.2-fpm
    ERROR: Module php7.2-fpm does not exist!

    How do I enable php7.2-fpm?

    • First you have to install it as simple as i wrote in the guide:
      apt install libapache2-mod-php7.2 php7.2-cli php7.2-common php7.2-mbstring php7.2-gd php7.2-intl php7.2-xml php7.2-mysql php7.2-zip php7.2-dev php7.2-curl php7.2-fpm php7.2-json php7.2-bz2 php7.2-ldap php-dompdf php-apcu imagemagick php-imagick php-smbclient redis-server php-redis unzip -y
      Then you will be able to disable PHP 7.2 and mpm_prefork and enable php7.2-fpm with mpm_event by issuing
      a2dismod php7.2 && a2dismod mpm_prefork && a2enmod proxy_fcgi setenvif mpm_event && service apache2 restart
      a2enconf php7.2-fpm && service apache2 restart

      • dongha28 says:

        I already have php7.2-fpm installed
        php7.2-fpm is already the newest version (

        But there is no conf OR load file in the /etc/apache2/mods-enabled directory.
        The funny thing is, php7.2-fpm has its own directory at /etc/php/7.2/fpm
        root@ubuntu01:/etc/php/7.2/fpm# ls
        conf.d php-fpm.conf php-fpm.conf.bak php.ini php.ini.bak pool.d

        Will I be ablate enable php7.2-fpm by copying over the php-fpm.conf file to the /mods-enabled/ directory?
        I already executed the previous step ‘a2dismod php7.2 && a2dismod mpm_prefork && a2enmod proxy_fcgi setenvif mpm_event && service apache2 restart’ and everything went ok, including apache2 restart. I keep getting stuck at the php7.2-fpm part.

  8. Michael says:


  9. steffen says:


    Ich habe alles soweit hinbekommen, nun habe ich meine PiDrive Platte von WD eingebunden und diese wird auch in nextcloud angezeigt.
    Das einzige Problem das ich hab ist, ich kann auf die Platte keine Datein hochladen? Was mach ich falsch.

  10. aytac says:

    hello again
    i am following your tutorial it is genius !
    my nextcloud instalation has problem when i try to send test mail it say A problem occurred while sending the email. Please revise your settings. (Error: Connection could not be established with host [ #0])
    do you know how to resolve it ?
    my instalation is on the ubuntu 17.10 and pgsl with php7.2
    thank you for all !

  11. aytac says:

    hello many many thanks for your best tutorial
    i would like to ask you somethings about nextcloud installations
    1) nextcloud web server for the 100 users which is your prefer ? (apache or nginx )
    2) database postgres or Mariadb
    3) is it ok ubuntu 17.10 server ?
    many thanks for your answer

  12. stefano says:

    thank you, you are the best

  13. Claes says:

    I followed your guide and everything i setup and working, except for mounting shares using “SMB / CIFS” under “External storages” in Nextcloud from my file server running Windows…
    How do I configure it?

    • Hi Claes, do you have php-smbclient installed? Check: php -m
      If yes, you may choose it in Nextclouds external storage app as your preferred storage provider and configure the necessary credentials.
      If not please install php-smbclient by issuing
      sudo -s
      apt install php-smbclient -y

      Cheers, Carsten
      Cheers, Carsten

      • Michael Seyfert says:

        Hi Carsten,
        erst einmal ganz herzlichen Dank für diese großartige Anleitung. Nach meinem Update von Xenial auf Bionic kann NC die SMB/CIFS-Freigaben nicht mehr einbinden. Ich habe dann nach deiner Anleitung auf NC15 aktualisiert (mit Ausnahme von MySQL -> Oracle), das Problem bleibt bestehen. php-smbclient ist nach wie vor installiert, die App ‘External Storage’ auch, Benutzer dürfen externen Speicher einbinden und an der config im Benutzer-Backend habe ich nichts geändert, bzw. ich habe einmal die credentials neu eingegeben, um Fehler hierbei auszuschließen.
        Im Protokoll von NC bekomme ich folgende Fehlermeldungen:

        [webdav] Fatal: Sabre\DAV\Exception\ServiceUnavailable: Storage with mount id 1 is not available at <>
        0. /var/www/nextcloud_15.0.0/3rdparty/sabre/dav/lib/DAV/Tree.php line 76
        1. /var/www/nextcloud_15.0.0/3rdparty/sabre/dav/lib/DAV/Server.php line 967
        2. /var/www/nextcloud_15.0.0/3rdparty/sabre/dav/lib/DAV/Server.php line 1666
        getPropertiesIteratorForPath(“files/michael/BSB”, [“{DAV:}resource … “], 1)
        3. /var/www/nextcloud_15.0.0/3rdparty/sabre/dav/lib/DAV/CorePlugin.php line 355
        generateMultiStatus(Generator {}, false)
        4. <>
        httpPropFind(Sabre\HTTP\Reque … “}, Sabre\HTTP\Response {})
        5. /var/www/nextcloud_15.0.0/3rdparty/sabre/event/lib/EventEmitterTrait.php line 105
        call_user_func_array([Sabre\DAV\CorePlugin {},”httpPropFind”], [Sabre\HTTP\Requ … }])
        6. /var/www/nextcloud_15.0.0/3rdparty/sabre/dav/lib/DAV/Server.php line 479
        emit(“method:PROPFIND”, [Sabre\HTTP\Requ … }])
        7. /var/www/nextcloud_15.0.0/3rdparty/sabre/dav/lib/DAV/Server.php line 254
        invokeMethod(Sabre\HTTP\Reque … “}, Sabre\HTTP\Response {})
        8. /var/www/nextcloud_15.0.0/apps/dav/lib/Server.php line 298
        9. /var/www/nextcloud_15.0.0/apps/dav/appinfo/v2/remote.php line 35
        10. /var/www/nextcloud_15.0.0/remote.php line 163
        require_once(“/var/www/nextcl … p”)


        [no app in context] Error: OCP\Files\StorageNotAvailableException: at <>
        0. /var/www/nextcloud_15.0.0/lib/private/Files/Storage/Wrapper/Availability.php line 461
        1. /var/www/nextcloud_15.0.0/lib/private/Files/Storage/Wrapper/Wrapper.php line 582
        2. /var/www/nextcloud_15.0.0/lib/private/Files/Cache/Scanner.php line 112
        3. /var/www/nextcloud_15.0.0/lib/private/Files/Cache/Scanner.php line 150
        4. /var/www/nextcloud_15.0.0/lib/private/Files/Cache/Scanner.php line 336
        scanFile(“”, 3, -1, null, true)
        5. /var/www/nextcloud_15.0.0/lib/private/Files/Utils/Scanner.php line 245
        scan(“”, true, 3)
        6. /var/www/nextcloud_15.0.0/apps/files/lib/Command/Scan.php line 145
        scan(“/michael”, true, null)
        7. /var/www/nextcloud_15.0.0/apps/files/lib/Command/Scan.php line 201
        scanFiles(“michael”, “/michael”, Symfony\Componen … {}, false, true, false)
        8. /var/www/nextcloud_15.0.0/3rdparty/symfony/console/Command/Command.php line 255
        execute(Symfony\Componen … {}, Symfony\Componen … {})
        9. /var/www/nextcloud_15.0.0/core/Command/Base.php line 166
        run(Symfony\Componen … {}, Symfony\Componen … {})
        10. /var/www/nextcloud_15.0.0/3rdparty/symfony/console/Application.php line 946
        run(Symfony\Componen … {}, Symfony\Componen … {})
        11. /var/www/nextcloud_15.0.0/3rdparty/symfony/console/Application.php line 248
        doRunCommand(OCA\Files\Command\Scan {}, Symfony\Componen … {}, Symfony\Componen … {})
        12. /var/www/nextcloud_15.0.0/3rdparty/symfony/console/Application.php line 148
        doRun(Symfony\Componen … {}, Symfony\Componen … {})
        13. /var/www/nextcloud_15.0.0/lib/private/Console/Application.php line 213
        run(Symfony\Componen … {}, Symfony\Componen … {})
        14. /var/www/nextcloud_15.0.0/console.php line 96
        15. /var/www/nextcloud_15.0.0/occ line 11

        Ich habe im web keine weitere Lösung dazu finden können. Hast du noch eine Idee?

        • blockiert hier ufw oder eine andere firewall an der destination? Einfach mal lokal
          ufw status verbose und auch mal php - m
          aufrufen um die Module zu überprüfen.

          Ansonsten bitte auch die nginx logs
          /var/logs/nginx überprüfen.

          Ggf. bitte bei Nextcloud ein Ticket öffnen. Danke.

          • Michael Seyfert says:

            Ach, ufw hatte ich noch gar nicht aktiviert. php -m zeigt mir libsmbclient an.
            Ich habe apache installiert, aus den Fehlermeldungen werde ich auch nicht schlau.
            Dann mache ich mal ein Ticket auf. Trotzdem nochmal vielen Dank!

          • Michael Seyfert says:

            Hallo Carsten, ich habe das Problem wohl eingegrenzt. Wenn ich in der sshd_config PasswordAuthentication auf yes setze, funktioniert zumindest das Einbinden per SFTP (nicht aber SMB/CIFS). Aber das ist ja eine große Sicherheitseinbuße. Mit public oder private key (RSA) habe ich es nicht hinbekommen. Ein Ticket bei Github hatte ich bisher nicht geöffnet. Ich werde mich wieder melden, wenn das Problem gelöst ist.

          • Michael Seyfert says:

            Moin Carsten,
            ich hab’s hinbekommen 🙂 Beim Einbinden des externen Speichers (SMB/CIFS) hatte ich bisher keine Domain eingetragen (nur ‘Host’, ‘Share’, ‘Benutzer’ und ‘Passwort’ sind obligatorisch). Dies ist aber offenkundig nach dem Update auf Ubuntu Bionic notwendig geworden.
            Danke, danke noch einmal!!

  14. ErAzOr says:

    Hi Carsten. Vielen Dank für die Anleitung.

    Haben mal ne generelle Frage zu Apache:
    Nginx bietet ja das Modul ngx_cache_purge, welches die Generierung von Thumbnails beschleunigen soll.
    Gibt es analog dazu auch ein entsprechendes Modul für Apache? Oder ist es mit Apache nicht erforderlich, da entsprechende Funktion bereits Bestandteil ist?.
    Grüße ErAzOr

    • Vielen Dank! Ein explizites Modul ist mir nicht bekannt – ich bin auf diesem Gebiet leider noch “blank”. Über Informationen dazu wäre ich dankbar 😉 Viele Grüße, Casten

  15. Nextclouder says:

    Thanks for the fast response and update, I delete 000-default in sites-enabled and default-ssl in sites-available, the only file left is /etc/apache2/sites-available/001-nextcloud.conf which has my, the domain is working, I get the Apache2 welcome page on port 80.

    Certbot is unhappy and doesn’t pick up the vhost in /etc/apache2/sites-available/001-nextcloud.conf:

    # certbot –apache
    Saving debug log to /var/log/letsencrypt/letsencrypt.log
    Plugins selected: Authenticator apache, Installer apache
    No names were found in your configuration files. Please enter in your domain
    name(s) (comma and/or space separated) (Enter ‘c’ to cancel):

    This is my 001-nextcloud.conf:


    DocumentRoot /var/www/html/nextcloud

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    Thanks again for your fantastic blog, just trying to follow along and running in little hiccups ..

    • Hi, did you change the vhost (001-nextcloud.conf) properly? LE would pick up the ServerName from the vhost – this is definitivley wrong: ServerName
      You have to substitute the hostname and mail: to e.g. to e.g.

      assuming your dyndns would be “”.

      Certbot is unhappy and doesn’t pick up the vhost in /etc/apache2/sites-available/001-nextcloud.conf:
      You have to create a link (e.g. ln -s) or a2ensite 001-nextcloud.conf first. Apache2 won’t use vhosts in sites-available.
      Cheers, Carsten

  16. Nextclouder says:

    I made it to “certbot –apache” then I get the error apache2: Syntax error on line 225 of /etc/apache2/apache2.conf: Could not open configuration file /etc/apache2/sites-enabled/000-default.conf: No such file or directory

    Do we first need to enabled the 001-nextcloud.conf from sites-available to the sites-enabled folder? Also is it possible that the apache2 package is missing in the apt install commands above? I had to manually install it in addition to copy & pasting ..

    • Hi.
      No, it isn’t missised, it will be installed by issuing “libapache2-mod-php7.2” …
      Please remove the defaults vhosts:
      rm /etc/apache2/sites-available/000-default.conf
      rm /etc/apache2/sites-enabled/000-default.conf
      service apache2 restart

      and before issuing certbot aou have to a2ensite 000-nextcloud.conf.
      Thank you very much for your feedback and your hint! I already updated the guide Cheers, Carsten

Leave a Reply

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