← Blog
Self-Host Your Photo Library with Immich

Your photos are probably sitting in someone else's cloud right now. Every picture of your kids, every vacation, every moment, stored on servers you don't control, scanned by algorithms you didn't agree to, and subject to pricing changes you can't predict.

Immich is the way out. It's a self-hosted photo and video management platform that runs on your own server. Face recognition, mobile auto-backup, smart search, shared albums, map view, all the features you expect from a modern photo service, on hardware you own.

This guide walks through deploying Immich on a Linux server using Docker Compose. You'll have a working photo server in under 30 minutes.

What you'll need

  • A Linux server (Ubuntu 22.04/24.04, Debian 12, or any distro with Docker support)
  • At least 6 GB RAM (8 GB recommended, the ML container needs room to work)
  • 2+ CPU cores (4 recommended)
  • Storage sized to your photo library, plan for your existing library plus 10-20% overhead for thumbnails and transcoded video
  • Docker Engine 25+ with the docker compose plugin (not the deprecated docker-compose)

A VPS with 4 cores and 8 GB RAM handles a family library of 50,000+ photos comfortably. For larger collections or snappier face recognition, a dedicated server with more RAM and NVMe storage makes a real difference.

Step 1, Install Docker

If Docker isn't already on the box, set it up from the official repository. Don't use the docker.io package from Ubuntu's default repos. It's outdated and missing the Compose plugin.

bash

# Remove old versions
sudo apt remove docker docker-engine docker.io containerd runc 2>/dev/null

# Add Docker's official GPG key and repository
sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Install Docker Engine + Compose plugin
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Add your user to the docker group
sudo usermod -aG docker $USER

Log out and back in for the group change to take effect. Verify with:

bash

docker compose version

Step 2, Download the Immich config files

Create a directory for Immich and pull the official Docker Compose and environment files:

bash

mkdir -p /opt/immich && cd /opt/immich

wget -O docker-compose.yml 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

Step 3, Configure the environment

Edit .env to set your storage paths and a secure database password:

bash

nano .env

The key variables to change:

bash

UPLOAD_LOCATION=/mnt/data/immich/library
DB_DATA_LOCATION=/opt/immich/postgres
IMMICH_VERSION=v2
DB_PASSWORD=your_secure_password_here

Generate a strong password with:

bash

openssl rand -base64 32

Two important rules for storage paths:

  • UPLOAD_LOCATION can be on any filesystem. This is where your photos live, so point it at your largest drive.
  • DB_DATA_LOCATION should be on an SSD. Database performance directly affects how fast the UI feels.

Step 4, Start Immich

bash

cd /opt/immich
docker compose up -d

Watch the logs to make sure everything starts cleanly:

bash

docker compose logs -f immich-server

You're looking for the server to report that it's listening on port 2283. The machine learning container takes a minute or two on first start to download its models. That's normal.

Verify all containers are running:

bash

docker compose ps

Step 5, Create your admin account

Open your browser and go to http://your-server-ip:2283. Click "Getting Started" and create the first account. This is the admin user.

Step 6, Set up mobile backup

Install the Immich app on your phone (iOS App Store or Android Google Play/F-Droid). Then:

  1. Enter your server URL
  2. Log in with your admin credentials
  3. Enable automatic backup in the cloud icon settings
  4. Select which albums to back up

Step 7, Set up HTTPS with a reverse proxy

For remote access, you'll want HTTPS. Basic Nginx reverse proxy with Let's Encrypt:

bash

sudo apt install -y nginx certbot python3-certbot-nginx

Create a config file at /etc/nginx/sites-available/immich:

nginx

server {
    listen 80;
    server_name photos.yourdomain.com;
    client_max_body_size 50000M;
    location / {
        proxy_pass http://127.0.0.1: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";
    }
}

Enable and get SSL:

bash

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

The client_max_body_size 50000M is important. Without it, Nginx rejects large video uploads.

Step 8, Import an existing photo library

Immich can index existing photos without copying them. Add a volume mount to docker-compose.yml:

yaml

services:
  immich-server:
    volumes:
      - ${UPLOAD_LOCATION}:/data
      - /path/to/existing/photos:/mnt/photos:ro

The :ro flag makes the mount read-only. Useful if you want Immich to index your library without any risk of modifying the original files.

Then go to Administration → External Libraries → Create External Library and set the import path to /mnt/photos.

Keeping Immich updated

bash

cd /opt/immich
docker compose pull
docker compose up -d
docker image prune -f

Your photos, database, and settings stay in the configured volumes.

Backups matter

Add a nightly database backup to your crontab:

bash

0 3 * * * cd /opt/immich && docker compose exec -T immich_postgres pg_dumpall -U postgres | gzip > /mnt/backups/immich-db-$(date +\%Y\%m\%d).sql.gz

This dumps the entire database every night at 3 AM and saves it as a compressed file. Don't forget to also back up your UPLOAD_LOCATION directory. The database alone won't recover anything if the photos are gone.

Troubleshooting

ML container keeps restarting: usually RAM. Either bump your server's memory or switch to smaller ML models in the admin settings.

Uploads are slow: check your Nginx client_max_body_size value first. If that's fine, the bottleneck is almost always the database. It must be on an SSD.

Face recognition not working: it runs in the background and can take hours on large libraries. Check Administration → Jobs to see the progress.

Can't reach the mobile app from outside: confirm your reverse proxy is forwarding WebSocket upgrades correctly. The Upgrade and Connection headers in the Nginx config are not optional.

Continue reading

Create account Access my account

No commitment, deploy in seconds

Community zone

A question ?
Find answers and share your knowledge !

We are waiting you on community zone. More than 70 guides (sysadmin, gaming, devops...) !

Let me check
DEDIMAX DEDIMAX DEDIMAX DEDIMAX
DEDIMAX

Need a quote ?

Write us !

Contact us

Prendre contact