Nextcloud 18 installation guide (Ubuntu 20.04/18.04)

Ubuntu 18.04 / NGINX 1.17 / MariaDB 10 (AMD64)

Following this guide you will be able to install and configure Nextcloud 18 latest based on Ubuntu 18.04.x LTS 64Bit (ARM64 anor AMD64), NGINX 1.17, TLSv1.3, PHP 7.4, MariaDB 10.4, Redis, UFW and fail2ban. You will achieve an A+ rating from both, Nextcloud and Qualys SSL Labs. We will request and implement your ssl certificate(s) from Let’s Encrypt – you only have to ammend all the red marked values like, 192.168.2.x with regards to your environment!

Find the entire update history here.

Table of content

  1. Prepare your server and install nginx
  2. PHP 7.4
  3. MariaDB 10.5
  4. Redis-server
  5. Nextcloud (SSL enabled, A+)
  6. Hardenings (fail2ban and ufw)

1. Prepare your server

Change into sudo mode

sudo -s

Prepare your server for the installation itself:

apt install curl gnupg2 git lsb-release ssl-cert ca-certificates apt-transport-https tree locate software-properties-common dirmngr screen htop net-tools zip unzip curl ffmpeg ghostscript libfile-fcntllock-perl -y

Add new software repositories

cd /etc/apt/sources.list.d
echo "deb [arch=amd64] $(lsb_release -cs) nginx" | tee nginx.list
echo "deb [arch=amd64] $(lsb_release -cs) main" | tee php.list
echo "deb [arch=amd64] $(lsb_release -cs) main" | tee mariadb.list

Download the required keys to trust all the new sources:

curl -fsSL | sudo apt-key add -
apt-key adv --recv-keys --keyserver hkps:// 4F4EA0AAE5267A6C
apt-key adv --recv-keys --keyserver hkps:// 0xF1656F24C74CD1D8

Update your server and generate self signed certificates:

apt update && apt upgrade -y
make-ssl-cert generate-default-snakeoil -y

Remove old nginx software if exists:

apt remove nginx nginx-extras nginx-common nginx-full -y --allow-change-held-packages

Install and configure NGINX

First ensure Apache(2) isn’t running otherwise NGINX won’t start because the required port (:80) would be in use by Apache(2):

systemctl stop apache2.service && systemctl disable apache2.service
apt install nginx -y
systemctl enable nginx.service

Change the default nginx configuration:

mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak && touch /etc/nginx/nginx.conf
nano /etc/nginx/nginx.conf

Paste all the following rows to the new file. Substitute the red marked parameters properly:

user www-data;
worker_processes auto;
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.4-fpm.sock;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log warn;
# please customize the ip-range properly
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;
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 valid=30s;
#resolver valid=30s; *is recommended but requires a valid DNS configuration*
resolver_timeout 5s;
include /etc/nginx/conf.d/*.conf;

Test and restart the webserver

nginx -t && service nginx restart

Create four folders and apply the appropriate permissions:

mkdir -p /var/nc_data /var/www/letsencrypt
chown -R www-data:www-data /var/nc_data /var/www

The preparation and installation of nginx has finished and we will install PHP latest in the next chapter.

2. Install and configure PHP 7.4 (fpm)

The PHP repository was enabled in chapter 1 – so just perform the following statement to install PHP as needed by and recommended for Nextcloud:

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

Awesome, PHP 7.4 is already installed. Verify your timezone settings :


If it is not set properly customize it as examplarily shown for Germany:

timedatectl set-timezone Europe/Berlin

Backup and then tweak PHP for optimization and security reasons:

cp /etc/php/7.4/fpm/pool.d/www.conf /etc/php/7.4/fpm/pool.d/www.conf.bak
cp /etc/php/7.4/cli/php.ini /etc/php/7.4/cli/php.ini.bak
cp /etc/php/7.4/fpm/php.ini /etc/php/7.4/fpm/php.ini.bak
cp /etc/php/7.4/fpm/php-fpm.conf /etc/php/7.4/fpm/php-fpm.conf.bak
cp /etc/ImageMagick-6/policy.xml /etc/ImageMagick-6/policy.xml.bak
sed -i "s/;env\[HOSTNAME\] = /env[HOSTNAME] = /" /etc/php/7.4/fpm/pool.d/www.conf
sed -i "s/;env\[TMP\] = /env[TMP] = /" /etc/php/7.4/fpm/pool.d/www.conf
sed -i "s/;env\[TMPDIR\] = /env[TMPDIR] = /" /etc/php/7.4/fpm/pool.d/www.conf
sed -i "s/;env\[TEMP\] = /env[TEMP] = /" /etc/php/7.4/fpm/pool.d/www.conf
sed -i "s/;env\[PATH\] = /env[PATH] = /" /etc/php/7.4/fpm/pool.d/www.conf
sed -i "s/output_buffering =.*/output_buffering = 'Off'/" /etc/php/7.4/cli/php.ini
sed -i "s/max_execution_time =.*/max_execution_time = 3600/" /etc/php/7.4/cli/php.ini
sed -i "s/max_input_time =.*/max_input_time = 3600/" /etc/php/7.4/cli/php.ini
sed -i "s/post_max_size =.*/post_max_size = 10240M/" /etc/php/7.4/cli/php.ini
sed -i "s/upload_max_filesize =.*/upload_max_filesize = 10240M/" /etc/php/7.4/cli/php.ini
sed -i "s/;date.timezone.*/date.timezone = Europe\/\Berlin/" /etc/php/7.4/cli/php.ini
sed -i "s/memory_limit = 128M/memory_limit = 1024M/" /etc/php/7.4/fpm/php.ini
sed -i "s/output_buffering =.*/output_buffering = 'Off'/" /etc/php/7.4/fpm/php.ini
sed -i "s/max_execution_time =.*/max_execution_time = 3600/" /etc/php/7.4/fpm/php.ini
sed -i "s/max_input_time =.*/max_input_time = 3600/" /etc/php/7.4/fpm/php.ini
sed -i "s/post_max_size =.*/post_max_size = 10240M/" /etc/php/7.4/fpm/php.ini
sed -i "s/upload_max_filesize =.*/upload_max_filesize = 10240M/" /etc/php/7.4/fpm/php.ini
sed -i "s/;date.timezone.*/date.timezone = Europe\/\Berlin/" /etc/php/7.4/fpm/php.ini
sed -i "s/;session.cookie_secure.*/session.cookie_secure = True/" /etc/php/7.4/fpm/php.ini
sed -i "s/;opcache.enable=.*/opcache.enable=1/" /etc/php/7.4/fpm/php.ini
sed -i "s/;opcache.enable_cli=.*/opcache.enable_cli=1/" /etc/php/7.4/fpm/php.ini
sed -i "s/;opcache.memory_consumption=.*/opcache.memory_consumption=128/" /etc/php/7.4/fpm/php.ini
sed -i "s/;opcache.interned_strings_buffer=.*/opcache.interned_strings_buffer=8/" /etc/php/7.4/fpm/php.ini
sed -i "s/;opcache.max_accelerated_files=.*/opcache.max_accelerated_files=10000/" /etc/php/7.4/fpm/php.ini
sed -i "s/;opcache.revalidate_freq=.*/opcache.revalidate_freq=1/" /etc/php/7.4/fpm/php.ini
sed -i "s/;opcache.save_comments=.*/opcache.save_comments=1/" /etc/php/7.4/fpm/php.ini
sed -i '$aapc.enable_cli=1' /etc/php/7.4/mods-available/apcu.ini
sed -i "s/rights=\"none\" pattern=\"PS\"/rights=\"read|write\" pattern=\"PS\"/" /etc/ImageMagick-6/policy.xml
sed -i "s/rights=\"none\" pattern=\"EPI\"/rights=\"read|write\" pattern=\"EPI\"/" /etc/ImageMagick-6/policy.xml
sed -i "s/rights=\"none\" pattern=\"PDF\"/rights=\"read|write\" pattern=\"PDF\"/" /etc/ImageMagick-6/policy.xml
sed -i "s/rights=\"none\" pattern=\"XPS\"/rights=\"read|write\" pattern=\"XPS\"/" /etc/ImageMagick-6/policy.xml

Restart both services, php and nginx:

service php7.4-fpm restart
service nginx restart

PHP was successfully installed and configured – we will go ahead with the installation of MariaDB.

3. Install, harden and configure MariaDB 10.5

Install MariaDB by issuing the following statement:

apt update && apt install mariadb-server -y

How to upgrade from MariaDB v. 10.4 to v. 10.5

Verify your database server version:

mysql --version

Harden and secure your MariaDB by issuing:

Switch to unix_socket authentication [Y/n] N
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

With regards to Nextcloud we optimize the configuration of MariaDB:

service mysql stop
mv /etc/mysql/my.cnf /etc/mysql/my.cnf.bak
nano /etc/mysql/my.cnf

Paste all the following rows:

 default-character-set = utf8mb4
 port = 3306
 socket = /var/run/mysqld/mysqld.sock
 log_error = /var/log/mysql/mysql_error.log
 nice = 0
 socket = /var/run/mysqld/mysqld.sock
 basedir = /usr
 bind-address =
 binlog_format = ROW
 bulk_insert_buffer_size = 16M
 character-set-server = utf8mb4
 collation-server = utf8mb4_general_ci
 concurrent_insert = 2
 connect_timeout = 5
 datadir = /var/lib/mysql
 default_storage_engine = InnoDB
 expire_logs_days = 7
 general_log_file = /var/log/mysql/mysql.log
 general_log = 0
 innodb_buffer_pool_size = 1024M
 innodb_buffer_pool_instances = 1
 innodb_flush_log_at_trx_commit = 2
 innodb_log_buffer_size = 32M
 innodb_max_dirty_pages_pct = 90
 innodb_file_per_table = 1
 innodb_open_files = 400
 innodb_io_capacity = 4000
 innodb_flush_method = O_DIRECT
 key_buffer_size = 128M
 lc_messages_dir = /usr/share/mysql
 lc_messages = en_US
 log_bin = /var/log/mysql/mariadb-bin
 log_bin_index = /var/log/mysql/mariadb-bin.index
 log_error = /var/log/mysql/mysql_error.log
 log_slow_verbosity = query_plan
 log_warnings = 2
 long_query_time = 1
 max_allowed_packet = 16M
 max_binlog_size = 100M
 max_connections = 200
 max_heap_table_size = 64M
 myisam_recover_options = BACKUP
 myisam_sort_buffer_size = 512M
 port = 3306
 pid-file = /var/run/mysqld/
 query_cache_limit = 2M
 query_cache_size = 64M
 query_cache_type = 1
 query_cache_min_res_unit = 2k
 read_buffer_size = 2M
 read_rnd_buffer_size = 1M
 slow_query_log_file = /var/log/mysql/mariadb-slow.log
 slow-query-log = 1
 socket = /var/run/mysqld/mysqld.sock
 sort_buffer_size = 4M
 table_open_cache = 400
 thread_cache_size = 128
 tmp_table_size = 64M
 tmpdir = /tmp
 transaction_isolation = READ-COMMITTED
 user = mysql
 wait_timeout = 600
 max_allowed_packet = 16M
 key_buffer = 16M 

Restart MariaDB and connect to MariaDB:

service mysql restart
mysql -uroot -p


  • the database nextcloud
  • the user nextcloud
  • and its password (nextcloud):
CREATE DATABASE nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER nextcloud@localhost identified by 'nextcloud'; GRANT ALL PRIVILEGES on nextcloud.* to nextcloud@localhost; FLUSH privileges; quit;

Verify the transaction isolation level is set to READ_Commit and the collation is 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'"

The resultset should consist of “READ-COMMITTED” and “utf8mb4_general_ci” … go ahead with the installation of the redis-server.

4. Install and configure Redis

Install the redis-server to optimize Nextclouds performance and to minimize the load on the database:

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

Change the redis configuration and set the group membership properly:

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 -aG redis www-data
cp /etc/sysctl.conf /etc/sysctl.conf.bak
sed -i '$avm.overcommit_memory = 1' /etc/sysctl.conf

Now reboot your server once:

reboot now

We are now ready to install Nextcloud.

5. Prepare NGINX for Nextcloud (create all vhosts)

First create all the configuration and webhost files (aka vhost). Change into sudo mode and create the /etc/nginx/conf.d/nextcloud.conf (vhost):

sudo -s
[ -f /etc/nginx/conf.d/default.conf ] && mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak
touch /etc/nginx/conf.d/default.conf
nano /etc/nginx/conf.d/nextcloud.conf

Paste all the following rows and customize the red marked parameters:

server {
listen 80 default_server;
listen [::]:80 default_server;
location ^~ /.well-known/acme-challenge {
proxy_set_header Host $host;
location / {
return 301 https://$host$request_uri;
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
root /var/www/nextcloud/;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
location = /.well-known/carddav {
return 301 $scheme://$host/remote.php/dav;
location = /.well-known/caldav {
return 301 $scheme://$host/remote.php/dav;
#SOCIAL app enabled? Please uncomment the following row
#rewrite ^/.well-known/webfinger /public.php?service=webfinger last;
#WEBFINGER app enabled? Please uncomment the following two rows.
#rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
#rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;
client_max_body_size 10240M;
location / {
rewrite ^ /index.php;
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
deny all;
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
location ^~ /apps/rainloop/app/data {
deny all;
location ~ \.(?:flv|mp4|mov|m4a)$ {
mp4_buffer_size 100M;
mp4_max_buffer_size 1024M;
fastcgi_split_path_info ^(.+?.php)(\/.*|)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name =404;
include fastcgi_params;
include php_optimization.conf;
location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+).php(?:$|\/) {
fastcgi_split_path_info ^(.+?.php)(\/.*|)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name =404;
include fastcgi_params;
include php_optimization.conf;
location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
try_files $uri/ =404;
index index.php;
location ~ \.(?:css|js|woff2?|svg|gif|map|png|html|ttf|ico|jpg|jpeg)$ {
try_files $uri /index.php$request_uri;
access_log off;
expires 360d;

Create the letsencrypt.conf (vhost):

nano /etc/nginx/conf.d/letsencrypt.conf

Paste all the following rows:

listen default_server;
charset utf-8;
location ^~ /.well-known/acme-challenge
default_type text/plain;
root /var/www/letsencrypt;

Create the ssl.conf:

nano /etc/nginx/ssl.conf

Paste all 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/rsa-certs/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/rsa-certs/privkey.pem;
#ssl_certificate /etc/letsencrypt/ecc-certs/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/ecc-certs/privkey.pem;
#ssl_trusted_certificate /etc/letsencrypt/ecc-certs/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.3 TLSv1.2;
ssl_ecdh_curve X448:secp521r1:secp384r1:prime256v1;
ssl_prefer_server_ciphers on;
ssl_stapling on;
ssl_stapling_verify on;

Create the proxy.conf :

nano /etc/nginx/proxy.conf

Paste all 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:

nano /etc/nginx/header.conf

Paste the following rows:

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

Create the optimization.conf:

nano /etc/nginx/optimization.conf

Paste all the following rows:

fastcgi_hide_header X-Powered-By;
fastcgi_read_timeout 3600;
fastcgi_send_timeout 3600;
fastcgi_connect_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/ 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:

nano /etc/nginx/php_optimization.conf

Paste all the following rows:

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $path_info;
fastcgi_param HTTPS on;
fastcgi_param modHeadersAvailable true;
fastcgi_param front_controller_active true;
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
fastcgi_cache_valid 404 1m;
fastcgi_cache_valid any 1h;
fastcgi_cache_methods GET HEAD;

To enhance the security just create your own dhparam.pem:

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

Please be patient, it will take a while depending on your hardware. If your dhparam.pem exists please customize and restart your webserver:

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

Download and extract the Nextcloud software, then request your SSL certificates from Let’s Encrypt using acme:

cd /usr/local/src
tar -xjf latest.tar.bz2 -C /var/www && chown -R www-data:www-data /var/www/ && rm -f latest.tar.bz2

Create a technical user to install and renew your ssl certificates

adduser acmeuser
usermod -a -G www-data acmeuser

To request ssl certificates from letsencrypt just install acme and request your ssl-certificate(s):

su - acmeuser
curl | sh

Create three folders to request and store your ssl certificates to (substitute

mkdir -p /var/www/letsencrypt/.well-known/acme-challenge /etc/letsencrypt/rsa-certs /etc/letsencrypt/ecc-certs
chmod -R 775 /var/www/letsencrypt /etc/letsencrypt && chown -R www-data:www-data /var/www/ /etc/letsencrypt
su - acmeuser --issue -d --keylength 4096 -w /var/www/letsencrypt --key-file /etc/letsencrypt/rsa-certs/privkey.pem --ca-file /etc/letsencrypt/rsa-certs/chain.pem --cert-file /etc/letsencrypt/rsa-certs/cert.pem --fullchain-file /etc/letsencrypt/rsa-certs/fullchain.pem --issue -d --keylength ec-384 -w /var/www/letsencrypt --key-file /etc/letsencrypt/ecc-certs/privkey.pem --ca-file /etc/letsencrypt/ecc-certs/chain.pem --cert-file /etc/letsencrypt/ecc-certs/cert.pem --fullchain-file /etc/letsencrypt/ecc-certs/fullchain.pem

Apply the appropiate permissions using a script:

vi /root/

Paste all the following rows:

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

Mark the script as executable and issue it:

chmod +x /root/

Remove the links to your self signed certificates and restart nginx:

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

From now your webserver interacts withs your ssl certificates from let’s encrypt. Go ahead and install your Nextcloud software silently by issuing the following statement:

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


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

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

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

–admin-user “YourNextcloudAdmin” : your free choice

–admin-pass “YourNextcloudAdminPasssword” : your free choice

Wait for the installation and finally make amendments to your Nextcloud ‘config.php’ as the webuser www-data:

1. Set your trusted domain:

sudo -u www-data php /var/www/nextcloud/occ config:system:set trusted_domains 0

2. Set your domain as overwrite.cli.url:

sudo -u www-data php /var/www/nextcloud/occ config:system:set overwrite.cli.url --value=

Enhance your Nextcloud configuration – back up the current config.php and issue the statements below:

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

Expand your Nextcloud config.php:

sudo -u www-data sed -i 's/^[ ]*//' /var/www/nextcloud/config/config.php
sudo -u www-data sed -i '/);/d' /var/www/nextcloud/config/config.php
sudo -u www-data cat <<EOF >>/var/www/nextcloud/config/config.php
'activity_expire_days' => 14,
'' => 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',
sudo -u www-data sed -i "s/.*dbhost.*/\'dbhost\' \=\>\ \'localhost\:\/var\/run\/mysqld\/mysqld\.sock\'\,/g" /var/www/nextcloud/config/config.php

Edit Nextclouds file ‘.user.ini’ and adjust some Nextcloud apps as user www-data:

sudo -u www-data sed -i "s/output_buffering=.*/output_buffering='Off'/" /var/www/nextcloud/.user.ini
sudo -u www-data php /var/www/nextcloud/occ app:disable survey_client
sudo -u www-data php /var/www/nextcloud/occ app:disable firstrunwizard
sudo -u www-data php /var/www/nextcloud/occ app:enable admin_audit
sudo -u www-data php /var/www/nextcloud/occ app:enable files_pdfviewer

Your Nextcloud is now installed, optimized and secured – finally restart all relevant services:

service nginx stop
service php7.4-fpm stop
service mysql restart
service php7.4-fpm restart
service redis-server restart
service nginx restart

Add a Nextcloud cronjob for www-data:

crontab -u www-data -e

Paste the following rows:

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

Switch from Ajax to Cron using Nextclouds cli:

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

6. Hardenings (fail2ban and ufw)

First install and configure fail2ban to harden your server:

apt update && apt install fail2ban -y

Paste all the following rows to the fail2ban filter for Nextcloud (download here):

nano /etc/fail2ban/filter.d/nextcloud.conf
failregex=^{"reqId":".*","remoteAddr":".*","app":"core","message":"Login failed: '.*' \(Remote IP: '<HOST>'\)","level":2,"time":".*"}$
^{"reqId":".*","level":2,"time":".*","remoteAddr":".*","user,:".*","app":"no app in context".*","method":".*","message":"Login failed: '.*' \(Remote IP: '<HOST>'\)".*}$
^{"reqId":".*","level":2,"time":".*","remoteAddr":".*","user":".*","app":".*","method":".*","url":".*","message":"Login failed: .* \(Remote IP: <HOST>\).*}$

Create a new jail file (download here):

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

Paste all the following rows:

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

enabled = true

Restart the fail2ban-service and verify the fail2ban-status:

service fail2ban restart
fail2ban-client status nextcloud

At least we will install and customize the ufw (uncomplicated firewall):

Before issuing the following statement verify the used ports. If e.g. SSH operates on a different port than 22 you won’t be able to connect via ssh anymore – please customize the ports if necessary!

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

Set the firewall logging to medium and deny non defined incoming connections. Finally enable and restart ufw by issuing the last statement:

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

Enjoy your personal data in your secured and hardened Nextcloud! If you are interested in operating more web applications don’t hesitate to read the guide: Roundcube, WordPress, Shellinabox and Pi-hole behind a NGINX reverse proxy.

Don’t forget to backup your Nextcloud

Find more instructions here: Nextcloud backup and restore

My twins, my wife and me do really appreciate any donation!
My twins, my wife and me do really appreciate any donation!