Install Nextcloud on Raspberry Pi

For a lot of people, using a cloud service such as Dropbox or Google Drive for syncing their data between different machines has become a necessity. However, it comes at a cost - you lose control over your data once you uploaded them. What if you could run a cloud service at your personal server? Welcome to Nextcloud. You might have a heard about Owncloud. Due to disagreements over the goals of the project, the Owncloud founder and few other key figures have forked it into Nextcloud. Between the Nextcloud conference and the Nextcloud Box, the project seems to be gaining a lot of traction. And that’s why I chose it rather than Owncloud. As in my previous guides for Setting Up Headless Raspberry Pi Server and Turning Raspberry Pi Into Torrentbox, I will guide you step by step how to install Nextcloud on Raspberry Pi, turning it into your personal cloud. In the examples, I am using Raspbian, but the instructions should be similar for other systems.

Setup Database

Nextcloud is a web application written in PHP. Therefore, to run it, you will need to install a web server, an SQL database and PHP. The following command will install PHP, with MariaDB as database and nginx as web server:

$ sudo apt install nginx mariadb-server php7.4-fpm php7.4-cli php7.4-mysql php-pear php7.4-gd php7.4-mcrypt php7.4-curl php7.4-apcu

During the installation you will be asked for your MariaDB password. Write it down somewhere (or better, use a password manager like Keepass). Now it’s time to configure things. Let’s start with MariaDB. Above all else, secure the installion:

$ mysql_secure_installation

First, enter the MariaDB root password you wrote down earlier. Then choose the following options:

Change the root password? [Y/n] n
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

Now your MariaDB installation should be a bit more secure. All that is remaining, is to create the database for Nextcloud. For that, login to MariaDB as root:

$ mysql -u root -p

and execute the following commands to create a database, a database user and give the user proper privileges:

CREATE DATABASE nextclouddb; CREATE USER 'nextclouddb'@'localhost' IDENTIFIED BY 'password';
GRANT ALL ON nextclouddb.* TO 'nextclouddb'@'localhost';
FLUSH PRIVILEGES;
quit

Configure PHP

Next on the chopping block is php-fpm. Start by opening the /etc/php/7.4/fpm/pool.d/www.conf file:

sudo vim /etc/php/7.4/fpm/pool.d/www.conf

change the listen line to:

listen = 127.0.0.1:9000

and uncomment the lines defining path variables:

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

When done, open /etc/php/7.4/fpm/php.ini and change the following lines to allow the upload of files up to 2G:

upload_max_filesize = 2000M
post_max_size = 2000M
memory_limit = 2000M

And while you are at it, turn off allow_url_fopen, as it allows remote PHP code execution and is a common cause for having your server hacked:

allow_url_fopen = Off

then reload the php-fpm service:

$ sudo systemctl reload php7.4-fpm.service

One more thing, open sudo nano /etc/dphys-swapfile and edit this line:

CONF_SWAPSIZE=512

Configure the Web Server

Now, if you open the browser and enter your Raspberry’s IP address (192.168.0.1 in my case), you should see the Nginx welcome page. Let’s configure it to work with Nextcloud. First, generate an SSL key and change its permissions:

$ sudo openssl req $@ -new -x509 -days 730 -nodes -out /etc/ssl/certs/nextcloud.pem \
  -keyout /etc/ssl/private/nextcloud.key
$ sudo chmod 600 /etc/ssl/certs/nextcloud.pem
$ sudo chmod 600 /etc/ssl/private/nextcloud.key

Then open the nginx configuration with by sudo nano /etc/nginx/sites-available/nextcloud and paste the following in place of the original configuration:

upstream php-handler {
    server 127.0.0.1:9000;
}


server {
    listen 80;
    server_name 192.168.0.1;
    # enforce https
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    server_name 192.168.0.1;
    ssl_certificate /etc/ssl/certs/nextcloud.pem;
    ssl_certificate_key /etc/ssl/private/nextcloud.key;
    add_header Strict-Transport-Security “max-age=15768000; includeSubDomains; preload;;
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options “SAMEORIGIN”;
    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;

    # Path to the root of your installation
    root /var/www/nextcloud/;

    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 2000M;
    fastcgi_buffers 64 4K;

    # Disable gzip to avoid the removal of the ETag header
    gzip off;

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

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

    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
        deny all;
    }

    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
        deny all;
    }

    location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+|core/templates/40[34])\.php(?:$|/) {
        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|woff|svg|gif)$ {
        try_files $uri /index.php$uri$is_args$args;
        add_header Cache-Control “public, max-age=7200”;
        add_header X-Content-Type-Options nosniff;
        add_header X-Frame-Options “SAMEORIGIN”;
        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;
        # Optional: Don’t log access to assets
        access_log off;
    }

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

Install Nextcloud

Good, we’re almost there. There is only one piece of the puzzle left - Nextcloud itself. Download the tarball of the latest version (12.0.2 at the time of writing) and uncompress it:

 wget https://download.nextcloud.com/server/releases/nextcloud-12.0.2.tar.bz2 tar xvjf nextcloud-12.0.2.tar.bz2

Move the uncompressed files into the appropriate folder and change the permissions:

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

The tarball is not needed anymore, so just delete it:

$ rm -rf nextcloud-12.0.2.tar.b2z

In order to enable large file upload, you also have to open /var/www/nextcloud/.user.ini and edit the following:

upload_max_filesize=2000M
post_max_size=2000M
memory_limit=2000M

That concludes the Nextcloud configuration. Now you just need to create a folder for storing the data on an external drive. If you have no drive connected yet, check “Connecting an External USB Drive” section in my guide on turning Pi into a torrent box. Create the folder and change its owner to the www-data user and group:

$ mkdir -p /media/external/nextcloud/data
$ sudo chown -R www-data:www-data /media/external/nextcloud

Everything is ready to run now! Just open the web browser and type in your Pi’s IP (192.168.0.1 in my case), enter your username and password, database name and its user name and password, and last but not least /media/external/nextcloud/data as the data directory. Congratulations! You have setup Nextcloud on your Raspberry Pi. Now I recommend installing a desktop client and start syncing your data. If you have any questions, leave me a comment.