# Home Cloud Server: Raspberry Pi 5 Upgrade

> Building a home cloud server with Raspberry Pi 5: CasaOS, Nextcloud, RAID storage, and Cloudflare Tunnel.

- Published: 2024-09-22
- Category: Journal
- Tags: Linux
- Reading time: 9 min read
- Source: https://www.muhammetsafak.com.tr/en/blog/home-cloud-server-raspberry-pi5-upgrade/
- Language: en-US
- Author: Muhammet Şafak

---
I had a home server that had been running since 2017: a Raspberry Pi 3 Model B with a 2 TB external drive. It held up for a long time. But eventually, 1 GB of RAM, USB 2.0, and a 100 Mbps network connection were no longer enough. It was time to refresh both hardware and software. This post documents that upgrade process.

![Raspberry Pi 5 (8GB) single-board computer](/images/423bc-raspberry-pi-5-8gb.jpeg)

## Hardware Selection

I went through a lengthy research process. Some products simply couldn't be sourced — they don't ship directly to Turkey, so the cart goes empty with no alternatives. From what was actually available, I weighed price-to-performance and settled on this list:

**Raspberry Pi 5 8 GB with official power adapter:** I expect 8 GB of RAM to last a good while longer. I went with the official adapter to avoid power-related headaches.

**SanDisk MicroSDXC UHS-I A2 64 GB:** I'm not planning to add an NVMe SSD in the near term, so I wanted to be confident about speed and capacity. A 32 GB A1 card probably would have been sufficient too.

**Argon One V3 Case:** Active cooling, aluminium chassis — and a few other nice touches.

**Archgon MH-3643-JSC:** A 4-bay external drive enclosure. Looks quality for the price.

**Seagate IronWolf NAS HDD 4 TB (×4):** Designed for 24/7 operation. In a RAID 10 setup, I get 8 TB of redundant storage. I considered SSDs but the cost multiplied quickly.

I assembled everything in about an hour and a half. The real work starts on the software side.

## OS Installation

Installing an operating system onto the SD card with [Raspberry Pi Imager](https://www.raspberrypi.com/software/) is now a matter of a few clicks — select your device, OS, and target card, then proceed.

For the OS I went with **Raspberry Pi OS 64-bit Lite**. No desktop environment, a Debian-based distribution at around 400–500 MB. No unnecessary overhead for server use.

One important step during setup: when the imager asks about editing settings, go to the `Services` tab and **enable SSH.** If you're doing headless first-access over SSH (no keyboard, mouse, or monitor), this is mandatory.

Insert the SD card, apply power. First boot can take 1–2 minutes. Once you've found the Pi's IP address from your router's admin interface:

```bash
ssh [pi_username]@[pi_ip_address]
```

The username and password are the ones you set in the Imager's settings screen. If you want to change the password:

```bash
passwd
```

## Static IP

To access the server at a fixed local address, a static IP needs to be assigned. This version of Raspberry Pi OS Lite doesn't ship with the `dhcpcd` service; network management has moved to NetworkManager, so the assignment is done with `nmcli`.

For Ethernet (the connection is usually named `Wired connection 1`):

```bash
sudo nmcli connection modify "Wired connection 1" \
    ipv4.method manual \
    ipv4.addresses 192.168.1.249/24 \
    ipv4.gateway 192.168.1.1 \
    ipv4.dns "8.8.8.8,8.8.4.4"
```

For Wi-Fi (the connection is named after the network's SSID):

```bash
sudo nmcli device wifi connect "WiFi_Ag_Adi" password "WiFi_Sifresi"
sudo nmcli connection modify "WiFi_Ag_Adi" \
    ipv4.method manual \
    ipv4.addresses 192.168.1.249/24 \
    ipv4.gateway 192.168.1.1 \
    ipv4.dns "8.8.8.8,8.8.4.4"
```

I prefer a full reboot to apply the changes:

```bash
sudo reboot now
```

To verify the change:

```bash
ip a
```

## DNS

We already added nameservers in the static IP configuration, but for a machine acting as a server it's worth explicitly confirming it's using robust, reliable DNS:

```bash
sudo nano /etc/resolv.conf
```

```text
nameserver 8.8.8.8
nameserver 8.8.4.4
```

I went with Google DNS. Cloudflare DNS is a solid alternative.

There's a catch: on reboot, the system may overwrite this file. To prevent that, make it read-only:

```bash
sudo chattr +i /etc/resolv.conf
```

When you need to edit it again:

```bash
sudo chattr -i /etc/resolv.conf
```

## Firewall (UFW)

Running a server without a firewall is unthinkable.

```bash
sudo apt update
sudo apt install ufw
```

If you're connected via SSH during installation, it will ask whether to allow SSH connections — confirm with `Y`.

Set the default rules first:

```bash
sudo ufw default deny incoming
sudo ufw default allow outgoing
```

Allow SSH:

```bash
sudo ufw allow ssh
sudo ufw allow 22
```

If you're running apps with web interfaces, HTTP and HTTPS ports need to be open:

```bash
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
```

Enable UFW:

```bash
sudo ufw enable
```

More specific rules can be added as needed. For example, allowing only a specific local IP to reach a particular port:

```bash
sudo ufw allow from 192.168.1.100 to any port 3306
```

To check current status:

```bash
sudo ufw status verbose
```

To delete a rule:

```bash
sudo ufw status numbered
sudo ufw delete <RuleNumber>
```

## Storage Pool: RAID 10

Before bringing the drives into the system, formatting them with EXT4 is a good starting point.

List attached drives:

```bash
lsblk
```

Drives will appear as `/dev/sda`, `/dev/sdb`, `/dev/sdc`, `/dev/sdd`, etc. Format each partition individually:

```bash
sudo mkfs.ext4 /dev/sda1
```

Note that you specify the partition name, not the disk name.

Install `mdadm` for software RAID 10:

```bash
sudo apt update
sudo apt install mdadm
```

Create the 4-drive RAID 10 array:

```bash
sudo mdadm --create --verbose /dev/md0 --level=10 --raid-devices=4 /dev/sda /dev/sdb /dev/sdc /dev/sdd
```

Check RAID status:

```bash
cat /proc/mdstat
```

Format the RAID array with EXT4:

```bash
sudo mkfs.ext4 /dev/md0
```

Mount it:

```bash
sudo mkdir -p /mnt/raid10
sudo mount /dev/md0 /mnt/raid10
```

For automatic mounting on every boot, add it to `/etc/fstab` using the UUID. Get the UUID:

```bash
sudo blkid /dev/md0
```

Then edit `/etc/fstab`:

```bash
sudo nano /etc/fstab
```

```text
UUID=<RAID UUID> /mnt/raid10 ext4 defaults 0 0
```

Monitoring RAID status at regular intervals matters:

```bash
sudo mdadm --detail /dev/md0
```

For monitoring and alerts:

```bash
sudo mdadm --monitor --scan --daemonise --mail=root@localhost --delay=300
```

I plan to handle this part with a Python script: it'll run nightly, collect SMART and MDADM data, analyse it, and generate a report. That's a separate post.

### In the Event of a Disk Failure

RAID 10 can tolerate a single disk failure, but you need to act fast. If a second disk fails before you've added a replacement, data loss becomes possible.

Identify the failed disk:

```bash
sudo mdadm --detail /dev/md0
```

The failed disk will appear under `Failed Devices`. If `State` shows `degraded`, the RAID is not running at full capacity.

Remove the failed disk from the array:

```bash
sudo mdadm /dev/md0 --fail /dev/sdc --remove /dev/sdc
```

After swapping in a physical replacement, confirm the new disk's device name:

```bash
lsblk
```

Wipe the new disk:

```bash
sudo wipefs -a /dev/sdc
```

Add it to the array:

```bash
sudo mdadm /dev/md0 --add /dev/sdc
```

Monitor the resync process:

```bash
cat /proc/mdstat
```

Once complete, verify status — `State` should read `clean`:

```bash
sudo mdadm --detail /dev/md0
```

Finally, update the configuration:

```bash
sudo mdadm --detail --scan | sudo tee -a /etc/mdadm/mdadm.conf
sudo update-initramfs -u
```

**Note:** Local storage solutions carry software, hardware, and physical risks. Never rely on a single layer of backup for critical data.

## CasaOS

CasaOS is a home server dashboard that lets you install and manage applications running as Docker containers. Installation is a single command:

```bash
sudo apt update && sudo apt upgrade -y
curl -fsSL https://get.casaos.io | sudo bash
```

This installs dependencies like Docker and Samba, along with the CasaOS web interface. Once complete, access it at:

```text
http://[your_server_ip_address]
```

On first launch you'll create an admin account. After logging in, the `Apps` section shows one-click-installable applications. For any Docker app not listed, use the "Custom Install" button in the top-right corner of the Apps screen.

## Database (MariaDB)

While each application has its own database solution, I wanted a dedicated MariaDB instance — so I can intervene directly at the database level if something goes wrong.

In the CasaOS interface, search for MariaDB under `Apps` and click Install.

Open the MySQL port in the firewall:

```bash
sudo ufw allow 3306/tcp
```

The default root password is `casaos`. Change it immediately:

```bash
sudo mysql -u root -p
```

```sql
ALTER USER 'root'@'localhost' IDENTIFIED BY '[rootP@s$WorD]';
```

Change the `casaos` user's password the same way.

Go into the MariaDB app settings in CasaOS, enter your updated passwords in the environment variables. Don't forget to define a volume for the `/var/lib/mysql` path — otherwise, data will be lost when the container restarts.

![MariaDB app settings in the CasaOS interface](/images/e09fc-ekran-goruntusu-2024-09-22-103628.png)

## Nextcloud

For personal cloud storage, Nextcloud. Search for it in CasaOS and install. While the installation runs, prepare the database Nextcloud will use:

```bash
sudo mysql -u root -p
```

```sql
CREATE DATABASE nextcloud_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'nextcloud_user'@'%' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON nextcloud_db.* TO 'nextcloud_user'@'%';
FLUSH PRIVILEGES;
quit
```

Once installation completes, if the firewall blocks access to the Nextcloud web interface, check the URL for the port it's using and allow it:

```bash
sudo ufw allow 10081/tcp
```

An important detail: Nextcloud accesses the filesystem as the `www-data` user by default. Keep that in mind — it'll matter later.

Create the directory on the RAID that Nextcloud will use:

```bash
sudo mkdir /mnt/raid10/Cloud
sudo chown www-data:www-data /mnt/raid10/Cloud
sudo chmod -R 755 /mnt/raid10/Cloud
```

In CasaOS, open the Nextcloud app settings, go to `Volumes`, and mount this directory into the container. I mapped it as `/media/Disk01` — leaving room to attach additional disks later.

![Defining a volume for Nextcloud in CasaOS](/images/df75f-ekran-goruntusu-2024-09-22-110442.png)

Save and restart. On the Nextcloud setup screen, after setting your username and password, open the **Storage & Database** section before clicking Install, select **MySQL/MariaDB**, and enter your database credentials.

After logging in, go to **Administration Settings** (top-right) → **Administration** in the left menu → **External Storage**. From here you can attach the RAID storage to Nextcloud.

![Attaching RAID storage to Nextcloud](/images/e41f4-ekran-goruntusu-2024-09-22-111741.png)

A personal cloud on the local network is now ready.

## Cloudflare Tunnel

The traditional approach to accessing a local machine from the internet is forwarding a port on your modem. That requires a static IP or DDNS, demands real effort to manage securely, and if your ISP puts you behind CGNAT it's simply not an option.

Cloudflare Tunnel solves this from a different angle: your device opens an outbound connection to Cloudflare's servers, and external traffic arrives through that connection. You don't open any ports — Cloudflare provides the tunnel.

Before starting, you'll need a domain with its nameservers pointed at Cloudflare.

Go to [https://dash.cloudflare.com](https://dash.cloudflare.com) and click **Zero Trust** in the left menu. (First-time use requires registration; the Free plan is sufficient for personal use.)

**Networks → Tunnels → Create a Tunnel.** Keep "Cloudflared" selected, give the tunnel a name, and save. On the "Choose your environment" step, select **Docker**.

You'll be given a command. I modified mine slightly:

```bash
docker run -d --name cloudflare_tunnel --restart always cloudflare/cloudflared:latest tunnel run --token [TOKEN]
```

I removed the `--no-autoupdate` flag and added `-d --name cloudflare_tunnel --restart always`. Don't share this command — it contains your token.

Once the container is up, your device will appear under "Connectors" in the Cloudflare interface. The next step is mapping a subdomain to a local IP and port, then clicking "Save Tunnel".

![Subdomain and port routing with Cloudflare Tunnel](/images/a6cf5-ekran-goruntusu-2024-09-22-115339.png)

You can route multiple domains through a single tunnel. To do that, go to **Zero Trust → Networks → Tunnels**, click "Configure" next to your tunnel, and under the **Public Hostname** tab use **Add a public hostname** to add new mappings.

### Exposing Nextcloud to the Internet

You've defined a public hostname for Nextcloud in the Cloudflare tunnel, but when you try to access that domain, Nextcloud will throw an untrusted domain error. To fix this, add the address to Nextcloud's trusted domains list:

```bash
sudo nano /DATA/AppData/nextcloud/var/www/html/config/config.php
```

Find the `trusted_domains` array and add your domain:

```text
'trusted_domains' => array(
  0 => '192.168.1.249',
  1 => 'nextcloud.muhammetsafak.com.tr'
),
```

Save the file (CTRL+O, CTRL+X) and restart Nextcloud from CasaOS. It will now be accessible from outside your network.

## Samba

CasaOS installs Samba as part of its setup. File sharing through the web interface takes a click or two — but there's a catch: it shares publicly to the entire local network by default. Since I didn't want that, I manage the Samba configuration manually. To avoid breaking CasaOS's own config and to keep my settings isolated from CasaOS updates, I use a separate file.

First, create a Samba user:

```bash
sudo smbpasswd -a [user_smb_username]
```

Create my own configuration file:

```bash
sudo nano /etc/samba/smb.home.conf
```

```text
[Cloud01]
        comment = Home Cloud 01
        path = /mnt/raid10/Cloud
        browseable = Yes
        read only = No
        guest ok = No
        public = No
        valid users = [user_smb_username]
        create mask = 0777
        directory mask = 0777
        force user = www-data
```

A few key fields in this configuration:

- `[Cloud01]`: The share name. Accessible as `\\192.168.1.249\Cloud01`.
- `path`: The directory being shared.
- `read only = No`: Users can read, write, and delete.
- `guest ok = No` / `public = No`: Only defined users can access it.
- `valid users`: Samba users permitted to connect.
- `force user = www-data`: All operations run under the `www-data` account, keeping file ownership consistent with Nextcloud.

Include this configuration in the main Samba config:

```bash
sudo nano /etc/samba/smb.conf
```

Add the following at the very end of the file (since the included file declares its own `[Cloud01]` section, it doesn't matter which section the line lands after):

```text
include=/etc/samba/smb.home.conf
```

Restart Samba:

```bash
sudo systemctl restart smbd
```

---

Setup complete. Additional applications on CasaOS — download managers, ad-blocking DNS, and more — can be installed with a single click. Assembling the hardware took about an hour and a half; writing this post took two days. Hopefully, for you, this reverses that ratio.
