How to Build a Raspberry Pi Personal Cloud Server with NextCloud

This guide will show you how to create a Raspberry Pi Personal Cloud Server covering flashing Raspbian and securing your Pi server with SSL.

By Tim Trott | Raspberry Pi Projects | November 23, 2017
2,977 words, estimated reading time 11 minutes.

Now you have your new Raspberry Pi, you may be wondering how to use it. This guide will show you how to flash Raspbian, boot into your Raspberry Pi, and configure and build a personal cloud server secured with SSL from Let's Encrypt.

Why a Personal Cloud Server?

Cloud servers such as Google Drive, Apple iCloud, Microsoft OneDrive and Dropbox are all well and good, but the free space they provide isn't very much these days (~5GB) and additional storage can be very expensive.

Most of the top cloud storage providers have had some form of security breach [1] , [2]  or problems with their platform resulting in data loss [1] .

Clouds
Clouds

I also wanted a small public-facing home web server for a few small personal applications, so I thought, "Why don't I put this Raspberry Pi to good use?" The Raspberry Pi 3 Model B has an impressive specs for a tiny computer, it should be more than enough to run a cloud storage server and a few web applications for a single user. As the Raspberry Pi has a very low energy footprint using it as an always-on web server makes it an ideal choice.

In this guide I'll cover installing Raspbian  on the Raspberry Pi, setting up and configuring a web server, network security, nextCloud server  and using Let's Encrypt  X509 certificates for SSL and HTTPS.

Raspberry Pi
Raspberry Pi

You Will Need

  • Raspberry Pi (I'm using a Pi 3 Model B, other models may work)
  • Ascociated peripherals (monitor, keyboard, cables etc)
  • Micro SD card 8GB+
  • 32GB USB Thumb Drive / Flash Drive (for storing files)

Downloading and Flashing Raspbian

Raspbian  is the official OS for the Raspberry Pi. You can install it with NOOBS or download the image and flash it to an SD card yourself. Since the Raspberry Pi has fixed hardware you can flash OS images to the SD card much in the same way as you flash a ROM to an Android smartphone.

For Raspberry Pi, the flashing tool of choice is Etcher. This is a graphical SD card writing tool that works on Mac OS, Linux and Windows and is the easiest option for most users. Simply download the Raspbian image from the link above, Etcher from here , install and run Etcher. It gives you the option of selecting the image to flash, the destination SD card and a button to start the process. Simples.

Using Etcher to flash Raspberry Pi to SD Card
Using Etcher to flash Raspberry Pi to SD Card

Once the process is complete you simply insert the micro SD card into the Raspberry Pi and turn the power on. The Pi will then boot up into Raspbian.

Getting Started in Raspbian

Raspbian is based on Debian, so if you've used Ubuntu or Linux Mint then the system should be very familiar. If you've not used Linux before, I recommend you to read my tutorial series on getting started with Linux.

The default username and password for Raspbian are:

  • Username: pi
  • Password: raspberry

Once you are logged in, the first things to do are to change the default username, password and run system updates.

To change a password in Linux, simply use the passwd command. In Raspbian you can also use sudo raspi-config to enter the configuration screens. Selecting the password option will allow you to change your password.

If you wish to rename the default pi username, the process is simple but involves a few steps.

Firstly we need to create a new user.

sudo adduser username

Follow the prompts to set the new user's information. It is fine to accept the default to leave all of this information blank.

Use the usermod command to add the user to the sudo group.

sudo usermod -aG sudo username

Now logout of the pi user and log in with the new username.

Now, simply enter these commands into the terminal. The first command renames the user, the second sets the user's home directory. You may need to copy any files from the old home directory to the new if any were created.

sudo usermod -l techman pi
sudo usermod -d /home/techman -m techman

You can now delete the new user as we won't be needing it again.

sudo userdel username

Running System Updates in Linux

Running system updates is performed by issuing the following command in the terminal.

sudo apt-get update && sudo apt-get upgrade

The next thing to do is set up SSH so I can access the Pi from my desktop. This is easy enough to do as SSH is already installed on the Raspberry Pi, it's just disabled by default. To enable SSH on the Raspberry Pi enter the raspi-config tool, select Interfacing Options and select SSH.

The default hostname for a Raspberry Pi is raspberrypi. Very imaginative. If you would like to change it, you can do that from the raspi-config screen as well. In the remainder of this tutorial simply replace raspberrypi with whatever you chose.

Setting a Fixed IP Address

It is often handy to have servers with a fixed IP address, that way it is easier to remote into them and to set up firewall rules. In my case, later on, I will need to port forward the HTTP and HTTPS ports to the Pi and my router requires a static IP address for this.

Simply edit the DHCP daemon config

sudo pico /etc/dhcpcd.conf

And at the bottom, add in eth0 (Ethernet) or wlan0 (Wireless adaptor) these lines. You should change the IP addresses as provided by your network setup or system administrators.

interface eth0
static ip_address=192.168.1.10/24
static routers=192.168.1.1
static domain_name_servers=192.168.1.1

Reboot for the changes to take effect.

Installing Apache and PHP

For your Raspberry Pi to work as a web server, we need to install the Apache web server, PHP for server-side scripting and MySql for databases.

To install Apache and PHP, you need to run these commands to start the installation. With the release of Stretch, Debian has removed the obsolete PHP5 package so we must use the newer PHP 7.

sudo apt-get install apache2 php7.0 php7.0-gd libapache2-mod-php7.0 php7.0-curl

When the installation is complete you can start Apache with this command.

sudo service apache2 restart

Now you should be able to access the default web page in a browser on another computer by entering http://raspberrypi.local in your browser's address bar.

For setting up websites in Apache, please refer to the article Apache Administration on Linux

Installing MySQL, MariaDB and Creating Root User

Now to install MySql. This is also simple, just type in these commands.

sudo apt-get install mysql-server python-mysqldb php-mysql

Now for the not-so-simple part. MySQL 5.7 changed the secure model so that now MySQL root login requires a sudo-level execution. This means that root can no longer be used for web logins via PHP. The simplest and safest solution will be to create a new user and grant the required privileges.

sudo mysql --user=root mysql

Run the following commands, replacing some_pass with the desired password.

sql
CREATE USER 'lonewolf'@'localhost' IDENTIFIED BY 'some_pass';
GRANT ALL PRIVILEGES ON *.* TO 'lonewolf'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;

Now you should be able to log in with this user later on in this tutorial.

Linux Network Security

Linux server security isn't complicated. There are a few applications to install and configure which will block 99% of attacks an internet-facing web server can be exposed to. Follow these step by step and you should be fine, but as with everything, there are no guarantees. If you have any suggestions to add to this list, please let me know in the comments below.

Install Fail2ban

Fail2ban is a daemon that monitors login attempts to a server and blocks suspicious activity as it occurs. It's well-configured out of the box.

sudo apt-get install fail2ban

Install a Firewall

No secure server is complete without a firewall. Linux provides a good firewall called ufw, which makes firewall management easy. Install it with this command:

sudo apt-get install ufw

We now need to configure it thusly.

sudo ufw allow from {your-ip} to any port 22
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enable

This will allow all traffic from your IP address (e.g. a desktop used to SSH into the Raspberry Pi) and from any other address, only port 80 (http) and 443 (https) will be accessible.

That's security on the server sorted. I said it was easy!

When I'm ready to put this Raspberry Pi server live, I'll forward ports 80 and 443 to the Pi IP address on the router. By forwarding these two ports, any attempts to access the Pi on any other port from the internet will be blocked by my router first.

Now is a good time to reboot the Pi so that all the new changes can take effect.

sudo shutdown -r -t 0

Installing 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.

Installing NextCloud to the Raspberry Pi is quite simple, although it is more involved than previous installations.

I'm using the default Apache www directory for this, if you have changed the location then adjust the commands accordingly. Also, note this is the current version as of writing. You should check the NextCloud website download page for the latest file version.

First, change the directory to the HTML root.

cd /var/www/html

Now we need to download the NextCloud archive to this folder and extract it. This file was the latest as of the time of writing, please refer to the NextCloud website for the most up-to-date version.

sudo wget https://download.nextcloud.com/server/releases/nextcloud-12.0.3.zip
sudo unzip nextcloud-12.0.3.zip

This will extract all the required files to a new nextcloud directory.

Optional - Store Data Files on External Drive

Raspberry Pi
Raspberry Pi

This part is optional. For me I'm using an 8GB micro SD card, which doesn't offer much for cloud storage, so to add more space and reduce stress on the micro SD card, I've added a 32GB USB thumb drive to my Pi which I will use exclusively for storing my files. I've created a data directory in /media which will be used to mount the drive.

sudo mkdir /media/data

I will then add the USB mount to the automatic fstab file so that it will mount automatically at boot. I've formatted mine as FAT32 since I will be sharing this USB stick with a Windows laptop and FAT32 is natively supported by both Windows and Linux. I could have used exFat, but eh. Old skool. You can use whatever filesystem you choose here. If you are not connecting the external storage to Windows then EXT4 may be a better option for you.

First, you will need to know the uid of the www-data user on your system. This is as easy as typing in

id www-data
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Next, we need to know the block device associated with the USB drive:

sudo fdisk -l
Disk /dev/sda: 29.7 GiB, 31914983424 bytes, 62333952 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x0006c0e4

Device     Boot Start      End  Sectors  Size Id Type
/dev/sda1  *     2048 62333951 62331904 29.7G  c W95 FAT32 (LBA)

Now we know the block device we need to know the unique ID to mount the drive. We can find out the UUID by using this command.

sudo blkid /dev/sda1

Changing sda1 with the device id in the previous step. Now we know these pieces of information we can proceed to edit the automount entries.

sudo pico /etc/fstab

Now to mount the drive on boot, add the following line

UUID="90A9-AEEF" /media/data vfat auto,rw,uid=33,gid=33,umask=0027 0 0

This mounts sda1 to /media/data as a FAT32 partition, automounted, read and write enabled with user and group owner of www-data and the permissions of 0755. For more information on the fstab permission masks, see this post fstab Permission Masks Explained, and this post for linux file permissions in general.

Now to mount the drive run this command. If all is well you can cd into the data directory and view any files already there, in my case a test.txt file written in Windows.

sudo mount -a

Create NextCloud Data Structure

If you chose to store your data externally, as in the previous step, then you can skip this, otherwise if you are going to use the default storage location you need to run these commands to create the directory and set the permissions.

sudo mkdir -p /var/www/html/nextcloud/data
sudo chown www-data:www-data /var/www/html/nextcloud/data
sudo chmod 750 /var/www/html/nextcloud/data

Setting Permissions for NextCloud and Apache Modules

Now the data storage is configured we need to set the Linux permissions on the config and app folders so that NextCloud can write settings and download apps. We also need to install a few Apache modules if they are not already installed.

cd /var/www/html/nextcloud/
sudo chown www-data:www-data config apps

NextCloud requires a few Apache modules to be installed. They can be added using this command.

sudo apt-get install php7.0-xml php7.0-zip php7.0-mbstring php-xml

Increasing PHP maximum upload size

The default file upload size is very small by today's standards, it won't even let you upload a photo from the iPhone camera. To change this, we need to modify the php.ini file and increase the limit.

sudo pico /etc/php/7.0/apache2/php.ini

Now we need to find and replace the following two lines.

post_max_size = 8M
upload_max_filesize = 2M

To

post_max_size = 1024M
upload_max_filesize = 1024M

This will allow files of 1GB to be uploaded. Feel free to change that number to whatever you think is the maximum size file you will upload to your NextCloud.

For all these changes to take effect, we need to restart Apache.

sudo service apache2 restart

Setting up Let's Encrypt SSL

For any web server running on the open internet, we must use some form of encryption when communicating. For this, we use an X509 certificate and the HTTPS protocol. Because I will be hosting this on my business connection, I have a static IP address and domain name to use. These are required when using the Let's Encrypt service. You can also use a self-signed certificate but you may get security warnings. The data is still encrypted, it's just that your browser cannot verify the server identity with a trusted third party.

Obtaining a certificate from Let's Encrypt

The first thing to do is install the certbot tool. This will do most of the work for us.

sudo apt-get install python-certbot-apache

Next, we need to configure Apache, since certbot will read this file to obtain domain-specific information.

sudo pico /etc/apache2/sites-available/000-default.conf

Within the Virtual Host block, add or uncomment the ServerName directive and set it to your domain name. Save and close the file and test the config using this command.

sudo apache2ctl configtest

If you did the change correctly you should see Syntax OK. Restart Apache then we are good to proceed to obtain the certificate.

sudo certbot --apache

Certbot will read in the Apache config and present a list of domains we can install the certificate for. Hopefully, yours is now on the list, so go ahead and select it from the menu.

Which names would you like to activate HTTPS for?
-------------------------------------------------------------------------------
1: test.example.com
-------------------------------------------------------------------------------
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel):

You will need to provide a valid email address which you can receive confirmation and security messages about. Typically these are just notices regarding renewing the certificate.

Finally, accept the terms and conditions, and certbot goes away and does its thing. If you get errors about "Failed authorization procedure." or "The server could not connect to the client to verify the domain" check that your 443 port is forwarded correctly on your router and that the rules are allowed on the firewall (ufw status).

During the process, there is the option to have all requests redirected to the secure site. I recommend doing this so that everything is sent encrypted. All this does is add an entry to the config which redirects all non-https traffic to the https equivalent. You can also manually add this to the .htaccess for the same result.

RewriteEngine on
RewriteCond %{SERVER_PORT} 80 
RewriteCond %{SERVER_NAME} =test.example.com [NC]
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent]

The final step is to add the domain name to NextClouds trusted domain list, else you will get a message stating access from an untrusted domain is denied.

sudo pico /var/www/html/nextcloud/config/config.php

Locate the trusted domains and add a new line.

'trusted_domains' =>
array (
    0 => '192.168.0.2',
    1 => 'test.example.com',
),

Installing NextCloud

Now we have everything all set up and ready to go. You should be able to use your internet browser to navigate to the domain name you specified in the Apache config and access the NextCloud welcome screen.

NextCloud installation wizard
NextCloud installation wizard

Enter in details for an admin user to create, change the storage location if you are using external storage, or leave the default if not, and specify the details for the database connection.

Hopefully, when the process completes, it does take a little while, you should see the screen below.

NextCloud installation wizard
NextCloud installation wizard

Fin!

With a bit of luck, you should now have a secure Raspberry Pi web server complete with NextCloud personal cloud storage configured!

Was this article helpful to you?
 

Related ArticlesThese articles may also be of interest to you

CommentsShare your thoughts in the comments below

If you enjoyed reading this article, or it helped you in some way, all I ask in return is you leave a comment below or share this page with your friends. Thank you.

This post has 21 comment(s). Why not join the discussion!

We respect your privacy, and will not make your email public. Learn how your comment data is processed.

  1. GU

    On Sunday 15th of November 2020, Gunnar said

    Does this work with a raspberry pi 4

    1. On Thursday 10th of June 2021, replied

      Yes. This will theoretically work with all models of Pi. In fact, it will run much faster on a 4.

  2. MS

    On Friday 25th of September 2020, Mark Symms said

    This is great. I do have one question. Does this also act as an NAS, or are all the files handled through the web interface?

  3. DM

    On Monday 15th of June 2020, Dan Martin said

    Hi Tim,
    I love the step by step instructions. I am up to installing PHP and stuck (I think):
    sudo apt-get install apache2 php7.0 php7.0-gd libapache2-mod-php7.0 php7.0-curl
    Reading package lists... Done
    Building dependency tree
    Reading state information... Done
    Note, selecting 'php7.0-thrift' for regex 'php7.0'
    Note, selecting 'php7.0-remctl' for regex 'php7.0'
    Note, selecting 'php7.0-common' for regex 'php7.0'
    Note, selecting 'php7.0-curl' for regex 'php7.0'
    Note, selecting 'php7.0-remctl' instead of 'php7.0-remctl'
    Package php7.0-curl is not available, but referred to by another package.
    This may mean that the package is missing, has been oboleted, or
    is only available from another source

    E: Unable to locate package php7.0-gd
    E: Couldn't find any package by glob 'php7.0-gd'
    E: Couldn't find any package by regex 'php7.0-gd'
    E: Unable to locate package 'libapache2-mod-php7.0'
    E: Couldn't find any package by glob 'libapache2-mod-php7.0'
    E: Couldn't find any package by regex 'libapache2-mod-php7.0'
    E: Package 'php7.0-curl' has no installation candidate

    Any suggestions would be appreciated,
    Dan

    1. DM

      On Monday 15th of June 2020, Dan Martin replied

      I broke up the commands and executed one at a time and it appears to have worked.
      Dan

  4. DA

    On Tuesday 28th of April 2020, Dan said

    Hi Tim,
    first of all thanks for this very useful guide.

    Is it possible to access this cloud from outside my home internet connection?
    I would like to access my data either I am home or not.

    1. Tim Trott

      On Wednesday 29th of April 2020, Tim Trott  Post Author replied

      Yes it is. You would need to setup port forwarding on your router and ideally obtain a static ip address from your ISP. Check your router instructions on how to configure port forwarding and ask your ISP about static IP. You can do it without a static IP, but the one they assign can change randomly thus preventing you from accessing your cloud remotely. Mayby look into something like DynDNS if your ISP does not support static IP addresses.

      1. DA

        On Saturday 2nd of May 2020, Dan replied

        My ISP gives static IP only to business clients. The router has a section called Port Mapping which I think is the same as Port Forwaring.

        Surfing on the web I found a website called no-ip.com which is a free dynamic DNS. Do you have any experience with it?

        1. Tim Trott

          On Monday 4th of May 2020, Tim Trott  Post Author replied

          Port mapping and port forwarding are essentially the same thing. I'm afraid I have no experiance with using dynamic DNS providers but I'm sure there are plenty of comparison sites out there with that information.

      2. DA

        On Friday 1st of May 2020, Dan replied

        Hi Tim,
        on my ISP router I have "port mapping" I suppose this is the same as port forwarding.
        In addition I found a setting called UPnP, do you think this could be useful ?
        what do you think about no-ip.com instead of dynDNS?

        thanks for your kind help

  5. MB

    On Thursday 9th of April 2020, Michael Buckingham said

    8 april
    Would you be kind enough to help me with SSH.? Raspi 3B & buster raspbian, - ssh is enabled, but the Ssh will not authenticate either Juice or termius or any apps. Samsung tablet & android 7.5
    I would appreciate any ideas. Thank you

  6. SA

    On Thursday 20th of June 2019, Sam said

    Is it a requirement that I have purchased a domain name in order to do this? Can I just use a ZeroTier address?

    1. Tim Trott

      On Friday 21st of June 2019, Tim Trott  Post Author replied

      I've not heard of ZeroTier before now, looks interesting though. I imagine you should be able to use one, the domain name it's mainly used for accessing the site from the internet and configuring the web server. I don't know if NextCloud supports ZeroTier addresses, or how to configure it for ZeroTier. If you get it working I'd love to know more!

      1. SA

        On Friday 21st of June 2019, Sam replied

        I was able to get pretty close, but apparently NextCloud now requires PHP 7.1 or greater. The Raspbian Stretch repo only has PHP 7.0. I tried to move to Raspbian Buster, but the installation process went sideways. I ended up having to reinstall the OS onto my Pi. Any thoughts?

  7. JA

    On Thursday 29th of November 2018, JAMES said

    "Within the Virtual Host block, add or uncomment the ServerName directive and set it to your domain name. Save and close the file and test the config using this command."

    Do I just choose a random domain name to use here?

    1. Tim Trott

      On Saturday 1st of December 2018, Tim Trott  Post Author replied

      You should use the hostname for the server you are setting up with a .local suffix. For example myserver.local

  8. NI

    On Monday 5th of November 2018, Nick said

    SD cards are notorious for corrupting if you even look at them wrong. I wouldn't trust one for storage expansion. USB drives are better.

  9. DI

    On Monday 25th of June 2018, Diana said

    I followed each of your instructions and was able to get everything working apart from the last parts on Lets Encrypt setup. Each time I try and call certbot I get "Client with the currently selected authenticator does not support any combination of challenges that will satisfy the CA." What could the problem be?

    1. Tim Trott

      On Monday 25th of June 2018, Tim Trott  Post Author replied

      You need to upgrade your Certbot. Let’s Encrypt permanently disabled the TLS-SNI-01 challenge 1.4k due to a security report, as of 2018/01/09.

      Certbot 0.21.0 was released on 2018/01/17. It adds support for the HTTP-01 challenge to the Apache and Nginx plugins. If you have installed Certbot from your OS package manager, version 0.21.0 probably isn’t available yet. You can install Certbot through <code>sudo apt-get install certbot-auto</code> which will automatically install the latest version.

  10. JO

    On Monday 4th of December 2017, Johnny said

    As said in the fstab file, you can use "UUID= as a more robust way to name devices, that works even if disks are added and removed."

    Now to get that UUID it's very easy :
    -get your device's name (e.g. /dev/sda2) with the disk utility gui, or with sudo fdisk -l, or with gparted
    - use this name to get the UUID : sudo blkid /dev/sdax (your device's name)

    Then add the entry to fstab replacing "/dev/sdax" by "UUID=[your device's UUID]".

  11. RS

    On Friday 1st of December 2017, Roger Smith said

    Nice write-up, I followed it step by step and worked perfect for me. Only thing I'd add is that after getting everything setup, take a backup image of the SD card in case it gets corrupt. Thanks for your efforts in writing.