# 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.

Difficulty: Intermediate\
Tested on: Ubuntu 24.04 LTS, Ubuntu 26.04 LTS, Debian 12, Debian 13

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.

> **Note**
>
> Immich's own documentation asks you to follow a 3-2-1 backup strategy. Immich is where your photos live, not a backup of them, so plan the backup section of this guide before you upload your library.

## 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](/guides/secure-a-new-linux-server) and [Set up SSH keys](/guides/ssh-keys).
- Docker Engine with the Compose plugin from Docker's repository: [Ubuntu](/guides/install-docker-ubuntu) or [Debian](/guides/install-docker-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](/guides/caddy-reverse-proxy), and a subdomain such as `photos.example.com` pointing at the server.

| Resource | Minimum (official) | Suggested starting point |
|---|---|---|
| RAM | 6 GB (8 GB recommended); 4 GB possible with machine learning disabled | 8 GB |
| CPU | 2 cores (4 recommended) | 4 vCPUs |
| Disk | Unix filesystem with ownership and permissions (ext4, ZFS); database on local SSD, never a network share | SSD 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](https://github.com/immich-app/immich/releases), 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.

> **Note**
>
> Outbound port 25 is closed by default on HyperDC VPS. For services bought for a term of 3 months or longer, it is opened on request: [open a support ticket](/guides/support-tickets). Until then, send mail through an SMTP relay on port 587.

## 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](/guides/nginx-reverse-proxy-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:

> **Danger**
>
> `docker compose down -v` and `rm -rf ./postgres` delete the current Immich database. Run them only on a fresh installation or when you are sure you want to replace everything with the backup.

```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](/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

- Learn the Compose file format in [Docker Compose basics](/guides/docker-compose-basics).
- Read more about site blocks and certificates in [How to set up Caddy as a reverse proxy](/guides/caddy-reverse-proxy).
- Add file sync next to your photos with [Nextcloud All-in-One](/guides/install-nextcloud-aio).
- Compare servers for photo libraries on the [Immich hosting](/immich-hosting) page.
- Read the [Immich documentation](https://docs.immich.app/) for external libraries, OAuth and more.

## 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.

---

Source: <https://hyperdc.com/guides/tutorials/install-immich>\
Updated: 2026-10-09
