Phase 8 — Immich Photo Server
Goal: Set up Immich as a self-hosted Google Photos replacement — giving you and Ahana a beautiful, searchable photo library with face recognition, object search, map view, and sharing, all running on your own infrastructure.
Time estimate: 2–3 hours
What you need: Mini PC running Windows with Docker Desktop,
UNAS2 accessible at 192.168.1.2, Phase 5 complete (existing
Docker stack running)
Prerequisites: Phase 5 complete, Photos_Bipin and
Photos_Ahana populated on UNAS2
Why Immich Instead of Jellyfin for Photos
Jellyfin is a media server built for movies and music — it handles photos but the experience is basic. Immich is built exclusively for photos and videos. The difference in day-to-day use is significant:
| Feature | Jellyfin | Immich |
|---|---|---|
| Face recognition | ❌ No | ✅ Yes — automatic |
| Object/scene search | ❌ No | ✅ Yes — "show me beach photos" |
| Map view | ❌ No | ✅ Yes — photos on a world map |
| Mobile app (iOS + Android) | ✅ Basic | ✅ Excellent — Google Photos feel |
| Sharing albums | ❌ Limited | ✅ Full share links, expiry, password |
| Memory view (On This Day) | ❌ No | ✅ Yes |
| Duplicate detection | ❌ No | ✅ Yes |
| Folder-based albums | ❌ No | ✅ Via folder album creator |
Architecture For Your Setup
UNAS2 (storage)
├── Photos_Bipin/ ← mounted read-only into Immich
│ ├── Camera/ ← FolderSync daily backup (unchanged)
│ ├── Photos from 2021/
│ └── ...
└── Photos_Ahana/ ← mounted read-only into Immich
└── Camera/ ← PhotoSync backup (unchanged)
Mini PC (compute)
└── Immich Docker stack
├── immich-server (port 2283)
├── immich-machine-learning
├── PostgreSQL (local SSD only — not on NAS)
├── Redis / Valkey
└── immich-folder-album-creator
Phone backup stays exactly as configured in Phase 3: FolderSync (Android) and PhotoSync (iPhone) continue syncing to the NAS as before. Immich scans those folders nightly as External Libraries and picks up new photos automatically. No change to your existing backup flow — Immich is a viewer and organiser on top of what you already have.
Why keep FolderSync/PhotoSync instead of the Immich mobile app? Immich's mobile app uploads to an internal folder that cannot be redirected to your existing NAS folder structure. Keeping FolderSync/PhotoSync means new photos land in
Photos_Bipin/CameraandPhotos_Ahana/Camera— the same place your historical photos are — keeping everything in one consistent structure that Immich then indexes.PostgreSQL cannot run on a network share. The Immich database must live on the mini PC's local SSD. Only photos and uploads live on the NAS.
Step 1 — Create Immich Folder Structure on Mini PC
mkdir C:\docker\immich
mkdir C:\docker\immich\library
mkdir C:\docker\immich\postgres
mkdir C:\docker\immich\model-cache
Step 2 — Create the Environment File
Create C:\docker\immich\.env with the following content:
# Upload location — where Immich stores new photos uploaded
# directly via web or mobile app
UPLOAD_LOCATION=C:\docker\immich\library
# Database location — MUST be on local SSD, not network share
DB_DATA_LOCATION=C:\docker\immich\postgres
# Immich version — pin to v2 for stability
IMMICH_VERSION=v2
# Database credentials — change DB_PASSWORD to something secure
DB_PASSWORD=changethis_to_secure_password
DB_USERNAME=immich
DB_DATABASE_NAME=immich
# Timezone
TZ=Asia/Kolkata
Change DB_PASSWORD to a strong random password using only letters and numbers (A-Za-z0-9) — avoid special characters as Docker may misparse them. Save it in your password manager.
Step 3 — Create the Docker Compose File
Create C:\docker\immich\docker-compose.yml:
name: immich
services:
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
restart: always
ports:
- "2283:2283"
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- /etc/localtime:/etc/localtime:ro
- "P:/:/mnt/photos-bipin:ro"
- "Q:/:/mnt/photos-ahana:ro"
env_file:
- .env
depends_on:
- redis
- database
healthcheck:
disable: false
immich-machine-learning:
container_name: immich_machine_learning
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
restart: always
volumes:
- C:\docker\immich\model-cache:/cache
env_file:
- .env
healthcheck:
disable: false
redis:
container_name: immich_redis
image: docker.io/valkey/valkey:8-bookworm
restart: always
healthcheck:
test: redis-cli ping || exit 1
database:
container_name: immich_postgres
image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0
restart: always
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
POSTGRES_INITDB_ARGS: "--data-checksums"
volumes:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
healthcheck:
test: >-
pg_isready --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}"
|| exit 1; Chksum="$$(psql --dbname="$${POSTGRES_DB}"
--username="$${POSTGRES_USER}" --tuples-only --no-align
--command='SELECT COALESCE(SUM(checksum_failures), 0)
FROM pg_stat_database')"; echo "checksum failure count=$${Chksum}";
[ "$${Chksum}" = '0' ] || exit 1
interval: 5m
start_interval: 30s
start_period: 5m
immich-folder-album-creator:
container_name: immich_folder_album_creator
image: salvoxia/immich-folder-album-creator:latest
restart: unless-stopped
environment:
API_URL: http://immich_server:2283/api
API_KEY: REPLACE_WITH_API_KEY_AFTER_SETUP
ROOT_PATH: /mnt/photos-bipin,/mnt/photos-ahana
CRON_EXPRESSION: "0 2 * * *"
RUN_IMMEDIATELY: "yes"
ALBUM_LEVELS: 1
SYNC_MODE: "2"
TZ: Asia/Kolkata
Note on
immich-folder-album-creator: TheAPI_KEYfield must be filled in after Immich is set up — you generate the key in Step 7. Leave it as the placeholder for now and update it after setup. The container will fail to start until a valid key is provided — this is expected.Note on network drive paths: The volumes
"P:/:/mnt/photos-bipin:ro"and"Q:/:/mnt/photos-ahana:ro"mount your mapped network drives (Photos_Bipin and Photos_Ahana) as read-only into the Immich container. Confirm P:\ and Q:\ are mapped before starting.
Step 4 — Start Immich
cd C:\docker\immich
docker compose up -d
This pulls four images — takes 5–10 minutes on the first run. Verify all containers are running:
docker compose ps
You should see these all as Up (the folder album creator
may show as restarting until you add the API key — that's fine):
- immich_server
- immich_machine_learning
- immich_redis
- immich_postgres
Step 5 — Initial Immich Setup
- Open
http://localhost:2283in your browser - Click Getting Started
- Create the admin account:
- Name: Bipin
- Email: your email
- Password: strong password — save in password manager
- Complete the setup wizard
- Skip the mobile app step for now
Step 6 — Create Ahana's Account
- Go to Administration → Users → Create User
- Fill in:
- Name: Ahana
- Email: Ahana's email
- Password: set a password — she can change it after first login
- Save
Step 7 — Generate API Key for Folder Album Creator
- Click your avatar (top right) → Account Settings
- Go to API Keys → New API Key
- Name:
folder-album-creator - Click Create
- Copy the generated key
Now update the docker-compose.yml — replace
REPLACE_WITH_API_KEY_AFTER_SETUP with the actual key:
API_KEY: your_actual_api_key_here
Restart the folder album creator container:
cd C:\docker\immich
docker compose up -d immich-folder-album-creator
Step 8 — Configure External Libraries
This is the step that makes your existing NAS photos appear in Immich without moving or duplicating them.
Allow external library paths (admin setting):
1. Go to Administration → Settings → Library
2. Under External Path, add both allowed paths:
- /mnt/photos-bipin
- /mnt/photos-ahana
3. Save
Create external library for Bipin:
1. Go to Administration → External Libraries
2. Click Create Library → select owner: Bipin
3. Click Add Folder → enter path: /mnt/photos-bipin
4. Click Add
5. Click the ... menu → Scan New Library Files
6. Rename the library to Bipin's Photos
Create external library for Ahana:
1. Click Create Library → select owner: Ahana
2. Click Add Folder → enter path: /mnt/photos-ahana
3. Click Add
4. Click ... menu → Scan New Library Files
5. Rename the library to Ahana's Photos
The initial scan will take time depending on how many photos you have. You can monitor progress under Administration → Jobs → Library.
Important: External library assets belong to the owner user. Bipin sees his photos, Ahana sees hers. Neither can browse the other's library by default — this matches your existing privacy setup.
Step 9 — Set Up Automatic Nightly Library Scan
Configure Immich to automatically pick up new photos from FolderSync and PhotoSync each night:
- Go to Administration → External Libraries
- Click ... on Bipin's Photos → Edit
- Under Scan Schedule, enter:
0 3 * * *(3am nightly) - Save
- Repeat for Ahana's Photos
The folder album creator also runs at 2am (Step 3 config) — this sequence means: photos arrive from FolderSync/PhotoSync during the day → Immich scans at 3am → folder album creator runs next night at 2am to create/update albums → photos appear in albums within 24 hours of being taken.
Step 10 — Configure Machine Learning
Immich's machine learning features (face recognition, smart search) run automatically in the background. Enable and tune them:
- Go to Administration → Settings → Machine Learning
- Confirm Smart Search is enabled
- Confirm Facial Recognition is enabled
- Go to Administration → Jobs
- Run Smart Search job — this indexes all photos for semantic search (takes hours for a large library — let it run overnight)
- Run Face Detection job — detects and groups faces (also runs in background)
Once complete you can search using natural language: - "beach photos" - "photos with children" - "outdoor photos 2023"
Step 11 — Add Cloudflare Tunnel Hostname
Add Immich to your Cloudflare Tunnel so you can access it remotely:
- Go to Cloudflare → Networking → Tunnels →
ahanabipin-home - Click Edit → Public Hostnames → Add a hostname
- Fill in:
- Subdomain:
photos - Domain:
ahanabipin.in - Service Type:
HTTP - URL:
localhost:2283 - Save
Immich is now accessible at:
https://photos.ahanabipin.in
Update the folder album creator
API_URLin docker-compose.yml to use the public URL if you ever need external API access — but for internal Docker communication, keep it ashttp://immich_server:2283/api.
Step 12 — Install Immich Mobile App (Optional)
The Immich mobile app gives you a Google Photos-like experience for browsing. Since you're keeping FolderSync/PhotoSync for backup, use the app in browse-only mode — disable auto-backup in the app settings to avoid duplicate uploads.
Android (Bipin):
1. Install Immich from Play Store
2. Open → Server URL: https://photos.ahanabipin.in
3. Log in with your Immich credentials
4. Go to app Settings → Backup → disable auto backup
iPhone (Ahana):
1. Install Immich from App Store
2. Open → Server URL: https://photos.ahanabipin.in
3. Log in with Ahana's credentials
4. Go to app Settings → Backup → disable auto backup
Step 13 — Update Phase 7 Backup Script
Immich's PostgreSQL database lives on the mini PC at
C:\docker\immich\postgres. This is not in the existing
robocopy path (C:\docker\mediastack\config). Update the
backup script to include it.
Open C:\rclone\backup-nas.bat and add this line after the
existing robocopy line:
echo [Immich] Copying Immich database and config to NAS... >> C:\rclone\backup.log
robocopy "C:\docker\immich" "\\192.168.1.2\Backups\immich-config" /MIR /XD "library" /R:2 /W:5 /LOG+:C:\rclone\backup.log
The
/XD "library"flag excludes the upload library folder from the backup — those photos are already on the NAS and backed up to B2 via rclone. Only the database and config are copied here.
Service Reference
| Service | Local URL | External URL |
|---|---|---|
| Immich | http://localhost:2283 |
https://photos.ahanabipin.in |
Verification Checklist
- [ ] Immich folder structure created on mini PC
- [ ]
.envfile created with secure DB_PASSWORD - [ ]
docker-compose.ymlcreated with correct NAS paths - [ ] All 4 core containers running (server, ML, redis, postgres)
- [ ] Admin account created for Bipin
- [ ] Ahana's account created
- [ ] API key generated and added to folder album creator
- [ ] External library paths allowed in admin settings
- [ ] Bipin's external library created →
/mnt/photos-bipin - [ ] Ahana's external library created →
/mnt/photos-ahana - [ ] Initial library scan completed
- [ ] Nightly scan schedule set for both libraries (3am)
- [ ] Machine learning jobs running (smart search, face detection)
- [ ]
photos.ahanabipin.inloading Immich via Cloudflare Tunnel - [ ] Both phones can browse photos via Immich app
- [ ] Phase 7 backup script updated to include Immich database
- [ ] Immich folder album creator running and creating albums
Troubleshooting
External library scan finds 0 photos:
Confirm the network drives P:\ and Q:\ are mapped and accessible
before Docker starts. Run docker compose restart immich_server
after confirming drives are connected. Check the path in the
external library settings exactly matches the container mount
path (/mnt/photos-bipin not the Windows path).
Folder album creator failing to start:
The API key placeholder must be replaced with a real key. Generate
it in Immich → Account Settings → API Keys, then update
docker-compose.yml and run docker compose up -d.
Machine learning very slow: This is normal on first run — it processes every photo once. Leave it running overnight. Subsequent scans only process new photos and are much faster. If you have an Intel CPU with QuickSync or an NVIDIA GPU, hardware acceleration can be enabled in the docker-compose.yml — see Immich docs for hardware transcoding configuration.
Photos appear with wrong date: Google Takeout JSON sidecar files contain the original date. Immich can read these — go to Administration → Jobs → Extract Metadata and run it. This corrects dates from the JSON files.
Cannot access photos.ahanabipin.in: Confirm the Cloudflare Tunnel hostname is configured correctly (localhost:2283) and the Tunnel is showing Healthy. Confirm the immich_server container is running on port 2283.
Immich not picking up new photos from FolderSync/PhotoSync: New photos land in the NAS folders overnight, then Immich scans at 3am. Check the scan schedule is set correctly in Administration → External Libraries. You can also trigger a manual scan any time from the same screen.
PostgreSQL container failing to start:
Confirm DB_DATA_LOCATION points to a local SSD path, not a
network share. Network shares are not supported for the Postgres
data directory.
Future Considerations
Sharing photos with family: Immich supports creating shared albums with external links — you can share an album of holiday photos with family members who don't have Immich accounts. Go to any album → Share → Create Link → set expiry if desired.
Merging faces: After face detection runs, go to Explore → People to see detected faces. Merge duplicate detections and name the people — Immich will then group all photos of that person together.
Vaultwarden addition:
When you decide to add Vaultwarden as a password manager,
it runs as a single Docker container on a different port (8765)
and can be added to this stack or the mediastack compose file
with a new Cloudflare Tunnel hostname vault.ahanabipin.in.
Phase 8 complete. Return to the overview for the full system summary.