← Previous Post Categories Next Post →

[93] - 08.05.2026 - Bye bye Google Photos, you won't be missed
Permanent link
hardware guide 


This blog post isn't a detailed step by step guide, as there are countless ways of achieving sovereignty over your photos.
My goal is to outline the most important steps and my personal learnings, in order to provide you with the knowledge & the motivation you will need to do the same.

Table of contents



Motivation

Your Photos Stay Yours

Photos contain personal information: faces, locations, relationships, travel history, you name it. Uploading them to cloud services such as Google Photos means you are trusting a third party with some of your most sensitive files..
However, with a self-hosted approach:

Protection Against AI and Generative Model Usage

Cloud platforms increasingly use AI for face recognition, object detection, search, and automated organization. Even if providers claim not to directly train public AI models on your photos, policies and data practices can change over time.

Your image library is valuable AI training data, self-hosting solves this issue as Immich (more on this later) runs image recognition locally, on your own hardware.

Avoiding Vendor Lock-In

Cloud photo platforms are designed to keep users inside their ecosystem. Over time, exporting large libraries along with albums, edits, and metadata becomes difficult and time-consuming.
With self-hosting:

Requirements

Note: I won't recommend any specific software, vendor or product. I am solely sharing my decision process as I highly suggest everyone to do research based on their own specific needs and abilities.

Time

I have spent a lot of time until everything was running how I envisioned it. Please don't think you can simply order the parts and be done after 2-3 hours.
In retrospect, it was worth every single minute as I learned a lot and got a big piece of mind by finally owning my own photos.
Protip: Use the money that you save by not paying Google to pay yourself for the time setting this up and maintaining it ;)

Space

When looking for the right place in your home, please consider the following things: The optimal solution for me was the cellar, there isn't anyone being bothered by the noise and the ambient temp is pretty cool. Just make sure the humidity of your cellar is within operating specs of your equipment.

NAS

Lets start with the NAS (network attached storage), the hardware where our Immich service will be hosted.
I chose the UGREEN DXP4800 Plus as it fulfills all of my requirements: I added another 8 GB of RAM (16 GB in total) to ensure I had enough left for some other use cases running on the NAS.

Harddrives

I chose two WD Red Plus 12TB drives as they have a pretty low defect rate as well as a competitive price.
Note: Be aware that using RAID has an influence on your total available capacity.

Networking Equipment

Switch

I opted for the UniFi Flex Mini 2.5G as it is the cheapest 2.5G switch from a reputable brand that I could find. Since solely the NAS and a RasperryPi are using the switching fabric, it should be plenty powerful for now.

Cables

I wired up everything using CAT 6A cables, which means I will be ready for when I want to upgrade my other equipment to 10G.
Having to crimp your own cables is nostalgic at best, but it is a good way to save some money as well as allowing you to route cables through tight spaces / other rooms.

UPS

Even though the power grid here is very stable, having a UPS for an always on system is an absolute no-brainer.
It serves the following functions: I opted for a cheap UPS from a reputable brand, connected it through USB and setup the UPS configuration in TrueNAS.
Now I receive an email notifications (thanks HexOS) should the UPS kick in and when power is restored.

Software

OS

I opted for HexOS which is a "UI wrapper" around TrueNAS, making it way easier to setup, configure and maintain. You might say that this isn't quite the spirit of full control, but I have enough trust in that company and this made things a lot less complicated.

Photos

Immich is open source and does everything I need (image recognition, mobile apps, nice UI).

Remote Access

Since I didn't want my Immich instance reachable to the whole internet, I opted to use Tailscale.

Offsite Backup Location

In the case that the both harddrives (RAID 1) should die at the same time (stroke of fate, fire, water, etc.), I needed an offsite location for the photos.
I ended up going for a Hetzner Storage Box, the reasons are straightforward: SSH access, European company, servers in Europe and fairly priced. You will find the backup approach I used in detail under "Maintenance".

Now you might say, "hey, now your photos are back in the cloud || under someone elses control". The backups are fully encrypted and with the big difference that I can actually validate this on my own, which isn't possible for any service being sold to you as being "end-to-end encrypted".

Installation

NAS

The first part was the easy, tangible part: unpack the NAS, add the extra RAM, and insert the disks.
After that, I inserted a USB drive loaded with the HexOS installer preloaded and followed their user guide.
Protip: Go to the UGREEN bios and disable their watchdog first, as otherwise your NAS will reboot every 3 minutes.

One reason I chose HexOS instead of building a pure TrueNAS setup from scratch is that HexOS is designed to validate hardware, partition the system, and get you into a usable dashboard quickly while still sitting on top of TrueNAS underneath.
Immich was the main reason I built this in the first place. HexOS now supports curated app installs, and Immich is on that curated list, which meant I did not have to manually compose every container, port, mount, and permission from scratch. HexOS’s install-script system is explicitly built to preconfigure networking, folders, storage paths, and resources using opinionated best-practice templates, and the Immich script creates dedicated locations for photo data and database storage while exposing the web interface on port 2283.
One click and waiting a few seconds is all you need to do until you are greeted by Immichs setup-guide.

The same goes for Tailscale, simply go to the app "store" and install it.

Network

Solely two things were required, configuring a fixed IP for the NAS and opening & forward UDP port 41641 for tailscale.

Smartphone(s)

Once the server side was working, the phone setup was pleasantly simple.
First, I installed Tailscale on the phone and signed it into the same tailnet. Tailscale supports iOS and Android directly from the App Store and Google Play, and once a device joins the tailnet it gets the same private-network treatment as everything else: its own address, its own identity, and the ability to reach other approved devices securely.
Then I installed the Immich mobile app. Immich’s own mobile docs say the app signs into a server endpoint URL, and that is exactly what I used: the NAS over Tailscale instead of a public domain. In practice, that meant I could point the mobile app at the NAS’s Tailscale address and keep the whole thing private. That is not a separate Immich feature so much as a nice consequence of combining Immich’s endpoint-based mobile login with Tailscale’s private networking.

The last thing is to check if the connection to your NAS is direct or going through peer relay nodes (see "Network" chapter):

Migration

The basic flow is straightforward. Google’s supported way to get your photo library out is Google Takeout: select the Google Photos data you want, create an export archive, and download it. That process does not delete anything from Google by itself, it simply gives you a copy of your data so you can keep it, archive it, or move it somewhere else.

From there, the goal was to get the archive into Immich. Immich’s own CLI can upload photos and videos to an Immich server, the photos will be sorted based on their EXIF data, simple as can be.

Backups

A self-hosted photo library is only as good as its backup story, and this is the part I tried to keep as simple as possible.

Immich itself is very clear about the separation between metadata and files. Its quick-start documentation warns that the built-in database backup only covers metadata and user information, while the actual images and videos in `UPLOAD_LOCATION` still need manual backup.

My offsite target is a Hetzner Storage Box. As the Storage Box supports connecting through SSH and my last bash script I wrote by hand is from 2024, I vibecoded the following restic script to do my nightly backup to the offsite location:

#!/bin/bash

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)"

# -------------------------
# CONFIGURATION
# -------------------------
SOURCE_DIR="/mnt/immich"
TARGET_REPO="/mnt/storagebox/immich"
RESTIC_PASSWORD="$(< "$SCRIPT_DIR/restic_pass")"

# -------------------------
# EXPORT ENVIRONMENT
# -------------------------
export RESTIC_REPOSITORY="$TARGET_REPO"
export RESTIC_PASSWORD="$RESTIC_PASSWORD"

# -------------------------
# FUNCTION TO CHECK LAST COMMAND STATUS
# -------------------------
check_status() {
    if [ $? -eq 0 ]; then
        echo "✅ $1"
    else
        echo "❗ $1"
        exit 1
    fi
}

# -------------------------
# CHECK IF RESTIC INSTALLED
# -------------------------
if ! command -v restic &> /dev/null; then
    echo "❗ Restic is not installed. Please install it first."
    exit 1
else
    echo "✅ Restic is installed"
fi

# -------------------------
# PRE-RUN CHECK: IS SOURCE MOUNTED?
# -------------------------
if mountpoint -q "$SOURCE_DIR"; then
    echo "✅ $SOURCE_DIR is already mounted"
else
    echo "$SOURCE_DIR is not mounted. Attempting to mount..."
    "$SCRIPT_DIR/mnt" immich
    check_status "Mounting $SOURCE_DIR"
fi

if mountpoint -q "$TARGET_REPO"; then
    echo "✅ $TARGET_REPO is already mounted"
else
    echo "$TARGET_REPO is not mounted. Attempting to mount..."
    "$SCRIPT_DIR/mnt" storagebox
    check_status "Mounting $TARGET_REPO"
fi

# -------------------------
# INITIALIZE REPOSITORY (if not already)
# -------------------------
if [ ! -f "$TARGET_REPO/config" ]; then
    echo "Initializing restic repository at $TARGET_REPO..."
    restic init
    check_status "Restic repository initialized"
else
    echo "✅ Restic repository already exists"
fi

# -------------------------
# PERFORM BACKUP
# -------------------------
echo "Backing up $SOURCE_DIR to $TARGET_REPO..."
restic backup "$SOURCE_DIR"
check_status "Backup completed"

# -------------------------
# KEEP MAX 10 SNAPSHOTS
# -------------------------
echo "Pruning old snapshots, keeping only the last 10..."
restic forget --keep-last 10 --prune
check_status "Old snapshots pruned"

# -------------------------
# VERIFY BACKUP
# -------------------------
echo "Verifying backup snapshots..."
restic snapshots
check_status "Snapshots verification done"

echo "✅ Backup complete and encrypted!"


Conclusion

That combination of local storage that I own, private remote access through Tailscale and an offsite backup is what finally made the setup feel complete.
My photos are not magically safer just because they live on a NAS now. They are safer because I know where they are, how they are accessed, and how they are backed up.

Would I recommend you to do the same? Absolutely, even if you lack the skills for any of the specific steps required, there are plenty of great resources online, as ultimately your freedom is priceless.



← Previous Post Categories Next Post →

First, solve the problem. Then, write the code.Privacy Policy