Deploy Immich on Docker: Self-Hosted Photo and Video Backup for Your HomeLab

HomeLab tutorial - IT technology blog
HomeLab tutorial - IT technology blog

The Problem with Trusting Your Memories to Big Tech

You open Google Photos one day and discover your free unlimited storage ended two years ago. Half your photos from 2021 are stuck in limbo — you hit the quota without noticing. Or maybe you just got the email: “Your storage is 95% full. Upgrade to Google One.”

This is exactly what happened to me. Years of family photos, travel snapshots, and random screenshots — all sitting on someone else’s server, behind a subscription paywall I had to keep feeding. The real issue isn’t the money. It’s the dependency. When a service changes its pricing or shuts down, your memories go with it.

Cloud photo services are built to make you dependent. Convenience upfront, lock-in once your data is there. Free tiers shrink, prices climb, and you have zero control over how your photos are stored, compressed, or shared with advertisers.

Already running a HomeLab — a NAS, an old PC, or even a Raspberry Pi 4 — you can host your own Google Photos replacement. No monthly fees, no compression, no privacy trade-offs. That solution is Immich.

What Immich Actually Is

Immich is an open-source, self-hosted photo and video backup solution. It looks and behaves almost exactly like Google Photos — mobile auto-backup, timeline view, albums, shared libraries — but everything runs on your own hardware.

A few things set Immich apart from simpler tools like Synology Photos or PhotoPrism:

  • Mobile apps for iOS and Android with automatic background backup
  • AI-powered features: face recognition, object detection, scene classification using CLIP embeddings
  • EXIF-based timeline: browse photos by date, location, and camera model
  • Multi-user support: separate libraries for each family member, with sharing controls
  • RAW file support and lossless original storage — no recompression
  • Video transcoding via hardware acceleration (Intel QSV, NVIDIA NVENC, VA-API)

Getting your photo library off commercial cloud and onto hardware you control is one of the most impactful things you can do in a privacy-first HomeLab. Once Immich is running, auto-backup from your phone just works — identical to Google Photos, except the data stays home. It deploys as a set of Docker containers, which keeps updates clean and rollbacks simple.

What You Need Before Starting

Check these before deploying:

  • Docker and Docker Compose v2+ installed
  • At least 4 GB RAM — bump to 8 GB if you enable AI features like face recognition
  • Enough disk space: a typical phone generates 5–10 GB per month in photos and videos. Mount an external drive or NAS share from the start
  • A domain name is optional but worth having if you want HTTPS remote access

Deploying Immich with Docker Compose

Step 1: Create the project directory and environment file

mkdir -p ~/immich && cd ~/immich

Pull the official docker-compose.yml and .env template directly from the Immich repository:

curl -L https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml -o docker-compose.yml
curl -L https://github.com/immich-app/immich/releases/latest/download/example.env -o .env

Step 2: Configure the .env file

Open .env and set the key variables:

# Path where your photos will be stored on the host
UPLOAD_LOCATION=/data/immich/photos

# Path for the database
DB_DATA_LOCATION=/data/immich/postgres

# Pin to a specific release or use "release" for latest stable
IMMICH_VERSION=release

# Timezone
TZ=Asia/Tokyo

# Database password — use something long and random
DB_PASSWORD=your_strong_password_here

Make sure /data/immich/photos exists with enough space. If you’re mounting an external drive, point UPLOAD_LOCATION to its mount path instead.

sudo mkdir -p /data/immich/photos /data/immich/postgres
sudo chown -R $USER:$USER /data/immich

Step 3: Start the stack

docker compose up -d

Docker pulls and starts four containers:

  • immich-server — main API, web UI, and background job processing
  • immich-machine-learning — face recognition and CLIP embeddings
  • redis — job queue
  • postgres — metadata database

Verify everything came up cleanly:

docker compose ps

The web UI lands at http://your-server-ip:2283. On first load, create your admin account.

Step 4: Set up the mobile app

Install the Immich app on your phone (iOS and Android both work). During setup:

  1. Enter your server URL: http://your-server-ip:2283
  2. Log in with your admin account, or create separate user accounts for family members
  3. Enable auto-backup in the app settings — new photos upload in the background, just like Google Photos used to

Storage Layout and External Drive Mounting

When your OS drive is small (a common situation on mini PCs and NUCs), point Immich at a separate disk from day one. Here’s how to mount an external drive and wire it up:

# Find the drive
lsblk

# Create mount point
sudo mkdir -p /mnt/photos

# Add to /etc/fstab for auto-mount (replace UUID with your drive's UUID from blkid)
echo 'UUID=your-drive-uuid /mnt/photos ext4 defaults 0 2' | sudo tee -a /etc/fstab
sudo mount -a

# Update UPLOAD_LOCATION in .env
UPLOAD_LOCATION=/mnt/photos/immich

After editing .env, restart the stack to apply the change:

docker compose down && docker compose up -d

Enabling Hardware Acceleration for Video Transcoding

By default, Immich transcodes videos for browser playback using CPU — painfully slow on low-power machines. An Intel iGPU changes this significantly; VA-API transcoding handles 1080p in real time on hardware as modest as an N100 mini PC.

In docker-compose.yml, find the immich-server service and add the device mapping:

immich-server:
  # ... existing config ...
  devices:
    - /dev/dri:/dev/dri

Then in the Immich admin panel under Administration → Video Transcoding, switch hardware acceleration to VA-API. NVIDIA GPUs follow the same pattern but require the NVIDIA container runtime installed on the host first.

Keeping Immich Updated

Immich ships updates frequently — sometimes weekly. Updating takes three commands and leaves your photos untouched:

cd ~/immich
docker compose pull
docker compose up -d

Docker swaps in the new images, restarts the containers, and runs database migrations automatically. Done.

Accessing Immich Securely from Outside Your Network

Two clean options for remote access:

  • Tailscale — install on both your phone and server. Access Immich over a private WireGuard tunnel with no port forwarding and no public exposure
  • Reverse proxy with HTTPS — use Caddy or Nginx Proxy Manager to put Immich behind a proper domain with a Let’s Encrypt certificate

Caddy makes HTTPS trivially simple. Drop this in your Caddyfile:

photos.yourdomain.com {
    reverse_proxy localhost:2283
}

Caddy handles certificate provisioning on its own. Point your DNS A record to your server’s public IP, open port 443, and you’re done — valid HTTPS with auto-renewal.

Migrating from Google Photos

Moving your existing library over is straightforward. Start with a Google Takeout export:

  1. Go to takeout.google.com and request a photo export — expect a multi-GB archive for most libraries
  2. Extract it locally — Google organizes the files into folders by album or year
  3. Use the Immich CLI to bulk-import everything:
# Install Immich CLI
npm install -g @immich/cli

# First, generate an API key: Immich web UI → Account Settings → API Keys → New API Key

# Log in with the API key
immich login http://your-server-ip:2283 --api-key YOUR_API_KEY_HERE

# Upload the export directory recursively
immich upload --recursive /path/to/google-photos-export

The CLI preserves EXIF dates during import. Your photos slot into the correct timeline positions — 2019 vacation photos land in 2019, not today’s date.

Running Smoothly Over Time

Three habits that’ll save you from headaches down the road:

  • Watch disk usage: photos pile up quietly. A simple cron job or a Grafana alert when the mount hits 80% capacity beats discovering a full disk at 2am
  • Back up the PostgreSQL database: the photo files themselves are just files, but Immich’s metadata — albums, face tags, people names — lives in Postgres. Back it up regularly:
docker exec immich_postgres pg_dumpall -U postgres > immich_backup_$(date +%F).sql
  • Keep Google Photos intact until you’ve verified the import: spot-check a few dozen photos across different years before deleting anything from the cloud

What You End Up With

At this point, your HomeLab handles photo backup end-to-end. Every phone in the house uploads automatically. Search works by face, object, location, and date. Albums are shareable. Videos play in the browser.

All of it runs on hardware you own. No subscription. No third party holding 10 years of family photos. Google Photos or iCloud becomes a choice rather than a requirement — and that shift is the whole point of building your own infrastructure.

Share: