What Immich needs
Immich is a self-hosted photo and video library with mobile apps, face and object search and sharing. It stores your originals, makes thumbnails and transcodes video, and its machine-learning features need real resources. The project's documentation recommends several gigabytes of memory, so use a plan with 8 GB or more, such as an AI and development plan, and several vCPUs. Search and face recognition indexing run on the CPU on our plans, so the first import of a large library takes a long time.
Storage is the main cost: your whole library plus thumbnails and transcoded videos. Check the project's current requirements before you choose a plan.
free -h
nproc
df -h /
sudo docker compose versionDownload the official files
Use the Compose file and example environment published with the latest release. Create a folder, download both files and rename the example file to .env. Do not copy an old file from a blog post, because the services change between versions.
mkdir -p ~/immich && cd ~/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
ls -lEdit the settings
Open .env and set the upload location, which is where originals are stored, a database location, your time zone, a random database password, and the Immich version. Pin the version to a specific release for production rather than using release, so updates happen when you choose. Keep the file private because it holds the database password.
cd ~/immich
chmod 600 .env
sudo mkdir -p /srv/immich/library /srv/immich/postgres
sed -i "s|^UPLOAD_LOCATION=.*|UPLOAD_LOCATION=/srv/immich/library|;s|^DB_DATA_LOCATION=.*|DB_DATA_LOCATION=/srv/immich/postgres|;s|^DB_PASSWORD=.*|DB_PASSWORD=$(openssl rand -hex 16)|" .env
nano .env
grep -E "UPLOAD_LOCATION|DB_DATA_LOCATION|TZ|IMMICH_VERSION" .envKeep it private, then start it
The official file publishes the web interface on port 2283 for every address. Change the port mapping so that it listens only on localhost, then reach it through a reverse proxy or an SSH tunnel, as the earlier guides describe. Check the port line in the server service before starting.
cd ~/immich
grep -n "2283" docker-compose.yml
sed -i 's|"2283:2283"|"127.0.0.1:2283:2283"|' docker-compose.yml
grep -n "2283" docker-compose.yml
sudo docker compose up -d
sudo docker compose pssudo ss -lntp | grep 2283Create the admin account and publish it
Open the interface through an SSH tunnel to port 2283, and create the first account, which becomes the administrator. Then publish it behind HTTPS with Caddy or Nginx. Photo uploads are large, so raise the upload size limit and the timeouts in Nginx, and enable WebSocket headers. Install the mobile app, enter your server address and turn on background backup.
ssh -L 2283:127.0.0.1:2283 deploy@YOUR_SERVERclient_max_body_size 50000M;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;Control the load
The first import and the machine-learning jobs use a lot of CPU, which can make a small server unusable. In the administration settings, lower the concurrency of the background jobs, and run the heavy jobs while you are not using the server. The machine-learning container can be limited or removed if you do not need smart search and face recognition. Watch memory and CPU while it runs.
cd ~/immich
sudo docker stats --no-stream
free -h
uptimeBack up the photos and the database
Back up both parts. The originals in UPLOAD_LOCATION are what you cannot recreate. The database holds albums, people, tags and settings, and the library without it loses its organisation. Immich creates database dumps on a schedule in a backups folder inside the library location, and the documentation describes how to restore them. Copy the whole library folder, including that backups folder, to another machine, with a tool such as restic as in the backup guide.
Follow the 3-2-1 rule: three copies, on two kinds of storage, one of them off site. A copy on the same server protects only against deletion mistakes.
Stop the server and machine-learning services before pairing a database dump with a library copy. Do not copy the live PostgreSQL data directory. Protect .env and the application files off-server alongside these archives. The commands use the default PostgreSQL username and database; adjust them if you changed the official environment file.
ls -lh /srv/immich/library/backups/ | tail -n 5
sudo du -sh /srv/immich/librarycd ~/immich
set -o pipefail
umask 077
sudo docker compose stop immich-server immich-machine-learning
sudo docker compose exec -T database pg_dump --clean --if-exists --username=postgres --dbname=immich | gzip > immich-db-$(date +%F).sql.gz
sudo tar czf immich-files-$(date +%F).tar.gz -C /srv/immich/library .
sudo chmod 600 immich-db-*.sql.gz immich-files-*.tar.gz
gzip -t immich-db-$(date +%F).sql.gz
sudo docker compose start immich-server immich-machine-learningUpdate deliberately
Immich releases often and sometimes includes breaking changes, which are listed in the release notes. Read them before each update, take a backup, change the version in .env, pull and restart. Check the logs and the interface, and test that uploads and search work. Do not update right before a trip when you cannot fix a problem.
cd ~/immich
nano .env
sudo docker compose pull
sudo docker compose up -d
sudo docker compose logs --tail 40 immich-serverTest a restore
Use a disposable recovery instance with the same Immich version, Compose configuration, .env and library paths as the backup. Confirm the database name, archive and destination before proceeding. These commands replace the application database contents and clear the upload library; preserve existing data first if this is not an empty recovery target.
Start PostgreSQL alone, replay the database, restore the whole matching library, then start the application. Sign in, locate a known uploaded image and download its original. Compare its checksum with the original file; thumbnails alone do not prove recovery worked.
cd ~/immich
set -o pipefail
sudo docker compose stop immich-server immich-machine-learning
sudo docker compose up -d database
# Wait until PostgreSQL is ready before importing.
sudo docker compose exec -T database pg_isready --username=postgres
gunzip -c immich-db-YYYY-MM-DD.sql.gz | sudo docker compose exec -T database psql --set=ON_ERROR_STOP=on --username=postgres --dbname=immich
# Confirm this exact upload directory and archive before clearing it.
sudo find /srv/immich/library -mindepth 1 -maxdepth 1 -exec rm -rf {} +
sudo tar xzf immich-files-YYYY-MM-DD.tar.gz -C /srv/immich/library
sudo docker compose start immich-server immich-machine-learning
sudo docker compose logs --tail 40 immich-server
Official documentation
These upstream references provide more detail on the commands and workflows in this guide.