Assemble the Hardware
~5 minutesFirst, let's make sure you have everything. Check off each item as you go:
Once you have everything:
- Attach the NVMe SSD to the NVMe HAT/Base board — it clicks into the M.2 slot at an angle, then press down and screw it in.
- Connect the HAT to the Pi 5 — plug in the flat ribbon cable to the PCIe connector on the underside of the Pi.
- Insert the MicroSD card into the Pi's card slot (we'll flash it in the next step).
- Don't power it on yet — we need to flash the OS first.
Flash the Operating System
~10 minutesWe need to install Raspberry Pi OS on the MicroSD card. This is what powers your Pi.
- Download and install Raspberry Pi Imager on your computer (Mac, Windows, or Linux).
- Open the Imager and configure these settings:
- Before writing, click the gear icon (⚙️) or "Edit Settings" and configure:
ughstorage
pi
- Click Write and wait for it to finish (~5 min).
- Put the MicroSD card back into the Pi and plug in the power supply.
- Wait ~2 minutes for the Pi to boot up for the first time.
SSH into the Pi
~2 minutesSSH (Secure Shell) lets you control the Pi from your computer's terminal. Think of it as a remote control for the command line.
On Mac: Open Terminal (search Spotlight for "Terminal").
On Windows: Open PowerShell (search Start for "PowerShell").
Type this command and press Enter:
$ ssh pi@ughstorage.local
Enter the password you set in Step 2 when prompted. You should see a welcome message and a command prompt like pi@ughstorage:~ $
ssh pi@raspberrypi.local— if you didn't change the hostname- Check your router's admin page for the Pi's IP address, then use
ssh pi@<IP_ADDRESS> - Make sure the Pi has been powered on for at least 2 minutes
- Ensure your computer is on the same WiFi network as the Pi
Partition & Format the NVMe SSD
~5 minutesYour NVMe SSD is a blank drive right now. We need to partition it (tell the system to use the whole drive as one big space) and format it (prepare it to store files). This is like formatting a USB drive — but bigger.
4a. Verify the Pi sees your SSD
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
mmcblk0 179:0 0 29.7G 0 disk
├─mmcblk0p1 179:1 0 512M 0 part /boot/firmware
└─mmcblk0p2 179:2 0 29.2G 0 part /
nvme0n1 259:0 0 931.5G 0 disk
You should see nvme0n1 in the list — that's your SSD. The size should match what you bought (e.g., ~931GB for a 1TB drive).
4b. Create a partition
$ sudo fdisk /dev/nvme0n1
This opens an interactive partition tool. Type these keys one at a time, pressing Enter after each:
4c. Format the partition
$ sudo mkfs.ext4 /dev/nvme0n1p1
This formats the partition with the ext4 filesystem — the standard Linux format. It's reliable, fast, and handles large files perfectly. This may take 10–30 seconds depending on drive size.
nvme0n1 is the whole drive. nvme0n1p1 is the partition we just created on it (partition 1). From now on, we'll always use nvme0n1p1.
Mount the SSD
~2 minutesMounting means connecting the SSD to a folder so the system can read and write files to it. Think of it like plugging in an external hard drive — except we tell Linux exactly where to "plug it in."
5a. Create the mount point and mount
$ sudo mkdir -p /mnt/nvme
$ sudo mount /dev/nvme0n1p1 /mnt/nvme
$ sudo chown pi:pi /mnt/nvme
Here's what each line does:
mkdir -p /mnt/nvme— Creates the folder/mnt/nvmewhere the SSD will be accessiblemount— Connects the formatted partition to that folderchown pi:pi— Gives your user account permission to read/write files on the SSD
5b. Make it permanent (auto-mount on boot)
Without this step, the SSD would disconnect every time the Pi restarts. This command adds it to the system's startup list:
$ echo '/dev/nvme0n1p1 /mnt/nvme ext4 defaults,noatime 0 2' | sudo tee -a /etc/fstab
5c. Verify everything worked
$ df -h /mnt/nvme
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p1 916G 28K 870G 1% /mnt/nvme
You should see your drive's full capacity. The "Avail" column is your usable storage space.
Install UghStorage
~5 minutesNow for the good part — installing the UghStorage server software. This is a single script that handles everything automatically.
$ cd /home/pi
$ git clone https://github.com/hneogy/ughstorage.git
$ cd ughstorage/server
$ chmod +x setup.sh ble_setup_service.sh
$ ./setup.sh
The setup script runs 6 steps automatically. Here's what it's doing behind the scenes:
Installs Python 3, pip, and FFmpeg (for generating video thumbnails)
Downloads the Cloudflare Tunnel binary — this is what makes your Pi accessible from anywhere without opening ports
Creates an isolated Python environment and installs all server dependencies
Creates /mnt/nvme/storage and /mnt/nvme/thumbnails on your SSD
Generates the .env file with pre-configured cloud connection settings
Creates a background service so the server starts automatically whenever the Pi boots
============================================
UghStorage Setup (v2 - Multi-Tenant)
============================================
[1/6] Installing system dependencies...
[2/6] Installing cloudflared...
cloudflared installed: 2025.x.x
[3/6] Creating Python virtual environment...
Installed Python packages.
[4/6] Creating storage directories...
/mnt/nvme/storage
/mnt/nvme/thumbnails
[5/6] Configuring environment...
Environment saved to /home/pi/ughstorage/server/.env
[6/6] Creating systemd service...
Service installed: ughstorage
============================================
Setup complete!
============================================
Install Bluetooth Service
~2 minutesThis script sets up Bluetooth Low Energy (BLE) so the UghStorage iPhone app can find your Pi wirelessly and configure it — no cables or keyboard needed.
$ sudo bash ble_setup_service.sh
Here's what this script configures:
Installs BlueZ (the Linux Bluetooth stack), Pi-specific Bluetooth drivers, and the dbus-next Python library
Switches WiFi management from the basic dhcpcd to NetworkManager, which allows the app to scan and connect to WiFi networks remotely
Creates the ughstorage-ble systemd service that runs on boot and advertises the Pi as "UghStorage-Setup" over Bluetooth
[INFO] ==========================================
[INFO] UghStorage BLE Setup Installer
[INFO] ==========================================
[INFO] Updating package lists...
[INFO] Installing Bluetooth and NetworkManager packages...
[INFO] Installing Python dependencies...
[INFO] Dependencies installed.
[INFO] Configuring NetworkManager...
[INFO] NetworkManager is active.
[INFO] Configuring Bluetooth...
[INFO] Bluetooth configured.
[INFO] Config directory ready at /etc/ughstorage
[INFO] Creating systemd service: ughstorage-ble...
[INFO] Service created and started.
[INFO] ==========================================
[INFO] Installation complete!
[INFO] ==========================================
ssh pi@ughstorage.local.
Start & Verify
~2 minutesLet's start the server and make sure everything is running properly.
8a. Start the server
$ sudo systemctl start ughstorage
8b. Check the status
$ sudo systemctl status ughstorage
● ughstorage.service - UghStorage personal cloud storage
Loaded: loaded (/etc/systemd/system/ughstorage.service; enabled)
Active: active (running) since ...
Main PID: 1234 (python3)
Tasks: 3 (limit: 4915)
CPU: 1.234s
CGroup: /system.slice/ughstorage.service
└─1234 /home/pi/ughstorage/server/venv/bin/python3 -m uvicorn main:app ...
Look for "active (running)" — that means the server is up and healthy.
8c. Quick health check
$ curl http://localhost:8000/health
{"status": "ok", "version": "1.0.0", ...}
Download the App & Connect
~3 minutesThe hard part is done! Now grab your iPhone and let the app do the rest.
- Download UghStorage from the App Store Coming Soon
- Create an account in the app
- Tap "Add Device" to start the setup wizard
The app will walk you through three automatic steps:
Find Your Pi
The app scans for Bluetooth devices and discovers your Pi as "UghStorage-Setup". Tap to connect.
Connect to WiFi
Select your home WiFi network and enter the password. The Pi connects automatically.
Register & Go Live
The app registers your Pi, provisions a secure Cloudflare Tunnel, and you're live at *.ughstorage.com.
Troubleshooting
Common issues & fixesMake sure you're within ~10 feet of the Pi and Bluetooth is enabled on your iPhone (Settings → Bluetooth). On the Pi, check the BLE service status:
$ sudo systemctl status ughstorage-ble
$ sudo systemctl restart ughstorage-ble
The NVMe HAT ribbon cable may not be fully seated. Power off the Pi, disconnect the cable, and reconnect it firmly on both ends. Also ensure the SSD is clicked into the M.2 slot and screwed down. Some NVMe HATs require a specific orientation — check the HAT's documentation.
Check both the tunnel and the server:
$ sudo systemctl status cloudflared
$ sudo systemctl status ughstorage
$ curl http://localhost:8000/health
$ journalctl -u ughstorage -n 20
Double-check the WiFi password. Make sure the Pi is within range of your router. You can also check what networks the Pi can see:
$ nmcli device wifi list
Yes! Your files are stored on the NVMe SSD and won't be lost during a power outage. When power returns, all three services (ughstorage, ughstorage-ble, and cloudflared) start automatically within ~60 seconds. No manual intervention needed.