Your private "cloud" with Nextcloud
view this post on our onion site
10 min read

Your private "cloud" with Nextcloud

Your private "cloud" with Nextcloud
This is an English translation from @j4imefoo's original Spanish article on @estudiobitcoin:

If you find this post helpful consider sending Jaime some sats:


Today we all have a mobile phone in our pocket. This phone is synchronized with the so-called “cloud” thanks to which your data is conveniently shared with all the devices connected to the same account. This gives us a lot of comfort by being able to see each change reflected on all our screens at the same time and being able to access our data from anywhere.

But unfortunately, we know that this "cloud" is nothing more than "someone else's computer".

Why should we entrust our calendars, contacts, photos and personal documents to someone who is not ourselves, who does not even have our interests in mind and for whom we are even one more product? You're right, we shouldn't.

What would you think if I told you that there is a solution today that allows us to manage our personal information in the same way that we would through the "cloud"?

We are very lucky to have a product that has all the features we need, with a long track record and is also free and open source software. I present to you Nextcloud.

What do we need

Being all the software that we will use free, we will focus first on the hardware.

Where do you want to install it? What use will you give? How many users? What response time do you need? How much fault tolerance for availability? These will be some of the questions you should ask yourself before deciding where you are going to install your Nextcloud instance. Here are some examples to help guide you in your decision:

  1. I'm interested in an installation to tinker with. I don't want to dedicate more hardware than a raspberry that I have at home. I will use Nextcloud to share important documents and photos with the family, inside the house.
  2. I want to use it continuously with my family, friends, or employees of my small business. We will have shared calendars and contacts synced continuously. We will make use of the sharing of files, photos and even collaborate online in the creation of documents.

If you already know which of the situations you identify with, you already know more or less what to expect in terms of hardware.

In the case of having it at home we will use a Raspberry PI or computer that we can leave on and in case we want to have it away from home for reasons of connectivity or resources, we can use any of the hosting services that exist on the market. I might recommend host4coins, Digital Ocean or Linode.

System Preparation

Nextcloud does not require a lot of resources, but at least 1GB of RAM would be recommended. Since one of its uses will be to store files and photos, we will also need some hard drive capacity.

If we are going to use it and it is not just about tinkering, it would also be convenient to register a domain name that points to our IP. In the case of wanting to install it at home without having a fixed IP, there are a wide variety of companies on the Internet that offer dynamic DNS. In our case, we select

To start, we will connect to our server by ssh:


Nextcloud is a web application written in PHP. We will therefore need a web server and a database.

The official installation involves installing the well-known Apache web server. However, as it is an installation that we may have to use on machines with few resources, I have opted to adapt it for nginx, which is a much lighter server.

We will use configurations created by the Nextcloud community, adapted to the official Apache ones. I have taken the liberty of adapting these configurations in turn to simplify and update them to the current versions of the different software packages that we will be using.

For the database I will opt for MariaDB.

With the software already chosen, we proceed to the installation of the different requirements.

We update our system first. We will assume that we are working with Ubuntu 20.04 LTS:

sudo apt update
sudo apt upgrade

We install the necessary web server, database and php packages:

sudo apt install nginx mariadb-server 
sudo apt install php7.4-gd php7.4-mysql php7.4-curl php7.4-mbstring php7.4-intl php7.4-gmp php7.4-bcmath php-imagick php7.4-xml php7.4-zip php7.4-bz2 php7.4-fpm 

We connect to mysql/MariaDB and create our database that will house the information of our Nextcloud installation, replacing username and password with the credentials that we choose. We write down the username and password that we will need later:

sudo mysql -uroot -p 

CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';
CREATE DATABASE IF NOT EXISTS nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
GRANT ALL PRIVILEGES ON nextcloud.* TO 'username'@'localhost';

Download and install Nextcloud

We download Nextcloud from its page: -> Server -> Download for server -> Download Nextcloud -> Details and download options

We go to our terminal and download it, along with the sha256 and asc file for verification, replacing x.y.z with the current version:


We check the package:

gpg --import nextcloud.asc
gpg --recv-keys 28806A878AE423A28372792ED75899B9A724937A
gpg --verify nextcloud-x.y.z.tar.bz2.asc nextcloud-x.y.z.tar.bz2
sha256sum -c nextcloud-x.y.z.tar.bz2.sha256 < nextcloud-x.y.z.tar.bz2
> OK

Once verified, we extract it and copy it to the folder where it will reside from now on:

tar -xjvf nextcloud-x.y.z.tar.bz2
cp -r nextcloud /var/www

We make nginx the owner of the newly created directory:

sudo chown -R www-data:www-data /var/www/nextcloud

Nginx configuration

We need to create the main configuration file. This is the list of instructions that we give to nginx so that it knows how to behave when running our Nextcloud instance.

So we create the file /etc/nginx/sites-available/nextcloud.conf which will contain the following lines:

upstream php-handler {
    server unix:/var/run/php/php7.4-fpm.sock;

server {
    listen 80;
    listen [::]:80;

    # set max upload size and increase upload timeout:
    client_max_body_size 512M;
    client_body_timeout 300s;
    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/ application/wasm 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;

    # Pagespeed is not supported by Nextcloud, so if your server is built
    # with the `ngx_pagespeed` module, uncomment this line to disable it.
    #pagespeed off;

    # HTTP response headers borrowed from Nextcloud `.htaccess`
    add_header Strict-Transport-Security "max-age=31536000" always;
    add_header Referrer-Policy                      "no-referrer"   always;
    add_header X-Content-Type-Options               "nosniff"       always;
    add_header X-Download-Options                   "noopen"        always;
    add_header X-Frame-Options                      "SAMEORIGIN"    always;
    add_header X-Permitted-Cross-Domain-Policies    "none"          always;
    add_header X-Robots-Tag                         "none"          always;
    add_header X-XSS-Protection                     "1; mode=block" always;

    # 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/nextcloud;

    # Specify how to handle directories -- specifying `/index.php$request_uri`
    # here as the fallback means that Nginx always exhibits the desired behaviour
    # when a client requests a path that corresponds to a directory that exists
    # on the server. In particular, if that directory contains an index.php file,
    # that file is correctly served; if it doesn't, then the request is passed to
    # the front-end controller. This consistent behaviour means that we don't need
    # to specify custom rules for certain paths (e.g. images and other assets,
    # `/updater`, `/ocm-provider`, `/ocs-provider`), and thus
    # `try_files $uri $uri/ /index.php$request_uri`
    # always provides the desired behaviour.
    index index.php index.html /index.php$request_uri;

    # Rule borrowed from `.htaccess` to handle Microsoft DAV clients
    location = / {
        if ( $http_user_agent ~ ^DavClnt ) {
            return 302 /remote.php/webdav/$is_args$args;

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

    # Make a regex exception for `/.well-known` so that clients can still
    # access it despite the existence of the regex rule
    # `location ~ /(\.|autotest|...)` which would otherwise handle requests
    # for `/.well-known`.
    location ^~ /.well-known {
        # The rules in this block are an adaptation of the rules
        # in `.htaccess` that concern `/.well-known`.

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

        location /.well-known/acme-challenge    { try_files $uri $uri/ =404; }
        location /.well-known/pki-validation    { try_files $uri $uri/ =404; }

        # Let Nextcloud's API for `/.well-known` URIs handle all other
        # requests by passing them to the front-end controller.
        return 301 /index.php$request_uri;

    # Rules borrowed from `.htaccess` to hide certain paths from clients
    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)  { return 404; }
    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console)                { return 404; }

    # Ensure this block, which passes PHP files to the PHP process, is above the blocks
    # which handle static assets (as seen below). If this block is not declared first,
    # then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
    # to the URI, resulting in a HTTP 500 error response.
    location ~ \.php(?:$|/) {
        # Required for legacy support
        rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy) /index.php$request_uri;

        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        set $path_info $fastcgi_path_info;

        try_files $fastcgi_script_name =404;

        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $path_info;
        fastcgi_param HTTPS on;

        fastcgi_param modHeadersAvailable true;         # Avoid sending the security headers twice
        fastcgi_param front_controller_active true;     # Enable pretty urls
        fastcgi_pass php-handler;

        fastcgi_intercept_errors on;
        fastcgi_request_buffering off;

        fastcgi_max_temp_file_size 0;

    location ~ \.(?:css|js|svg|gif|png|jpg|ico|wasm|tflite)$ {
        try_files $uri /index.php$request_uri;
        expires 6M;         # Cache-Control policy borrowed from `.htaccess`
        access_log off;     # Optional: Don't log access to assets

        location ~ \.wasm$ {
            default_type application/wasm;

    location ~ \.woff2?$ {
        try_files $uri /index.php$request_uri;
        expires 7d;         # Cache-Control policy borrowed from `.htaccess`
        access_log off;     # Optional: Don't log access to assets

    # Rule borrowed from `.htaccess`
    location /remote {
        return 301 /remote.php$request_uri;

    location / {
        try_files $uri $uri/ /index.php$request_uri;

We activate it by creating a link in the directory sites-enabled :

sudo ln -s /etc/nginx/sites-available/nextcloud.conf /etc/nginx/sites-enabled/

Next we will modify a couple of PHP configurations so that Nextcloud behaves correctly and has enough memory to be able to deal with synchronizing larger files.

In the File /etc/php/7.4/fpm/pool.d/www.conf edit the lines:

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

We change two variables in the file /etc/php/7.4/fpm/php.ini

# Default is 128M
memory_limit = 512M 

# Default is 2M
upload_max_filesize = 100M

We restart php and nginx:

sudo systemctl reload php7.4-fpm.service
sudo systemctl restart nginx

Secure SSL connection: letsencrypt!

If we are going to use this installation in a more "official" way, it is advisable to connect to it using SSL. For this we will need to generate our certificates. We will use certbot for this purpose:

sudo apt-get install python3-certbot-nginx

sudo certbot --nginx

We will answer certbot questions. We will choose "redirect to SSL" to force the user to connect securely.

We restart nginx again to load the modified configuration file, with the directives to connect by SSL.

sudo systemctl restart nginx

We connect for the first time with our installation. In our case,

Being the first time, it will ask us to create username and password and other data such as our database and your access password.

As soon as everything has been configured, it automatically takes us to our dashboard


In the upper right corner, if we click on our user, we can create more users and install applications

These are just some of the recommended apps. I invite the reader to discover more of so many jewels included in the huge directory:

  • Contacts. Contact directory that allows access to phones and email programs through CardDAV
  • Calendar. Same idea but for calendars. It will allow us to connect through CalDAV
  • Photos. Storage, categorization and viewing of photos and videos in the style of Google Photos. The different programs and apps will allow us to synchronize them on the devices we want
  • Files. The same idea but for files of all kinds.
  • News – RSS feed manager. We can create custom RSS feeds so that the status of the articles we read is synchronized on all our devices
  • Bookmarks. The same, but for the favorite links of all our browsers
  • PhoneTrack. What if you wanted your family to be able to track you privately without sharing your location with "the cloud"? This AddOn makes it possible if paired with mobile Apps created for this purpose.
  • Notes. Our notepad on the server, synchronized with the different apps.

As we said, there are many more that you can discover by browsing these lists. I leave as an exercise to the reader to install and test some more applications.

Sync to phone and computer: Nextcloud and DAVx5 apps

All these functionalities already described, would not be of much use if they remained only on our server. The interesting thing is the synchronization and possibility of collaboration between teams that this system offers.

On this page we can download the Nextcloud application for any of our platforms, whether computer or mobile phone.

If we also install DAVx5 on Android, we can synchronize both contacts and calendars with our new Nextcloud installation.


Much of the configuration files have been taken from the excellent documentation pages of the Nextcloud project, ordered, simplified and organized as I saw fit, trying to make the process less dry to the reader.

Found this post helpful? Consider sending the author a tip