Skip to content

TutorialsSelf-hosted apps

How to install Immich with Docker Compose and HTTPS

Self-host Immich photo backup with Docker Compose: official compose file, secure .env, port 2283 behind Caddy HTTPS, database dumps, restores and safe updates.

  • Intermediate
  • 35 min read
  • Updated

Tested on: Ubuntu 24.04 LTS, Ubuntu 26.04 LTS, Debian 12, Debian 13

This guide is not available in your language yet, so it is shown in English.

On this page
  1. Prerequisites
  2. Step 1 — Download the official files
  3. Step 2 — Configure the .env file
  4. Step 3 — Keep port 2283 on localhost
  5. Step 4 — Start Immich
  6. Step 5 — Create the admin account through an SSH tunnel
  7. Step 6 — Publish Immich over HTTPS with Caddy
  8. Back up and restore
  9. Update Immich
  10. Machine learning and hardware acceleration
  11. Troubleshooting
  12. The containers restart and the logs mention start_interval
  13. unknown shorthand flag: 'd' in -d
  14. Uploads of large videos fail through the domain but work through the tunnel
  15. The database container does not start after moving the data
  16. Face recognition or smart search never finishes
  17. Next steps

Immich is a self-hosted photo and video management tool with mobile apps that back up your camera roll automatically. It offers albums, sharing, a timeline, face recognition and smart search powered by a separate machine learning container.

This guide deploys Immich with Docker Compose using the files attached to Immich's latest GitHub release, exactly as the official documentation does. You keep the web port 2283 on localhost, create the admin account through an SSH tunnel, publish Immich over HTTPS with Caddy, and set up backups of both the database and the photo library. You also learn how to restore, update, and where hardware acceleration fits in.

Prerequisites

  • A 64-bit server (amd64 or arm64) running Ubuntu 24.04 or 26.04 LTS or Debian 12 or 13. Since v3, the machine learning image on amd64 needs the x86-64-v2 microarchitecture level; /lib64/ld-linux-x86-64.so.2 --help | grep x86-64-v2 should report it as supported.
  • A non-root user with sudo rights: see Secure a new Linux server and Set up SSH keys.
  • Docker Engine with the Compose plugin from Docker's repository: Ubuntu or Debian. Immich no longer supports the old docker-compose command, and its compose file needs Docker Engine 25 or newer.
  • Caddy on the host, set up with How to set up Caddy as a reverse proxy, and a subdomain such as photos.example.com pointing at the server.
ResourceMinimum (official)Suggested starting point
RAM6 GB (8 GB recommended); 4 GB possible with machine learning disabled8 GB
CPU2 cores (4 recommended)4 vCPUs
DiskUnix filesystem with ownership and permissions (ext4, ZFS); database on local SSD, never a network shareSSD sized for your library plus 10 to 20 percent for thumbnails and transcoded videos

Step 1 — Download the official files

Create a project folder and download docker-compose.yml and example.env from the latest release. The official guide uses a folder called immich-app; this library keeps Docker apps under /opt:

Bash
sudo mkdir -p /opt/immich
sudo chown $USER:$USER /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
ls -la

You should see docker-compose.yml and .env. The compose file defines four services: immich-server, immich-machine-learning, redis (a Valkey image) and database (PostgreSQL with the VectorChord extension).

Step 2 — Configure the .env file

Set a random database password first. Immich asks for letters and digits only, without special characters or spaces, so a hex string is ideal. Then protect the file and open it:

Bash
sed -i "s/^DB_PASSWORD=.*/DB_PASSWORD=$(openssl rand -hex 24)/" .env
chmod 600 .env
nano .env

Review the variables. Remove the # in front of TZ and set your time zone. The result should look like this, with your own password and time zone:

.env
UPLOAD_LOCATION=./library
DB_DATA_LOCATION=./postgres
TZ=Etc/UTC
IMMICH_VERSION=v3
DB_PASSWORD=generated-by-openssl
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
  • UPLOAD_LOCATION holds uploads, thumbnails, transcoded videos and the automatic database dumps. Point it at a disk with enough space if you have a separate data volume.
  • DB_DATA_LOCATION holds the PostgreSQL files. Keep it on local SSD storage; network shares are not supported.
  • IMMICH_VERSION=v3 follows the latest v3 release. To pin an exact version, set it to a release tag from the releases page, for example v3.3.1, the latest release at the time of writing.

Step 3 — Keep port 2283 on localhost

The compose file publishes the web port as '2283:2283', which Docker opens on every address, regardless of ufw. Bind it to localhost so that only Caddy can reach it:

Bash
sed -i "s/- '2283:2283'/- '127.0.0.1:2283:2283'/" docker-compose.yml
grep -n "2283" docker-compose.yml

The grep output should show 127.0.0.1:2283:2283. Repeat this edit whenever you replace docker-compose.yml with a newer release file.

Step 4 — Start Immich

Bash
docker compose up -d
docker compose ps
curl -I http://127.0.0.1:2283

The first start pulls several images and takes a few minutes. docker compose ps should list immich_server, immich_machine_learning, immich_redis and immich_postgres as running and, after a short while, healthy. The curl command returns an HTTP 200 response. If something fails, read the logs with docker compose logs -f immich-server.

Step 5 — Create the admin account through an SSH tunnel

The first user who registers becomes the administrator. Create that account before Immich is reachable from the internet. On your own computer, open a tunnel:

Bash
ssh -L 2283:127.0.0.1:2283 admin@203.0.113.10

Browse to http://localhost:2283, select Getting Started and create the admin account with a strong password. Add accounts for family or friends later under Administration → Users with Create user. If you want readable folders on disk, enable the storage template under Administration → Settings → Storage Template; its default pattern sorts files by year, then by date, keeping the original file name.

Immich emails new users, album invitations and shared-album updates once you configure an SMTP server under Administration → Settings → Notification Settings, for example host smtp.example.com on port 587 with STARTTLS.

Step 6 — Publish Immich over HTTPS with Caddy

Allow web traffic in ufw if you have not done so, and add a site block to /etc/caddy/Caddyfile:

Caddyfile
photos.example.com {
    reverse_proxy 127.0.0.1:2283
}

Immich must be served at the root of a host; subpaths are not supported. Its reverse proxy documentation asks for large uploads and long timeouts. Caddy does not limit request size by default and the official Caddy example uses exactly this block. If you use Nginx instead, follow Immich's settings (client_max_body_size 50000M and 600-second timeouts) with Nginx reverse proxy with Certbot.

Reload Caddy and check the result:

Bash
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo systemctl reload caddy
curl -I https://photos.example.com

You should get an HTTP 200 response with a valid certificate. In the Immich mobile app, enter https://photos.example.com as the server URL, log in, open the backup screen, choose albums and enable backup.

Back up and restore

Immich keeps its state in two places: the database (users, albums, people, metadata) and the upload location (the photos and videos themselves). Back up both, plus .env and docker-compose.yml.

Automatic database dumps. Immich writes a database dump every day at 02:00 and keeps the last 14 by default, in UPLOAD_LOCATION/backups, here /opt/immich/library/backups. Change the schedule under Administration → Settings → Database Dump Settings. These dumps contain no photos.

Manual dump. Create one before every update:

Bash
sudo mkdir -p /opt/backups
sudo chown $USER:$USER /opt/backups
docker exec -t immich_postgres pg_dump --clean --if-exists --dbname=immich --username=postgres | gzip > /opt/backups/immich-db-$(date +%F).sql.gz
cp /opt/immich/.env /opt/immich/docker-compose.yml /opt/backups/

The library. The folders library, upload and profile inside the upload location hold original content; Immich recommends backing up the whole upload location, including backups, thumbs and encoded-video. Copy it to another server with rsync, which only transfers changes:

Bash
sudo rsync -aAX --delete /opt/immich/library/ backup@198.51.100.20:/backups/immich-library/

Restore. Immich offers a restore in the web interface under Administration → Maintenance → Restore database backup, and a Restore from backup option on the welcome screen of a fresh installation. From the command line, copy the library back to the upload location, then follow the official procedure, which starts from an empty database:

Bash
cd /opt/immich
docker compose down -v
sudo rm -rf ./postgres
docker compose create
docker start immich_postgres
sleep 10
gunzip --stdout "/opt/backups/immich-db-2026-10-09.sql.gz" \
| sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" \
| docker exec -i immich_postgres psql --dbname=immich --username=postgres --single-transaction --set ON_ERROR_STOP=on
docker compose up -d

Restore into the same Immich version that made the backup; downgrades are not supported.

Update Immich

Read the release notes first: breaking changes are announced on GitHub and are meant to be limited to major releases. Make a manual database dump, then pull and recreate the containers:

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

If you pinned IMMICH_VERSION to an exact tag, change it in .env before you pull. Downgrading, even within the same minor version, is not supported. Immich recommends updating the mobile apps before a major server upgrade. When a new major version comes out, compare your docker-compose.yml and .env with the files of the new release and apply the 127.0.0.1 binding again if you replace the compose file.

Machine learning and hardware acceleration

The immich-machine-learning container powers face recognition and smart search. It runs on the CPU and downloads its models into the model-cache volume on first use. On a server with little RAM, you can turn machine learning off in the administration settings and keep the rest of Immich.

Most virtual servers have no GPU, so machine learning and video transcoding run on the CPU, which works but takes longer for large libraries. Immich supports hardware acceleration for machine learning (CUDA, ROCm, OpenVINO, ARM NN, RKNN) and for transcoding (NVENC, Quick Sync, VAAPI, RKMPP) through two extra files from the release:

Bash
cd /opt/immich
wget -O hwaccel.ml.yml https://github.com/immich-app/immich/releases/latest/download/hwaccel.ml.yml
wget -O hwaccel.transcoding.yml https://github.com/immich-app/immich/releases/latest/download/hwaccel.transcoding.yml

For NVIDIA, the documentation requires a GPU with compute capability 5.2 or higher, driver 545 or newer and the NVIDIA Container Toolkit. You then add the -cuda suffix to the machine learning image tag and uncomment the extends section in docker-compose.yml. For a server with a supported NVIDIA GPU, see GPU servers.

Troubleshooting

The containers restart and the logs mention start_interval

Your Docker Engine is older than version 25. Install the current Docker Engine from Docker's repository; as a stopgap, the documentation allows commenting out the start_interval line in the database section.

unknown shorthand flag: 'd' in -d

The docker compose plugin is missing or outdated, so Docker does not understand the command. Install the Compose plugin from Docker's repository and do not use the legacy docker-compose binary.

Uploads of large videos fail through the domain but work through the tunnel

The reverse proxy limits request size or times out. Caddy has no such limits by default; for Nginx, set client_max_body_size and the timeouts from Immich's reverse proxy documentation. Also check that no CDN proxy in front of the domain limits uploads.

The database container does not start after moving the data

The database folder is on a network share or a filesystem without Unix ownership and permissions. Move DB_DATA_LOCATION back to a local ext4 or ZFS filesystem, ideally on SSD, and restore from a dump if needed.

Face recognition or smart search never finishes

Check docker compose logs immich-machine-learning. Out-of-memory kills point to too little RAM; add memory or turn machine learning off. On amd64, a CPU without x86-64-v2 support cannot run the v3 machine learning image.

Next steps

Frequently asked questions

How much RAM does Immich need?

Immich's requirements page lists a minimum of 6 GB of RAM and recommends 8 GB, with at least 2 CPU cores and 4 recommended. On a 4 GB server you can run Immich with the machine learning features turned off.

Are Immich's automatic database backups enough?

No. The automatic dumps contain only the database, which holds metadata such as albums, people and users. Your photos and videos live in the upload location, so you must back up that folder as well and keep a copy off the server.

Can I put Immich under a subpath like example.com/photos?

No. Immich does not support being served on a subpath. Give it its own domain or subdomain, for example photos.example.com, and point the reverse proxy at the root of that host.

Do I need a GPU for Immich?

No. Face recognition, smart search and video transcoding run on the CPU by default. Hardware acceleration for machine learning or transcoding is optional and needs a supported GPU and the extra hwaccel files from the release.

Which HyperDC servers can run Immich?

Immich runs in Docker on a HyperDC Linux VPS, VDS or dedicated server with root access. Plan at least 6 GB of RAM, SSD storage for the database and enough disk for your library plus 10 to 20 percent for thumbnails and transcoded videos.

Sources

Generer passord

Please confirm