Cover image for How I turned my Raspberry Pi into a private cloud server

How I turned my Raspberry Pi into a private cloud server

rossanodan profile image Rossano D'Angelo Updated on ・5 min read

I do like travelling and taking pictures, even if most of them are really pointless πŸ˜„

Once back at home, I'm used to move all the pictures I took on my laptop and, after a selection, I upload the best pictures to the cloud. I like using Google Photos. But there's a problem.
Since I use the Free plan, I don't upload pictures with the original size. It means they lose quality.

That's why I decided to buy an HDD and to upload my pictures on it, not using Google Photos anymore.

Damn I miss it.

I don't have access to my pictures anymore when I'm not around my HDD. Showing and/or sharing them's impossible.

That's when the idea of the private cloud started floating in my mind.

You may say buying a HDD wasn't a cost? Pay for Google Photos then! You're right but nothing is better than the satisfaction you get by something built by yourself. I really like doing this kind of things so I made my private Google Photos! It's a full private cloud service actually - documents, video, images, emails, etc - but I use it only for my pictures.


Raspberry Pi and Micro SD

To setup my photo server I used a Raspberry Pi 4 (4 GB RAM) with 16 GB Micro SD and an external USB drive to use as storage.

Alt Text

Docker and Docker Compose 🐳

I also installed Docker on my Raspberry Pi: I didn't want to re-install everything in case something goes wrong.

Once installed, I did make sure the user pi can use it (I don't want to use sudo every time)

curl -fsSl https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker pi

I installed Docker Compose too - kudos to Roahn for the help

sudo apt-get install -y libffi-dev libssl-dev python3 python3-pip
sudo apt-get remove python-configparser
sudo pip3 install docker-compose

Since the architecture of the Raspberry Pi is different than the classic Ubuntu's, I needed to install Docker Compose via pip3.

The infrastructure

To setup Nextcloud I used a yml file docker-compose.yml

version: '2'


    image: nextcloud
      - 8080:80
      - nextcloud:/var/www/html
    restart: always

This yml file contains the infrastructure I want to build. This way to build infrastructures is called IaC, Infrastructure as Code: you declare the services you want to run and how they have to communicate each other and Docker Compose does the job for you.

In this case, I declared I want to use the nextcloud image to run an app on the port 8080 (host - I reach it on this port) and to redirect to the container "internal" port 80. Learn here how to expose ports. I also specified the path for the volume - where the container stores data (my photos).

Up and running

Now that the docker-compose.yml is ready, it's time to launch πŸš€

docker-compose up -d

The option -d stands for detached mode, containers run in background.

To check if the container we declared in the yml file is up and running, run

docker ps

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
a1d31d5ee1d6        nextcloud           "/entrypoint.sh apac…"   About an hour ago   Up About a minute>80/tcp   nextcloud_app_1

I can do something similar with Docker Compose. Within the root folder that contains the docker-componse.yml file, run

docker-compose ps

     Name                    Command               State          Ports
nextcloud_app_1   /entrypoint.sh apache2-for ...   Up>80/tcp

The difference between docker ps and docker-compose ps is that docker ps lists all running containers in docker engine while docker-compose ps lists containers related to images declared in the docker-compose.yml file.

If you're on your Raspberry, go to http://localhost:8080/. If you're connected to the Raspberry Pi via SSH instead, open a browser and go to http://[HOSTNAME]:8080/.

If you don't know the IP address of your Raspberry Pi, just run

hostname -I 2a00:23c7:8e8b:1201:f35:95a7:4c14:6ed

So, in my case, my Raspberry's IP address is It shouldn't change until you disconnect the Raspberry from the Internet > or you restart the router.

Here's a good article about how to connect via SSH to your Raspberry Pi.

Ta-da! Nextcloud is up and running, ready to use! πŸŽ‰ πŸŽ‰ πŸŽ‰

Setup the administrator account and do not change the storage and database settings. It's not time for that yet.

Let's take a closer look

Sweet, Nextcloud is working and is reachable only within my WiFi connection. I can upload photos from my smartphone too!

Let's take a look at the container now. Run

docker ps

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
a1d31d5ee1d6        nextcloud           "/entrypoint.sh apac…"   2 hours ago         Up 37 minutes>80/tcp   nextcloud_app_1

and copy the container id. Now run

docker exec -it <CONTAINER_ID> bash

to enter the container itself, in interactive mode -it using the bash.

What you will see is something like


You entered the container as root and it's waiting for a command. So, let's discover where the container will store my pictures. The volume path is /var/www/html. In this container you have Apache running, that's where /var/www comes from.

To list all the files run ls -l. To discover where Nextcloud stores my data, let's open the config.php file to sneak a peek.

more config/config.php

$CONFIG = array (
  'htaccess.RewriteBase' => '/',
  'memcache.local' => '\\OC\\Memcache\\APCu',
  'apps_paths' =>
  array (
    0 =>
    array (
      'path' => '/var/www/html/apps',
      'url' => '/apps',
      'writable' => false,
    1 =>
    array (
      'path' => '/var/www/html/custom_apps',
      'url' => '/custom_apps',
      'writable' => true,
  'instanceid' => 'ocagdfr8srkl',
  'passwordsalt' => 'Mw2SMCooFW1CAUuyzK7TV5Uh7cbGge',
  'secret' => 'KpK7QWHnzWs/NgdkQSATn4EogqLLrIFLXO0mu0cShbG6zJVQ',
  'trusted_domains' =>
  array (
    0 => '',
  'datadirectory' => '/var/www/html/data',
  'dbtype' => 'sqlite3',
  'version' => '',
  'overwrite.cli.url' => '',
  'installed' => true,

datadirectory, got it!


cd data/<NEXTCLOUD_USERNAME>/files/
ls -l

Here they are, files and folders! Photos are stored into Photos folder.

Alt Text

What's next

My private cloud is ready and now I can safely store my HD pictures on it! Sky is the limit!

Not yet 🚫 I do have two limits:

  1. I can't upload my photos if I'm not a home
  2. I can't upload all the photos I want because of the limited storage capacity of the Micro SD

To overcome these problems are enouhg a domain and an external hard disk πŸ”œ

Posted on Jan 28 by:

rossanodan profile

Rossano D'Angelo


Enthusiastic software engineer and tech lover, passionate about good music 🎢 and soccer ⚽️


markdown guide

Good stuff. I have something similar. Using docs.nextcloudpi.com/en/how-to-ins... . Booting up and running the install from a USB stick. I have found that much more reliable than an SD card. Data directory and snapshot backups are both on dedicated external drives powered by external source. Remote access via a dns address. Just got myself a pijuice power hat for an emergency UPS should it be needed. Here it is in a shoe box... Here it is in a shoe box...


This is awesome!! Do you have any hints for me about using an external hard drive as storage for Nextcloud? I tried but I had errors abour writing permissions on the external disk. I used a HDD 2 TB Toshiba.


Cheers! In order for me to be able to use an external USB drive, the USB drive must not be formatted as NTFS/FAT as these do not support the user/permission system. For me the drives needs to be formatted to BTRFS. That may be worth checking. Big drives (bigger than 2 TB) also need to be partitioned with GPT.


Well done. Please note that 8080:80 in the "ports" section of you docker-compose does not mean "use 80 if 8080 is busy". It means "expose 8080 and redirect to 80 on the container".


Ooooh thanks for reporting this!! I'll edit it right now. Thank you! :)


Pretty cool. I'm sure you thought about it, but for everyone else, on an RP4 you have USB 3 and that means you can hook up an SSD or a any other kind of external drive and make it run on that, and when you are no longer limited by the sd card, imagine the possibilities :)


There you are, that's what I'm try to do ;)


Awesome awesome stuff!!! Really nice! Similar to the app related to dams I did and wrote about here, I believe these projects are the best to learn


I agree. It gave me another chance to go deeper on Docker and Docker Compose. Now, as I said, I need to overcome the limitations.. Let's see if I find good advices here ;)


If I may suggest adding a Redis container to your setup, for Nextcloud caching instead of the default apcu. I'm also looking into adding a Photoprism container since it can import directly from Nextcloud, or so I keep reading.
Also I found Docker compose to be cumbersome so I started using Ansible since it has it's own "docker_module". That way I deploy my own cloud infra with really granular parameters and modulatity, and also avoiding docker-compose's "deploy my containers as a group" mentality.
The beauty of it all is that if one RaspberryPi's power isn't enough for this setup you can always buy another one and split containers among them as you see fit.

I followed what you said but, I want to be honest, I'm not able to implement such architecture by my own. I'm only at the beginning! :)
I'll keep your comment in mind tho, it'll be useful for my next steps into docker and docker-compose. I like working with it!! :)


Thank you Moeletji! You made my day with these comments. Really glad you enjoyed it :)


I like this. Running docker really excited me I can't wait to try it out.