# Self-hosted Google Photos by Immich

I've been hosting my Kubernetes cluster in the cloud for a while, but recently I managed to get my hands on a bare-metal server — a **Dell PowerEdge with 32 CPU cores and 128GB RAM** 😮 — and set it up in my basement. Naturally, I turned it into a Kubernetes node.

# Problem

In our household, we have multiple Android and iPhone devices filled with photos and videos. Since we don’t want to pay for cloud services like iCloud or Google Photos, our media library has always been at risk. If a device breaks or gets lost, years of memories disappear with it.

Now that I have a powerful home Kubernetes cluster running, I decided to finally solve this problem.

# Solution

## Immich for Photo & Video Backup

After researching self-hosting options, I discovered an amazing open-source project called [**Immich**](https://github.com/immich-app/immich).

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1765483081510/bfcaec11-add4-4c9c-b7a0-1e075fedb6d5.png align="center")

I chose Immich because:

* It has official **mobile apps** and a **web interface**
    
* Supports **facial recognition**, **OCR**, and **multi-user** features
    
* Has a strong community (over **86k GitHub stars**)
    
* Easy enough that non-technical family members can use it
    

We installed the Immich app on our phones and connected it to the Immich server running inside our private network.

## (Optional) External Backup to AWS S3 Using Restic

There was still one more risk:  
If our home server or NAS disk failed, all our backups would be gone.

To protect against that, I set up an additional off-site backup to **AWS S3** using an open-source tool called [**Restic**](https://github.com/restic/restic).

Restic tracks backup folders and database dumps, then **incrementally uploads** them to S3. Since I store everything in **S3 Glacier Flexible Retrieval**, the cost is extremely low.

* **S3 Glacier (us-east-1): $0.0036 per GB**
    
* That’s **$3.60/month for 1 TB** of data — super affordable.
    

# Deployment

Immich requires **PostgreSQL**, **Redis**, and its **machine-learning services**. I also added Restic backup Jobs/CronJobs.

I prepared a full **Kubernetes manifest** for this setup:

👉 **YAML file:**  
[https://gist.github.com/devsteppe9/17b83f51ca05c5012632d32c5e42cea5](https://gist.github.com/devsteppe9/17b83f51ca05c5012632d32c5e42cea5)

Before applying it, update the following depending on your environment:

* **PersistentVolume paths** (if using local storage or NAS)
    
* **External Postgres/Redis URLs** (if you already run those separately)
    

Then simply apply:

```bash
kubectl apply -f FILENAME.yaml
```

Once deployed, Immich is ready to use. The first user to register will be the admin user. The admin user will be able to add other users to the application.

To register for the admin user, access the web application at `http://< ip-address>:2283` and click on the **Getting Started** button.

The mobile app can be downloaded from the following places:

* Obtainium: You can get your Obtainium config link from the [Utilities page of your Immich se](https://my.immich.app/utilities)[rver.](https://my.immich.app/utilities)
    
* [Google Pl](https://my.immich.app/utilities)[ay Store](https://play.google.com/store/apps/details?id=app.alextran.immich)
    
* [App](https://play.google.com/store/apps/details?id=app.alextran.immich)[le App](https://apps.apple.com/us/app/immich/id1613945652) [Store](https://f-droid.org/packages/app.alextran.immich)
    
* [F-Droid](https://f-droid.org/packages/app.alextran.immich)
    
* [G](https://github.com/immich-app/immich/releases)[it](https://github.com/immich-app/immich/releases)[Hub Releases (apk)](https://my.immich.app/utilities)[On the mobile](https://play.google.com/store/apps/details?id=app.alextran.immich) [app, ju](https://apps.apple.com/us/app/immich/id1613945652)[st ente](https://f-droid.org/packages/app.alextran.immich)[r](https://apps.apple.com/us/app/immich/id1613945652) your Immich [URL, username, and pa](https://github.com/immich-app/immich/releases)ssword — and start [backing up!](https://my.immich.app/utilities)
    

After uploading our media to Immich, we ended up with approximately 160GB of data. With the Kubernetes configuration mentioned above, Restic initializes and uploads the data to AWS S3, and I can confirm that it has been successfully transferred

```bash
➜  ~ kubectl logs restic-init-4trwh
Initializing restic repository...
open repository
no parent snapshot found, will read all files
load index files
start scan on [/data]
start backup on [/data]
scan finished in 2.639s: 17108 files, 157.909 GiB

Files:       17108 new,     0 changed,     0 unmodified
Dirs:        16615 new,     0 changed,     0 unmodified
Data Blobs:      0 new
Tree Blobs:      0 new
Added to the repository: 0 B   (0 B   stored)

processed 17108 files, 157.909 GiB in 21:04
snapshot 560b0e01 saved
```

And let’s confirm from AWS S3:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1765483649700/e1704b4a-75d1-42a0-8e45-584688a36b53.png align="center")

Like this, relic tracks my filesystem and uploads any new or changed files to S3 every day

# [Su](https://my.immich.app/utilities)[mma](https://play.google.com/store/apps/details?id=app.alextran.immich)[ry](https://my.immich.app/utilities)

[By self-hostin](https://my.immich.app/utilities)[g](https://play.google.com/store/apps/details?id=app.alextran.immich) [Immich on my home Kubernetes](https://my.immich.app/utilities) [cluster and op](https://play.google.com/store/apps/details?id=app.alextran.immich)[tionall](https://apps.apple.com/us/app/immich/id1613945652)[y backi](https://f-droid.org/packages/app.alextran.immich)[n](https://apps.apple.com/us/app/immich/id1613945652)[g up everything to AWS S3, we now](https://github.com/immich-app/immich/releases) have:

* A safe private photo/video library
    
* Control of our own data
    
* Off-site backups in case the home server dies
    

I hope this setup inspires you! If you have your own self-hosting solution or ideas, feel free to share them
