← All projects / Self-Hosted Media + Photos
Live · photo backup in progress

Self-Hosted Media + Photos

A private streaming service and a photo backup that live on my own hardware. Family asks for a movie; it appears in the living room an hour later, no streaming-service hopping required.

Docker + Tailscale Live UGREEN NAS 7 services
What is this?

A small home server that does two things. One: replaces the streaming-service shuffle with a single Plex library that pulls in whatever the family asks for. Two: replaces Google Photos with a photo backup that lives on my hardware, not someone else's cloud, and that I can reach from anywhere via a private VPN.

Who it's for

Households tired of paying four streaming subscriptions to watch three shows, and anyone uneasy about a single company holding their entire photo history. This isn't an AI project, but it's the same operator pattern: chain best-in-class open-source tools together so the household never sees the plumbing.

Hardware
UGREEN NAS @ 192.168.4.61
Storage
10.7 TB free for media
Services
7 containers running
Remote access
Tailscale (no port forwarding)
7
Docker services
10.7TB
Storage available
0
Public ports
1 tap
User experience
Walk through the build

From bare NAS to one-tap streaming

Step 1 of 5

Plex baseline · Mac

Host192.168.4.53
Library sizeempty
TV readyyes
Consumer surface ✓
Step 1 · Plex first

Get the consumer surface working

Plex on a Mac with library pointed at empty folders. The consumption surface comes first, without a working Plex, nothing else has anywhere to feed.

Plex
Drop a Docker compose screenshot here UGREEN's container manager showing Radarr / Sonarr / qBittorrent green.
Step 2 · *arr stack

Radarr / Sonarr / qBittorrent in Docker

All three deployed via Docker Compose on the UGREEN NAS. Each gets its own port and root folder (/movies, /tv). qBittorrent gets credentials and a download category mapping so Radarr and Sonarr don't step on each other.

Docker Compose

Overseerr · request flow

1. Search title"Severance"
2. Tap Request→ Sonarr
3. qBittorrent downloadsautomatically
4. Renamed + filed/tv/Severance
5. In Plex~1 hour
No terminal touched
Step 3 · Overseerr as the front door

Netflix-style UI in front of *arr

Overseerr on port 5055 talks to Radarr, Sonarr, and Plex via API keys. The end-user surface is "search → request", they never see the *arr UIs, never touch a torrent client, never rename a file.

Overseerr REST APIs

Tailscale · ugreen-nas

Public ports opened0
Devices on Tailnet5
iPhone accessanywhere
Family devicesapproved only
VPN, not port-forwarding
Step 4 · Tailscale

Remote access without exposing anything

Tailscale on the NAS as ugreen-nas. All services reachable from any device on my Tailnet without opening a single port to the internet. iPhone gets full home-network access remotely; security model stays tight.

Tailscale Wireguard
📷 Drop an Immich screenshot here The Immich photo grid would close out the journey nicely.
Step 5 · Immich

Self-hosted Google Photos replacement

Compose deployed at :2283. Plan: iPhone app for automatic backup, Google Takeout dump as an External Library (no duplication), eventual full Google Photos exit.

Immich Self-hosted

The goal

I wanted to leave Google Photos and stop renting media from streaming services that lose titles every quarter. The requirements: request → automatic download → in Plex with metadata, no terminal touches; photo backup from iPhone with the Google Photos UX but on my hardware; remote access from outside the house without exposing anything to the public internet.

This isn't an AI project per se, but it's the same operator pattern as everything else I build: chain together best-in-class open-source pieces, keep them inspectable, automate the boring work, and only pay for the thin layer that makes them feel cohesive.

Home Stack a glimpse
Plex Media Server
● Running
Mac · 192.168.4.53
Overseerr
● :5055
request UI
Radarr
● :7878
movies → /movies
Sonarr
● :8989
TV → /tv
qBittorrent
● :8888
downloader
Tailscale
● ugreen-nas
remote VPN
Immich
● :2283
photo backup
Volume
10.7 TB free
/volume1

The flow

The user surface is exactly one tap. Open Overseerr (locally or via Tailscale), search for a movie or show, hit Request. Behind the scenes:

Overseerr (request)
    ↓
Radarr / Sonarr (find + queue)
    ↓
qBittorrent (download)
    ↓
Radarr / Sonarr (rename + move to /movies or /tv)
    ↓
Plex (auto-scan + metadata)
    ↓
You watch it on the TV.

The process

Step 1 · Plex baseline

Get the *consumer* surface working first

Plex on a Mac at 192.168.4.53, library pointed at empty folders on the NAS. The consumption surface comes first, without a working Plex, the rest of the stack has nothing to feed.

Step 2 · *arr stack in Docker

Radarr / Sonarr / qBittorrent

All three deployed via Docker Compose on the UGREEN NAS. Each gets its own port and its own root folder (/movies, /tv). qBittorrent gets credentials and a download category mapping so Radarr and Sonarr can hand work off without stepping on each other.

Step 3 · Overseerr as the front door

Netflix-style UI in front of *arr

Overseerr on port 5055 talks to Radarr, Sonarr, and Plex via API keys. End-user surface is "search → request" , they never see the *arr UIs, never touch a torrent client, never rename a file.

Step 4 · Tailscale for remote access

VPN, not port forwarding

Tailscale on the NAS as ugreen-nas. Now all services are reachable from any device on my Tailnet without opening a single port to the internet. iPhone gets full home-network access remotely. Security model stays tight.

Step 5 · Immich for photos

Self-hosted Google Photos replacement

Compose deployed at :2283. Plan: iPhone app for automatic backup, Google Takeout dump added as an External Library (no duplication), eventual full Google Photos exit.

Hiccups (and what I learned)

Hiccup #1 · Docker on UGREEN can't see /home

I tried to mount a volume from /home/ShadoWing1128/Photos for Immich. Container couldn't see it, UGREEN's Docker can't access personal user home folders.

All Docker volume mounts must use /volume1/ paths. Corrected Immich's upload path to /volume1/Photos/Immich. Lesson: every NAS vendor has its own Docker filesystem quirks; check before assuming Linux conventions hold.

Hiccup #2 · "Allow media deletion" missing

Spent 20 minutes looking for the Plex media-deletion toggle under Settings → Troubleshooting (where it used to be).

In newer Plex versions the toggle moved to Settings → Library. Wrote it down in the project notes so it doesn't bite me again, and so the same thing doesn't slow down anyone else trying to stand up a similar stack.

Hiccup #3 · OverseerrTV mobile app needed an API key

The native iPhone OverseerrTV app couldn't connect to my server, wanted an API key I didn't know existed.

Pulled the key from Overseerr's Settings → General → API Key, then connected. Now I can request from my phone like any streaming app. The lesson: every self-hosted service has at least one "obvious in retrospect" config step that isn't in the README.

Hiccup #4 · Sonarr Language Profile deprecation warning

Overseerr threw a yellow Language Profile deprecation warning every time I requested a TV show. Looked like a real failure.

Pure cosmetic, Sonarr removed Language Profiles in a recent version, Overseerr hasn't caught up. Ignored. The lesson: not every red-or-yellow string is a real problem; treat warnings as data, not commands.

Tools used

UGREEN NAS
hardware host
Docker / Compose
service runtime
Plex
media server + UI
Radarr
movie automation
Sonarr
TV automation
qBittorrent
download client
Overseerr
request front-end
Tailscale
remote access VPN
Immich
photo backup
OverseerrTV (iOS)
mobile request UI

Roadmap

  • NEXT
    Confirm Immich is live.

    Verify http://192.168.4.61:2283 is up after the /volume1/ path fix. Install iPhone app, enable automatic backup.

  • NEXT
    Google Takeout as External Library.

    Add the historical Google Photos dump to Immich as an External Library, no duplication, no re-import, just indexed.

  • v2
    Reverse proxy + custom domain.

    Caddy or Traefik in front of the stack. Replace bare IPs and ports with plex.home.lan, overseerr.home.lan, etc. Nicer URLs, free TLS, easier to share with family.

  • v2
    Off-site backup of the photo library.

    Encrypted Backblaze B2 nightly snapshot of /volume1/Photos. Belt-and-suspenders for the irreplaceable data.

  • LATER
    Home Assistant on the NAS.

    Same Docker host, same Tailscale exit. Smart-home control rolls into the same operator surface.

  • LATER
    Local LLM container alongside the stack.

    An Ollama container on the NAS for always-on local inference, queryable from any device on the Tailnet.


← Back to all projects