Open-source alternatives guide
How to Self-Host Immich in 2026: Docker Setup
Immich is the best self-hosted Google Photos alternative with 90K+ stars. This guide covers installation, mobile backup, AI features, GPU acceleration, and.
What You're Setting Up
Immich (90K+ GitHub stars) replicates the Google Photos experience on your own server:
- Automatic backup from iOS and Android (native apps)
- AI-powered search ("find all photos of dogs at the beach")
- Face recognition with named people
- Timeline view, memories, shared albums
- Video support with transcoding
This guide takes you from zero to a production-ready Immich installation with mobile backup configured and AI features working.
Server Requirements
Minimum (Small Library, CPU Only)
- 2 CPU cores
- 4GB RAM
- Storage: enough for your photo library + 20% overhead for thumbnails and ML models
Recommended (Full AI Features)
- 4+ CPU cores
- 8GB RAM
- Storage: library + thumbnails (plan for 2-5x raw storage)
With GPU Acceleration
- NVIDIA GPU (compute capability 5.2+, driver 545+)
- 4GB VRAM minimum
- GPU dramatically speeds AI indexing (hours → minutes for large libraries)
Recommended Servers (Hetzner)
| Use Case | Server | Monthly |
|---|---|---|
| Personal (no GPU) | CAX21 (4GB ARM) | $6 |
| Family/team (no GPU) | CPX31 (8GB) | $10 |
| Fast AI indexing | CCX33 (16GB dedicated) | $35 |
Storage: Photo libraries grow. Use Hetzner Volumes ($0.044/GB/month) attached to your server rather than local SSD, or Hetzner Storage Box for S3-compatible storage.
Step 1: Prepare Your Server
# Update system
sudo apt update && sudo apt upgrade -y
# Install Docker and Docker Compose
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Log out and back in for group change to take effect
# Verify
docker --version
docker compose version
Create Directory Structure
sudo mkdir -p /opt/immich
sudo chown $USER:$USER /opt/immich
mkdir -p /opt/immich/library
The /opt/immich/library directory stores your actual photos. If you're using a separate volume for storage, mount it to this path.
Step 2: Configure Immich
Download Configuration Files
cd /opt/immich
wget https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env
Edit the .env File
nano .env
Set these critical values:
# Strong password - letters and numbers only (no special characters)
DB_PASSWORD=YourStrongPassword123
# Where your photos are stored
UPLOAD_LOCATION=/opt/immich/library
# Immich version (use "release" for latest stable)
IMMICH_VERSION=release
# Your timezone
TZ=America/New_York
# Postgres settings
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
Review the Docker Compose File
The default docker-compose.yml includes:
immich-server: Main application and APIimmich-microservices: Background job processingimmich-machine-learning: AI/ML container for smart search and face recognitionredis: Job queuedatabase: PostgreSQL with pgvector extension
For basic setups, the default file works without modification.
Step 3: Start Immich
cd /opt/immich
docker compose up -d
Initial startup takes 2-5 minutes as the database initializes. Monitor progress:
docker compose logs -f immich-server
Wait until you see messages about the server starting successfully.
Verify Running Containers
docker compose ps
All containers should show "running" status. If any are restarting, check logs:
docker compose logs [service-name]
Step 4: Initial Configuration
Access Immich at http://your-server-ip:2283
Create Admin Account
The first user to register automatically becomes the admin. Register with your email and password.
After registering:
- Go to Administration → Server Settings
- Set your server's external URL (important for mobile app connection)
Import Existing Photos (Optional)
If you have an existing photo library to import:
# Install Immich CLI
npm install -g @immich/cli
# Authenticate
immich login https://your-server-ip:2283 your@email.com
# Import directory (preserves original dates from EXIF)
immich upload --recursive /path/to/your/photos/
# Import Google Takeout export
immich upload --recursive /path/to/takeout/Google\ Photos/
The CLI processes photos in batches and shows progress. For large libraries (100GB+), run in a screen session:
screen -S immich-import
immich upload --recursive /path/to/photos/
# Detach: Ctrl+A, D
# Reattach: screen -r immich-import
Step 5: Set Up the Mobile App
This is Immich's killer feature — automatic phone backup.
Install the App
- iOS: App Store → search "Immich"
- Android: Google Play or F-Droid → search "Immich"
Connect to Your Server
- Open the Immich app
- Enter your server URL:
http://your-server-ip:2283orhttps://your-domain.com - Log in with your Immich credentials
If using IP address: You need to be on the same network, or use a VPN (Tailscale, WireGuard) to access your home/server network remotely.
If using a domain with HTTPS: You can connect from anywhere without a VPN. Set up a reverse proxy (step 7) first.
Configure Backup
- Tap the cloud icon (top right)
- Toggle "Backup" to On
- Select which albums to back up (default: all camera roll photos)
- Configure:
- Background backup: On (backs up even when app is closed)
- Require charging: Recommended for large initial backups
- WiFi only: Recommended to avoid cellular data charges
Android-Specific: Battery Optimization
Android aggressively kills background apps. Disable battery optimization for Immich:
- Settings → Apps → Immich → Battery
- Select "Unrestricted" or "Don't optimize"
Without this, background backup may not trigger reliably.
iOS-Specific: Background App Refresh
- Settings → General → Background App Refresh
- Enable for Immich
Verify Backup
Back in the app, the backup status should show photos uploading. For large libraries, initial backup takes hours to days depending on library size and connection speed.
Check Immich web UI: Photos should appear as they upload. They'll be AI-indexed in the background after upload.
Step 6: Configure AI Features
Immich's machine learning container handles:
- Smart Search: Search photos by content ("beach", "birthday cake", "dog")
- Facial Recognition: Detect and group faces, assign names
Verify ML Container is Running
docker compose logs immich-machine-learning
You should see messages about model loading. On first run, Immich downloads AI models (~1-2GB). This takes 5-15 minutes.
Monitor Indexing Progress
In Immich web UI:
- Administration → Jobs
- Look for "Smart Search" and "Face Detection" jobs
- These run automatically after photo upload
Initial indexing of a large library (10,000+ photos) takes hours on CPU, minutes with GPU acceleration.
Enable GPU Acceleration (NVIDIA)
If your server has an NVIDIA GPU with compute capability 5.2+:
- Install NVIDIA Container Toolkit:
# Add NVIDIA repository
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
- Edit
docker-compose.yml— replace theimmich-machine-learningservice:
immich-machine-learning:
container_name: immich_machine_learning
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-cuda
runtime: nvidia
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities:
- gpu
volumes:
- model-cache:/cache
env_file:
- .env
restart: always
- Restart Immich:
docker compose up -d immich-machine-learning
GPU acceleration reduces AI indexing time by 5-20x depending on GPU model.
Step 7: Set Up HTTPS with Reverse Proxy
For remote access without VPN and for the mobile app to work from anywhere.
Option A: Caddy (Simplest)
Install Caddy:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install caddy
Configure /etc/caddy/Caddyfile:
photos.yourdomain.com {
reverse_proxy localhost:2283
}
sudo systemctl restart caddy
Caddy automatically obtains and renews SSL certificates via Let's Encrypt.
Option B: Nginx with Certbot
sudo apt install -y nginx certbot python3-certbot-nginx
Create /etc/nginx/sites-available/immich:
server {
listen 80;
server_name photos.yourdomain.com;
client_max_body_size 50000M;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
location / {
proxy_pass http://localhost:2283;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
sudo ln -s /etc/nginx/sites-available/immich /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d photos.yourdomain.com
Important: Set client_max_body_size 50000M (or higher) to allow large video uploads.
Update Server URL in Mobile App
After setting up HTTPS, update the mobile app's server URL from http://IP:2283 to https://photos.yourdomain.com.
Step 8: Backup Strategy
Immich stores your photos — losing this data would be catastrophic.
What to Back Up
- Photo library:
/opt/immich/library(or whereverUPLOAD_LOCATIONpoints) - Database: PostgreSQL database containing metadata, albums, faces
- Model cache: Optional (can be re-downloaded)
Database Backup
# Manual backup
docker exec -t immich_postgres pg_dumpall -c -U postgres | gzip > /opt/backups/immich-db-$(date +%Y%m%d).sql.gz
# Automated backup script (add to crontab)
#!/bin/bash
BACKUP_DIR="/opt/backups/immich"
mkdir -p "$BACKUP_DIR"
docker exec -t immich_postgres pg_dumpall -c -U postgres | gzip > "$BACKUP_DIR/db-$(date +%Y%m%d).sql.gz"
# Keep last 7 days
find "$BACKUP_DIR" -name "db-*.sql.gz" -mtime +7 -delete
Add to crontab (crontab -e):
0 2 * * * /opt/immich/backup.sh
Library Backup
For the photo library, use:
- Rclone to sync to Backblaze B2 or AWS S3
- rsync to a secondary server
- Hetzner Storage Box as a backup destination
# Rclone to Backblaze B2 (configure rclone first)
rclone sync /opt/immich/library b2:your-bucket-name/immich-library --progress
3-2-1 Rule for Photos
- 3 copies of your photos
- 2 different storage media
- 1 offsite copy
Immich server + cloud backup + original device = 3 copies, 2 media, 1 offsite. This protects against hardware failure, accidental deletion, and site disasters.
Step 9: User Management
Add Additional Users
- Administration → Users → Create User
- Set email, password, name
- Configure storage quota (optional): limit how much each user can upload
Share Albums
- Open any album → Share
- Invite other Immich users by email
- Or create a public share link (link sharing)
Shared albums allow family members or colleagues to contribute photos to a common collection.
Updating Immich
Immich releases frequently. Update process:
cd /opt/immich
docker compose pull
docker compose up -d
Check release notes at github.com/immich-app/immich/releases before updating major versions.
Cost Comparison
| Setup | Monthly | Annual |
|---|---|---|
| Google Photos 2TB | $9.99 | $120 |
| iCloud 2TB | $9.99 | $120 |
| Immich (Hetzner CAX21 + 2TB volume) | $4 + $8.80 | $153 |
| Immich (Hetzner CAX11 + Storage Box 2TB) | $4 + $4.36 | $100 |
At 2TB, self-hosting is roughly cost-neutral but with unlimited family members and no per-account fees. At 5TB+, self-hosting saves substantially.
The real value: full data ownership, no subscription cancellation risk, and AI search features that work privately on your own hardware.
Find More Photo Management Tools
Browse all Google Photos alternatives on OSSAlt — compare Immich, PhotoPrism, LibrePhotos, and every other open source photo management platform with deployment guides.
Why Self-Host Immich in 2026?
The case for self-hosting Immich in 2026 comes down to three practical factors: data ownership, cost at scale, and operational control.
Data ownership is the fundamental argument. When you use a SaaS version of any tool, your data lives on someone else's infrastructure subject to their terms of service, their security practices, and their business continuity. If the vendor raises prices, gets acquired, changes API limits, or shuts down, you're left scrambling. Self-hosting Immich in 2026 means your data and configuration stay on infrastructure you control — whether that's a VPS, a bare metal server, or a home lab.
Cost at scale matters once you move beyond individual use. Most SaaS equivalents charge per user or per data volume. A self-hosted instance on a $10-20/month VPS typically costs less than per-user SaaS pricing for teams of five or more — and the cost doesn't scale linearly with usage. One well-configured server handles dozens of users for a flat monthly fee.
Operational control is the third factor. The Docker Compose configuration above exposes every setting that commercial equivalents often hide behind enterprise plans: custom networking, environment variables, storage backends, and authentication integrations. You decide when to update, how to configure backups, and what access controls to apply.
The honest tradeoff: you're responsible for updates, backups, and availability. For teams running any production workloads, this is familiar territory. For individuals, the learning curve is real but the tooling (Docker, Caddy, automated backups) is well-documented and widely supported.
Server Requirements and Sizing
Before deploying Immich in 2026, assess your server capacity against expected workload.
Minimum viable setup: A 1 vCPU, 1GB RAM VPS with 20GB SSD is sufficient for personal use or small teams. Most consumer VPS providers — Hetzner, DigitalOcean, Linode, Vultr — offer machines in this range for $5-10/month. Hetzner offers excellent price-to-performance for European and US regions.
Recommended production setup: 2 vCPUs with 4GB RAM and 40GB SSD handles most medium deployments without resource contention. This gives Immich in 2026 headroom for background tasks, caching, and concurrent users while leaving capacity for other services on the same host.
Storage planning: The Docker volumes in this docker-compose.yml store all persistent Immich in 2026 data. Estimate your storage growth rate early — for data-intensive tools, budget for 3-5x your initial estimate. Hetzner Cloud and Vultr both support online volume resizing without stopping your instance.
Operating system: Any modern 64-bit Linux distribution works. Ubuntu 22.04 LTS and Debian 12 are the most commonly tested configurations. Ensure Docker Engine 24.0+ and Docker Compose v2 are installed — verify with docker --version and docker compose version. Avoid Docker Desktop on production Linux servers; it adds virtualization overhead and behaves differently from Docker Engine in ways that cause subtle networking issues.
Network: Only ports 80 and 443 need to be publicly accessible when running behind a reverse proxy. Internal service ports should be bound to localhost only. A minimal UFW firewall that blocks all inbound traffic except SSH, HTTP, and HTTPS is the single most effective security measure for a self-hosted server.
Backup and Disaster Recovery
Running Immich in 2026 without a tested backup strategy is an unacceptable availability risk. Docker volumes are not automatically backed up — if you delete a volume or the host fails, data is gone with no recovery path.
What to back up: The named Docker volumes containing Immich in 2026's data (database files, user uploads, application state), your docker-compose.yml and any customized configuration files, and .env files containing secrets.
Backup approach: For simple setups, stop the container, archive the volume contents, then restart. For production environments where stopping causes disruption, use filesystem snapshots or database dump commands (PostgreSQL pg_dump, SQLite .backup, MySQL mysqldump) that produce consistent backups without downtime.
For a complete automated backup workflow that ships snapshots to S3-compatible object storage, see the Restic + Rclone backup guide. Restic handles deduplication and encryption; Rclone handles multi-destination uploads. The same setup works for any Docker volume.
Backup cadence: Daily backups to remote storage are a reasonable baseline for actively used tools. Use a 30-day retention window minimum — long enough to recover from mistakes discovered weeks later. For critical data, extend to 90 days and use a secondary destination.
Restore testing: A backup that has never been restored is a backup you cannot trust. Once a month, restore your Immich in 2026 backup to a separate Docker Compose stack on different ports and verify the data is intact. This catches silent backup failures, script errors, and volume permission issues before they matter in a real recovery.
Security Hardening
Self-hosting means you are responsible for Immich in 2026's security posture. The Docker Compose setup provides a functional base; production deployments need additional hardening.
Always use a reverse proxy: Never expose Immich in 2026's internal port directly to the internet. The docker-compose.yml binds to localhost; Caddy or Nginx provides HTTPS termination. Direct HTTP access transmits credentials in plaintext. A reverse proxy also centralizes TLS management, rate limiting, and access logging.
Strong credentials: Change default passwords immediately after first login. For secrets in docker-compose environment variables, generate random values with openssl rand -base64 32 rather than reusing existing passwords.
Firewall configuration:
ufw default deny incoming
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
Internal service ports (databases, admin panels, internal APIs) should only be reachable from localhost or the Docker network, never directly from the internet.
Network isolation: Docker Compose named networks keep Immich in 2026's services isolated from other containers on the same host. Database containers should not share networks with containers that don't need direct database access.
VPN access for sensitive services: For internal-only tools, restricting access to a VPN adds a strong second layer. Headscale is an open source Tailscale control server that puts your self-hosted stack behind a WireGuard mesh, eliminating public internet exposure for internal tools.
Update discipline: Subscribe to Immich in 2026's GitHub releases page to receive security advisory notifications. Schedule a monthly maintenance window to pull updated images. Running outdated container images is the most common cause of self-hosted service compromises.
Troubleshooting Common Issues
Container exits immediately or won't start
Check logs first — they almost always explain the failure:
docker compose logs -f immich
Common causes: a missing required environment variable, a port already in use, or a volume permission error. Port conflicts appear as bind: address already in use. Find the conflicting process with ss -tlpn | grep PORT and either stop it or change Immich in 2026's port mapping in docker-compose.yml.
Cannot reach the web interface
Work through this checklist:
- Confirm the container is running:
docker compose ps - Test locally on the server:
curl -I http://localhost:PORT - If local access works but external doesn't, check your firewall:
ufw status - If using a reverse proxy, verify it's running and the config is valid:
caddy validate --config /etc/caddy/Caddyfile
Permission errors on volume mounts
Some containers run as a non-root user. If the Docker volume is owned by root, the container process cannot write to it. Find the volume's host path with docker volume inspect VOLUME_NAME, check the tool's documentation for its expected UID, and apply correct ownership:
chown -R 1000:1000 /var/lib/docker/volumes/your_volume/_data
High resource usage over time
Memory or CPU growing continuously usually indicates unconfigured log rotation, an unbound cache, or accumulated data needing pruning. Check current usage with docker stats immich. Add resource limits in docker-compose.yml to prevent one container from starving others. For ongoing visibility into resource trends, deploy Prometheus + Grafana or Netdata.
Data disappears after container restart
Data stored in the container's writable layer — rather than a named volume — is lost when the container is removed or recreated. This happens when the volume mount path in docker-compose.yml doesn't match where the application writes data. Verify mount paths against the tool's documentation and correct the mapping. Named volumes persist across container removal; only docker compose down -v deletes them.
Keeping Immich in 2026 Updated
Immich in 2026 follows a regular release cadence. Staying current matters for security patches and compatibility. The update process with Docker Compose is straightforward:
docker compose pull # Download updated images
docker compose up -d # Restart with new images
docker image prune -f # Remove old image layers (optional)
Read the changelog before major version updates. Some releases include database migrations or breaking configuration changes. For major version bumps, test in a staging environment first — run a copy of the service on different ports with the same volume data to validate the migration before touching production.
Version pinning: For stability, pin to a specific image tag in docker-compose.yml instead of latest. Update deliberately after reviewing the changelog. This trades automatic patch delivery for predictable behavior — the right call for business-critical services.
Post-update verification: After updating, confirm Immich in 2026 is functioning correctly. Most services expose a /health endpoint that returns HTTP 200 — curl it from the server or monitor it with your uptime tool.
The SaaS-to-Self-Hosted Migration Guide (Free PDF)
Step-by-step: infrastructure setup, data migration, backups, and security for 15+ common SaaS replacements. Used by 300+ developers.
Join 300+ self-hosters. Unsubscribe in one click.