Skip to content

About Nextcloud

Nextcloud is a suite of client-server software for creating and using file hosting services. It is functionally similar to Dropbox, although Nextcloud is free and open-source, allowing anyone to install and operate it on a private server.

In contrast to proprietary services like Dropbox, the open architecture allows adding functionality to the server in the form of applications and enables users to have full control of their data.

Installation

Before to start, we update our system on the last version of these packages.

apt update && apt full-upgrade

Prerequisites

First step we install all depedencies needed by nextcloud.

apt install nginx php-common php-fpm php-gd php-imagick php-intl php-mbstring php-mcrypt php-mysql php-xml php-zip php7.0-curl php-redis mariadb-client mariadb-server
certbot nginx

Set up a database for nextcloud.

create database mycloud;
create user "$user"@"localhost" identified by "$pass";
grant all privileges on mycloud.* to "$user"@"localhost";
flush privileges;

Set up nginx

Before configuring your nginx server, you must create your SSL certificate by following this procedure let's encrypt.

When it's done we edit /etc/nginx/sites-enabled/your.domain.com to configure nginx.

upstream php-handler {
    server unix:/run/php/php7.0-fpm.sock;
}

server {
    listen 80;
    server_name you.domain.com;
    # enforce https
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name you.domain.com;

    # Use Mozilla's guidelines for SSL/TLS settings
    # https://mozilla.github.io/server-side-tls/ssl-config-generator/
    # NOTE: some settings below might be redundant
    ssl_certificate /etc/letsencrypt/live/you.domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/you.domain.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/you.domain.com/chain.pem;
    ssl_dhparam /etc/nginx/dhparam.pem;
    ssl_protocols TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
    ssl_session_timeout 50m;
    ssl_session_cache shared:SSL:40m;
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 1.1.1.1 1.0.0.1;
    resolver_timeout 5s;

    # Add headers to serve security related headers
    # Before enabling Strict-Transport-Security headers please read into this
    # topic first.
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
    #
    # WARNING: Only add the preload option once you read about
    # the consequences in https://hstspreload.org/. This option
    # will add the domain to a hardcoded list that is shipped
    # in all major browsers and getting removed from this list
    # could take several months.
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Robots-Tag none;
    add_header X-Download-Options noopen;
    add_header X-Permitted-Cross-Domain-Policies none;
    add_header Referrer-Policy no-referrer;

    # Remove X-Powered-By, which is an information leak
    fastcgi_hide_header X-Powered-By;

    # Path to the root of your installation
    root /var/www/you.domain.com/;

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    # The following 2 rules are only needed for the user_webfinger app.
    # Uncomment it if you're planning to use this app.
    #rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
    #rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json
    # last;

    location = /.well-known/carddav {
      return 301 $scheme://$host/remote.php/dav;
    }
    location = /.well-known/caldav {
      return 301 $scheme://$host/remote.php/dav;
    }

    # set max upload size
    client_max_body_size 512M;
    fastcgi_buffers 64 4K;

    # Enable gzip but do not remove ETag headers
    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;

    # Uncomment if your server is build with the ngx_pagespeed module
    # This module is currently not supported.
    #pagespeed off;

    location / {
        rewrite ^ /index.php$request_uri;
    }

    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
        deny all;
    }
    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
        deny all;
    }

    location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
        #root /var/www/you.domain.com/;
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param HTTPS on;
        #Avoid sending the security headers twice
        fastcgi_param modHeadersAvailable true;
        fastcgi_param front_controller_active true;
        fastcgi_pass php-handler;
        fastcgi_intercept_errors on;
        fastcgi_request_buffering off;
    }

    location ~ ^/(?:updater|ocs-provider)(?:$|/) {
        try_files $uri/ =404;
        index index.php;
    }

    # Adding the cache control header for js and css files
    # Make sure it is BELOW the PHP block
    location ~ \.(?:css|js|woff2?|svg|gif)$ {
        try_files $uri /index.php$request_uri;
        add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
        # Add headers to serve security related headers (It is intended to
        # have those duplicated to the ones above)
        # Before enabling Strict-Transport-Security headers please read into
        # this topic first.
        # add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
        #
        # WARNING: Only add the preload option once you read about
        # the consequences in https://hstspreload.org/. This option
        # will add the domain to a hardcoded list that is shipped
        # in all major browsers and getting removed from this list
        # could take several months.
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Robots-Tag none;
        add_header X-Download-Options noopen;
        add_header X-Permitted-Cross-Domain-Policies none;
        add_header Referrer-Policy no-referrer;

        # Optional: Don't log access to assets
        access_log off;
    }

    location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ {
        try_files $uri /index.php$request_uri;
        # Optional: Don't log access to other assets
        access_log off;
    }
}

Get the installer

Get the tarball of the actual nextcloud version.

wget https://download.nextcloud.com/server/releases/nextcloud-14.0.4.zip

Uncompress and copy the instaler into the web directory.

unzip nextcloud-14.0.4.zip

cp -r nextcloud/* /var/www/html/

We fix the permissions.

chown -R www-data:www-data /var/www/html

We'll restart nginx , open your nextcloud url into your web navigator and follow the steps to install it.

Fine tuning

For php

Uncomment the environment and log files related lines in /etc/php/7.0/fpm/pool.d/www.conf.

access.log = /var/log/$pool.access.log

env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp

Adjust the numbers of procces started by php-fpm.

pm = dynamic
pm.max_children = 120
pm.start_servers = 12
pm.min_spare_servers = 6
pm.max_spare_servers = 18

Add the following content in /etc/php/7.0/mods-available/pdo_mysql.ini.

[mysql]
mysql.allow_local_infile=On
mysql.allow_persistent=On
mysql.cache_size=2000
mysql.max_persistent=-1
mysql.max_links=-1
mysql.connect_timeout=60
mysql.trace_mode=Off

Memory caching

You can significantly improve your Nextcloud server performance with memory caching, where frequently-requested objects are stored in memory for faster retrieval.

There are two types of caches to use: a PHP opcode cache, which is commonly called opcache, and data caching for your Web server.

If you do not install and enable a local memcache you will see a warning on your Nextcloud admin page. A memcache is not required and you may safely ignore the warning if you prefer.

To install the apcu module & redis server follow these steps.

apt install php-apcu redis-server

We must set up opcache in /etc/php/7.0/fpm/php.ini.

opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.revalidate_freq=1
opcache.save_comments=1

Note

If opcache not working, copy the properties aftermentioned into /etc/php/7.0/mods-available/opcache.ini.

Configure memory caching in the config.php of your nextcloud.

'memcache.locking' => '\OC\Memcache\Redis',
'memcache.local' => '\OC\Memcache\APCu',
'redis' => array(
     'host' => 'localhost',
     'port' => 6379,
      ),

Defining background jobs

A system like Nextcloud sometimes requires tasks to be done on a regular basis without the need for user interaction or hindering Nextcloud performance. For that purpose, as a system administrator, you can define background jobs (for example, database clean-ups) which are executed without any need for user interaction.

These jobs are typically referred to as cron jobs. Cron jobs are commands or shell-based scripts that are scheduled to run periodically at fixed times, dates, or intervals. cron.php is an Nextcloud internal process that runs such background jobs on demand.

Nextcloud apps register actions with cron.php automatically to take care of typical housekeeping operations, such as garbage collecting of temporary files or checking for newly updated files using filescan() for externally mounted file systems.

So we adapt the behavior of NC by following these steps.

crontab -u www-data -e

And add the following line

*/15 * * * * php -f /var/www/html/cron.php

To verify if cronjob works

crontab -u www-data -l

Configure nextcloud log level in config.php.

'log_type' => 'owncloud',
'log_file' => 'nextcloud.log',
'loglevel' => '3',
'logdateformat' => 'F d, Y H:i:s',

MySQL

To improve performance we adapt the settings of our mysql server in /etc/mysql/mariadb.conf.d/50-server.cnf.

# this is only for the mysqld standalone daemon
[mysqld]

#
# * Basic Settings
#
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
skip-external-locking

# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address        = 127.0.0.1

#
# * Fine Tuning
#
key_buffer_size     = 128M
max_allowed_packet  = 16M
thread_stack        = 256K
thread_cache_size       = 20
# This replaces the startup script and checks MyISAM tables if needed
# the first time they are touched
myisam_recover_options  = BACKUP
max_connections        = 250
table_cache            = 64
thread_concurrency     = 10

#
# * Query Cache Configuration
#
query_cache_limit   = 64M
query_cache_size        = 128M
##
query_cache_type = 1
query_cache_min_res_unit = 2k
tmp_table_size= 64M
max_heap_table_size= 64M
#
# * Logging and Replication
#
# Both location gets rotated by the cronjob.
# Be aware that this log type is a performance killer.
# As of 5.1 you can enable the log at runtime!
#general_log_file        = /var/log/mysql/mysql.log
#general_log             = 1
#
# Error log - should be very few entries.
#
log_error = /var/log/mysql/error.log
#
# Enable the slow query log to see queries with especially long duration
#slow_query_log_file    = /var/log/mysql/mariadb-slow.log
#long_query_time = 10
#log_slow_rate_limit    = 1000
#log_slow_verbosity = query_plan
#log-queries-not-using-indexes
#
# The following can be used as easy to replay backup logs or for replication.
# note: if you are setting up a replication slave, see README.Debian about
#       other settings you may need to change.
#server-id      = 1
#log_bin        = /var/log/mysql/mysql-bin.log
expire_logs_days    = 10
max_binlog_size   = 100M
#binlog_do_db   = include_database_name
#binlog_ignore_db   = exclude_database_name

#
# * InnoDB
#
# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/.
# Read the manual for more InnoDB related options. There are many!
innodb_buffer_pool_size = 1G
innodb_log_buffer_size = 256
innodb_flush_method = O_DIRECT
innodb_flush_log_at_trx_commit=2
innodb_buffer_pool_instances = 1
##
innodb_max_dirty_pages_pct = 90
innodb_large_prefix=on
innodb_file_format=barracuda
innodb_file_per_table = 1
innodb_buffer_pool_instances = 1
#
# * Security Features
#
# Read the manual, too, if you want chroot!
# chroot = /var/lib/mysql/
#
# For generating SSL certificates you can use for example the GUI tool "tinyca".
#
# ssl-ca=/etc/mysql/cacert.pem
# ssl-cert=/etc/mysql/server-cert.pem
# ssl-key=/etc/mysql/server-key.pem
#
# Accept only connections using the latest and most secure TLS protocol version.
# ..when MariaDB is compiled with OpenSSL:
# ssl-cipher=TLSv1.2
# ..when MariaDB is compiled with YaSSL (default in Debian):
# ssl=on

#
# * Character sets
#
# MySQL/MariaDB default is Latin1, but in Debian we rather default to the full
# utf8 4-byte character set. See also client.cnf
#
character-set-server  = utf8mb4
collation-server      = utf8mb4_general_ci

If you want to go far you can visit the official documentation of nextcloud here.