Goodbye Dropbox, Hello Nextcloud
Dropbox is Expensive Link to heading
I remember when I used to pay for Dropbox. It cost roughly $11.00/month for 2TB. Now don’t get me wrong, I wanted to host my entire collection of anime and some pictures. However, over time the $11.00/month started to add up and Dropbox became expensive. Plus I didn’t want my files to be on another person’s server. I wanted to take back ownership of my files and self host.
But how exactly would I be able to do just that???
Well, I had a raspberrypi 4B 8GB of RAM version and a 2TB hard drive laying around so ofcourse my initial thought would be to host my files on that. But the one cool thing that dropbox gave me was an easy UI. Plus, I did not want anyone to access my files nor would I want my raspberrypi to be attacked by hackers. I needed a level of security when accessing my raspberry pi from the outside.
Nextcloud + Tailscale Link to heading
Nextcloud is a free and open source solution for file hosting. Tailscale is a vpn service that allows you to access end devices through a “tailnet” using Wireguard. With these two services, I am able to create a file hosting service that I can access on my end device so long as its connected to the “tailnet”. Plus nextcloud has an iPhone application that I can use to access my files from the outside.
Setup Link to heading
TLDR: I’m using docker-compose to set up nextcloud. I’ve also installed tailscale on the raspberrypi running Ubuntu Server 24.
Materials Link to heading
- Raspberry Pi 4B 8GB RAM
- Raspberry PI power supply (I’m using Power over Ethernet via the POE Hat. It provides both power and networking for the Pi)
- Ethernet cable (CAT 6)
- MicroSD Card (32GB)
- 2TB External Hard-drive formatted to ext4
Raspberry Pi Link to heading
Flashing the SD Card Link to heading
The easiest way to flash an Operating System onto the SD card is through the Raspberry Pi Imager.
You can download it from this link. Follow the instructions on installing the application and open it.
From the Device list, select Raspberry Pi 4.
Now we need to choose an operating system. I’m going to install Ubuntu Server 24. Click on Other general-purpose OS and select Ubuntu Server 24.
Finally, choose the storage location which is the SD card and click Next. If you’d like, you can set up some extra configurations like ssh-keys or password or even the Wi-Fi for the raspberry pi to connect to. I normally set the default account as username: pi and password: raspberry but feel free to set it up with your own credentials. I am using a wired connection so I’m going to skip this but feel free to edit the configurations. Now image your pi and wait until the application completes.
Connecting to the Pi Link to heading
With your Pi connected to the network, we are going to ssh into the raspberry pi.
- Run the
ssh
command below:
ssh pi@<IP>
- Now we always need to make sure our linux server is up to date with its package. To do that we need to run and
update
and andupgrade
sudo apt update && sudo apt upgrade
Docker Link to heading
Now that we got our raspberry pi updated with the latest packages, we need to install docker. I followed the instructions from the docs.docker website linked here. Scroll to the section that says Install using the apt
repository. These would be the commands we need to run on the raspberry pi.
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
Once we have run the commands above, we can install docker.
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Do a quick test as suggested in the website by pulling the hello-world
image.
sudo docker run --rm hello-world
I added the --rm
flag to clean up the container once it exits.
Docker Compose Environment Link to heading
- Change directory to the pi home with the
cd
command.
cd ~pi
- Create two directories that are nested. I like to call the parent directory docker-compose and the child directory nextcloud
mkdir -p docker-compose/nextcloud
The -p
flag will create the parent directories if needed.
Docker Compose File Link to heading
For the actual docker compose file, I wrote out the nextcloud service like this:
services:
nextcloud:
image: linuxserver/nextcloud
container_name: nextcloud
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
ports:
- 443:443
volumes:
- /home/pi/nextcloud/config:/config
- /media/external/nextcloud/data:/data
restart: unless-stopped
Let’s take a quick look at the volumes. I decided to store the nextcloud configuration on the home directory of the raspberry pi. However the data that will be used by nextcloud will be stored on the external 2TB drive. I’ll go over mounting the external drive onto your raspberrypi using both the mount
command and making a change in fstab
. Go ahead and save the file, We won’t run docker compose
yet because we still need to mount the external drive.
Mount External Drive Link to heading
Unlike Windows or MacOS, most distros of Linux will not automatically mount your external drive. You’re going to need to mount it yourself. The first thing to do is identify where the drive is. You should see it as /dev
with either sda1, sda2, sdb1,
etc.
- To find out where the drive is, type in the
lsblk
command.
lsblk
Your result should look something like this
Here we can see that the 2TB external drive is attached to /dev/sda2 which means we need to mount that drive to /media/external
Mount Command Link to heading
For a one time mount, we can use the mount
command to mount our drive to /media/external.
sudo mount /dev/<sda#,sdb#> /media/external
To make sure we mounted it properly, we can simply type the mount
command and check the output to see if our external drive mounted properly.
FSTAB Link to heading
Now the mount command is great for a one time thing. But let’s say that your raspberrypi gets disconnected. You’ve now lost your mount point. To prevent this, we can have the external drive mounted on start up by adding an entry to /etc/fstab. Normally when making an addition to the fstab file, we can add our device name, some configurations, and we’d be good. However, device names are dynamic and we want to make sure that we mount just the external hard drive for now.
-
Type the
blkid
command to get the blockids of the devices. -
Look for your external hard drive at /dev/<sda,sdb>
-
On that line, you should see something that says UUID. Copy that value by highlighting it and right-clicking it. We will use that value as an entry for fstab.
-
Open /etc/fstab in a file editor of your choice. I’m going to use VIM for this example but feel free to use NANO.
sudo vim /etc/fstab
-
Scroll to the bottom of the file.
-
Type
i
for insert mode in VIM. -
Add the following line in the following pattern:
UUID=<UUID you copied> /media/external ext4 defaults 0 0
Let’s deep dive into what that particular line is.
- The first value is the device’s UUID which is a unique ID for that particular drive. This means that only that drive will be able to mount on the mount point.
- The second value is the mount point. In this example, we are mounting the device to /media/external but you can mount it wherever you see fit. Just don’t forget to change the mount point in the docker-compose file!
- The third value is the filesystem of the drive. The drive should be of ext4 filesystem but if it isn’t, you’re going to need to format the drive to ext4. Most of the time you can simply use the
mkfs.ext4
command on your device and the filesystem should be set to ext4. - The fourth value are the mount options. We don’t need any special options here and simply just need the drive to mount on startup.
- The fifth value is a backup operation which is outdated.
- The sixth value is a file system check order. This is a priority assigned to check the filesystem. Values with a 0 means that the filesystem will not be checked. We want to avoid using 1 because this disk is not a root filesystem. I’m setting it to 0 because I don’t need the filesystem to be checked.
-
Once you’ve added your line to fstab, close out the file. In VIM, we can use a
:wq
to save and close the file. -
Type
sudo systemctl daemon-reload
to reload the fstab.
Now we have successfully added a line to fstab and our external drive will mount automatically when the raspberrypi boots up!
Tailscale Link to heading
We got our docker-compose file setup and our external drive mounted. Now we need a way to access the raspberrypi from the outside. I’m going with Tailscale as my connection choice. To learn more about tailscale, click here. Setting up tailscale on the raspberrypi is super simple.
- Create a tailscale account.
- On the raspberrypi, type the following command as stated on the tailscale website.
curl -fsSL https://tailscale.com/install.sh | sh
- Now we want to turn on tailscale.
sudo tailscale up
-
There should be an address output from the command. Open up a browser and paste that URL in.
-
Connect to your device via the URL and your device should be added to your tailscale admin console.
And thats it for Tailscale! It’s super simple to set up and the webUI is also easy to navigate. At this point, I would download the Tailscale client on your laptop or iPhone. Tailscale should provide you with an IP Address of your raspberrypi. Make sure to save that IP Address off to the side because we will need it.
Running Nextcloud Link to heading
Now with our environment setup, we are good to run a docker compose up
command.
- SSH into your raspberrypi.
- Change directory to the docker-compose.yml file we created above using the
cd
command. - Perform a
docker compose up
in detached mode.
docker compose up -d
You should see docker pull the nextcloud image. To view the logs, type docker compose logs
and you will be presented with the nextcloud service’s logs. You can even check to see if the container is running by typing docker ps
and look for a container named nextcloud.
-
We are going to take the IP address of the raspberry pi first and paste it in the URL browser. We will come back to the tailscale IP address since we need to make a configuration change. You should be presented with an initial login page
-
Type in an admin account name and an admin password.
-
For the database, we are going to use the default which is SQLite.
-
Click on the Install button. The installation should take a few minutes.
-
Once the installation is complete, we can stop Nextcloud with a
docker compose down
command.
docker compose down
- In order for us to use the tailscale IP address to work, we need to make a change in the configuration file. On the raspberrypi, go the nextcloud config directory. In the docker compose we have it set to
/home/pi/nextcloud/config
.
cd /home/pi/nextcloud/config
- To edit the configuration file, we need to go to the following directory:
cd www/nextcloud/config
-
Using your editor of choice (in my case its VIM), edit the config.php file.
-
Where it says
array
, add an entry with your Tailscale IP Address.
array (
0 => '<raspberrypi local IP>',
1 => '<raspberrypi tailscale IP>'
)
- Change directory back to where the next cloud docker-compose.yml file is.
cd /home/pi/docker-compose/nextcloud/
-
Run
docker compose up -d
to start the nextcloud service in detached mode. -
Now enter your tailscale IP address and you should see your nextcloud login page.
If you see a login page and you are able to access your files, CONGRATULATIONS! You are now self hosting a file sharing application on a raspberrypi. Your files are with you and on a device you control. You’ve even added a security measure with tailscale to access the file server via the tailnet. You are now ready to start uploading files.
Additional Items Link to heading
Uploading Files into Nextcloud via SFTP Link to heading
Now that you have your nextcloud file hosting service up, you can start uploading files. However, using the webUI for uploading large files has errored out too many times for me. The better way to put your files directly on the nextcloud server (i.e. the raspberrypi) is to use SFTP or Secure File Transfer Protocol.
What is SFTP Link to heading
SFTP or Secure File Transfer Protocol is a network protocol that allows users to securely transfer files from a client to a server. It utilizes the same port as SSH so we don’t have to do any configurations for sftp to work.
Steps Link to heading
-
On the client machine (a laptop), go the directory where you have the large file via the terminal.
-
Type in the following:
sftp pi@<TAILSCALE IP>
You can also use your local raspberrypi IP address.
- Change directory to the location of the external hard drive’s nextcloud data. We mounted it in /media/external.
cd /media/external/nextcloud/data
- You should see your admin account directory. Change directory to the files directory within your admin account.
cd <admin account>/files
- Put your file using the
put
command. If you are putting a directory, you are going to need to add the flags-rf
for recursive and force.
put <FILE>
put -rf <DIRECTORY>
- We can close the sftp session by typing
bye
.
Now if we go to the webUI of nextcloud, we won’t be able to see the new file/directory we just uploaded. To fix this, we have to go into the container and execute a file scan.
- Because we named our container nextcloud, we are going to type:
docker exec -it nextcloud /bin/bash
What this command does is it executes a particular command within the container. In this case, we want to create an interactive shell in side the container that runs the bash command to open a bash shell.
- Once inside the container, we can run a file scan.
occ files:scan --all
- Now we can open up the nextcloud webUI and we should see our new file/directory.