> ## Content Index
> Fetch the complete content index at: https://articles.akadata.co.uk/llms.txt
> Use this file to discover other available public pages before exploring further.

# Immich, Photos and Videos Using WSL2, EXT4 Partition, and Full Speed Storage, also Docker and TrueNAS
- URL: https://articles.akadata.co.uk/self-hosting-immich-with-wsl2-ext4-nvme-the-ultimate-windows-setup-2/
- Published: 2025-02-26T05:59:40.000Z
- Updated: 2025-03-29T22:16:00.000Z
- Author: AKADATA

## [Introduction: What Is Immich?](#Introduction: What Is Immich?)

**Immich** is an open-source, self-hosted media solution that aims to be a privacy-focused alternative to services like Google Photos or iCloud. It offers AI-powered features such as face detection, object recognition, and automatic organization of your media libraries. Immich also provides mobile apps (iOS/Android), so you can automatically back up photos and videos from your phone, before you ask if I completed the task? Yes I did and below are the lessons learned and why you may not want to try the windows way at first.

> You want a robust, private photo/video management platform without the usual cloud fees or privacy trade-offs? Immich is well worth a look.

However, running Immich on **Windows** can be challenging, mainly if you rely on Docker Desktop's default setup. This guide shows you how to **bypass** Docker Desktop's 1TB virtual disk limit by attaching a **raw NVMe disk** (formatted as **EXT4**) inside **WSL2**. This gives you near-native Linux performance, no NTFS bottlenecks, and straightforward GPU acceleration.

---

## [Why This Blog Matters](#Why This Blog Matters)

Suppose you have thousands (or even hundreds of thousands) of photos and videos. In that case, you need reliable local storage with high performance—especially if you're performing AI-driven tasks like face recognition. Attempting this with Docker Desktop on Windows often hits the **1TB VHDX limit**. It can suffer from poor performance when using NTFS-based volumes.

**Enter WSL2** with pass-through NVMe and **EXT4**: There are no more NTFS bottlenecks, and the disk remains safe if WSL or Docker fails. Immich takes care of AI-based organization, face detection, and blazing performance, creating a near-perfect local media solution on Windows.

---

## [Common Issues with Running Immich on Windows](#Common Issues with Running Immich on Windows)

1. **VHDX Storage Limit** → Docker Desktop often maxes out at \~1 TB per WSL2 instance unless you use complicated manual resizing.
2. **NTFS Performance Bottlenecks** → Large media files can slow down and crawl due to NTFS overhead. Docker volumes on NTFS can be painfully slow.
3. **GPU Acceleration Problems** → Configuring NVIDIA CUDA or Intel QuickSync through Docker Desktop can be limiting. Meanwhile, WSL2 supports these more directly.

## [The Game-Changer: WSL2 + EXT4 NVMe](#The Game-Changer: WSL2 + EXT4 NVMe)

- **WSL2** provides a native Linux environment within Windows.
- **Raw NVMe SSD** (formatted as **EXT4**) bypasses NTFS overhead.
- **The Docker inside WSL2** eliminates the 1TB VHDX limit, offering native disk speed.
- **Hardware Acceleration** can be split:
  - **CUDA (NVIDIA RTX)** for AI tasks (face/object detection).
  - **QuickSync (Intel iGPU)** for video transcoding.

The result? High-performance photo and video management without Docker Desktop's usual restrictions.

## [Why Immich with WSL2 & EXT4?](#Why Immich with WSL2 & EXT4?)

- **Avoid NTFS Bottlenecks** → EXT4 read/write operations are much faster for large media libraries.
- **Bypass 1TB VHDX Limit** → Use a raw NVMe disk or partition directly.
- **GPU Acceleration** → Windows 11 Pro + WSL2 supports CUDA and (partially) QuickSync.
- **Lower Overhead** → WSL2 runs near-native Linux performance.
- **Future Expandability** → Migrate seamlessly to TrueNAS, a dedicated Linux server, or Kubernetes.

## [High-Level Flow](#High-Level Flow)

1. **Install WSL2 & Docker Desktop** on Windows 11 (enabling WSL2 backend).
2. **Attach & Format** a raw NVMe disk as EXT4 via wsl --mount.
3. **Configure Docker** to store Immich volumes on that disk (e.g., /mnt/immich).
4. **Set Up Immich** with optional hardware acceleration.
5. **Enjoy** a fast, scalable, private media library.

---

## [Step 1: Install WSL2 & Docker Desktop](#Step 1: Install WSL2 & Docker Desktop)

### [A. Enable WSL2](#A. Enable WSL2)

```powershell
wsl --install -d Ubuntu

```

Do as you are `Microsoft Told` and `reboot` when prompted, then launch Ubuntu from the Start menu. Or as I do open `cmd` prompt and type `wsl` 

### [B. Install Docker Desktop](#B. Install Docker Desktop)

- [Download Docker Desktop](https://docs.docker.com/desktop/windows/install/?ref=articles.akadata.co.uk) for Windows.
- [**Enable WSL2 backend**](https://docs.docker.com/desktop/features/wsl/?ref=articles.akadata.co.uk) during installation.
- [**Turn on WSL integration**](https://docs.docker.com/desktop/features/wsl/?ref=articles.akadata.co.uk) for your Ubuntu distro in Docker Desktop.

> **Pitfall**: If you install Docker Desktop but never enable WSL2 integration, you’ll be stuck with slower Hyper-V performance.

---

## [Step 2: The Important Step - Attach a Raw NVMe Disk in WSL2](#Step 2: The Important Step - Attach a Raw NVMe Disk in WSL2)

It's your life or your data, the disk is offline? Isn't it?

### [A. Before you start, be nice to WSL and shut it down](#A. Before you start, be nice to WSL and shut it down)

Using `cmd` prompt or `powershell` ignore `I:\immich` this is not the `disk`

![](https://articles.akadata.co.uk/content/images/2025/02/image-32.png)

### [B. Identify Your NVMe Disk](#B. Identify Your NVMe Disk)

In **PowerShell**:

```powershell
Get-Disk

```

![](https://articles.akadata.co.uk/content/images/2025/02/image-41.png)

Check the **FriendlyName** and **Size** fields to confirm which disk is your NVMe.

![](https://articles.akadata.co.uk/content/images/2025/02/image-33.png)

> **Take it offline** (example uses disk 2): **WARNING**: Close Disk Management before you proceed, It block the next step if left open.

You can safely take the disk offline if it is not *being used*, Windows may complain if you have a SWAP file on that disk so check and take action. 

Then using [PowerShell Set-Disk](https://learn.microsoft.com/en-us/powershell/module/storage/set-disk?view=windowsserver2025-ps&ref=articles.akadata.co.uk) proceed to set Drive Number 2 offline with `-isOffline` `$true`. 

```powershell
; Offline
Set-Disk -Number 2 -IsOffline $true

; Online
Set-Disk -Number 2 -IsOffline $false
```

![](https://articles.akadata.co.uk/content/images/2025/02/image-29.png)

Powershell showing the disk offline we are looking to format with EXT4

### [Confirm in **Disk Management** ](#Confirm in Disk Management )

(`diskmgmt.msc`) that it’s now offline.

![](https://articles.akadata.co.uk/content/images/2025/02/image-31.png)

We wee Highlighted Disk 2 Partition 2 and Disk 2 is shown as Offline

> **Important**: Mixing up disk numbers can lead to catastrophic data loss. Always double-check! did you check twice? just look again to make sure!

### [B. Format & Mount in WSL2](#B. Format & Mount in WSL2)

**Make it Persistent** using either `wsl --mount` each time or an **fstab** entry inside WSL. Typically, you’ll first create a mount point: *(I think I have missed a step here, sure someone will point that out, `wsl --mount` is going to be important later.)*

### [**WSL Time: Mount** the raw disk: ](#WSL Time: Mount the raw disk: )

Using [wsl --mount](https://learn.microsoft.com/en-us/windows/wsl/wsl2-mount-disk?ref=articles.akadata.co.uk) we mount our disk and partition and tell `wsl` it is expected in `ext4`. if you have not formatted the drive this will fail.

```powershell
wsl --mount \\.\PHYSICALDRIVE2 --partition 2 --type ext4 --bare

```

Did you forget you need to use an Administrative cmd prompt for this, Right click and run that command as Admin or you will see this

![](https://articles.akadata.co.uk/content/images/2025/02/image-34.png)

Adjust `--partition 2` if needed, run with an Administrator account.

![](https://articles.akadata.co.uk/content/images/2025/02/image-35.png)

If it is mounted and you happen to run the same command again you will see.

![](https://articles.akadata.co.uk/content/images/2025/02/image-36.png)

> **When it Goes Wrong! Oh yea it's going to work, for how long?**If you pick the wrong disk or partition, data loss can happen.Using `fdisk` incorrectly can render your disk unbootable.Always back up data and confirm the disk number carefully.

---

Note that `**wsl --mount**` (run from Windows) is still needed after a full reboot to attach the disk into WSL. Once that’s done, WSL processes `fstab` to mount it inside your Ubuntu environment.

### [Start WSL](#Start WSL)

**(Optional) Repartition or Format** if required. For example:

```bash
sudo fdisk  /dev/disk/by-id/scsi-SNVMe_Seagate_FireCuda6479_A77A_AF00_25C6.

```

You might see:

```
Disk /dev/disk/by-id/scsi-SNVMe_Seagate_FireCuda6479_A77A_AF00_25C6.: 1.82 TiB, 2000398934016 bytes, 488378646 sectors
Disk model: Seagate FireCuda
Units: sectors of 1 * 4096 = 4096 bytes
Sector size (logical/physical): 4096 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: D5E9559A-23B3-45F5-9B69-B973A75840A4

Device                                                                Start       End   Sectors  Size Type
/dev/disk/by-id/scsi-SNVMe_Seagate_FireCuda6479_A77A_AF00_25C6.-part1     6      4095      4090   16M Microsoft reserved
/dev/disk/by-id/scsi-SNVMe_Seagate_FireCuda6479_A77A_AF00_25C6.-part2  4096 488378367 488374272  1.8T Microsoft Basic data

```

If it’s labeled **Microsoft basic data**, change it to **Linux filesystem**: *(Type 20 and L to list codes)*

```
Command (m for help): t
Partition number (1,2, default 2): 2
Partition type or alias (type L to list all): 20
Command (m for help): w

```

### [Format the NVMe disk or partition: ](#Format the NVMe disk or partition: )

Before proceeding, be aware you will wipe the data at this point, now note the UUID of that disk , it's apparent it may not always be in the same place so we can not rely on names.

> **Warning**: Formatting erases **all data** on that partition which was likely NTFS, there is little come back from here the data is not to be seen in windows at this point on.

```bash
sudo mkfs.ext4 /dev/disk/by-id/scsi-SNVMe_Seagate_FireCuda6479_A77A_AF00_25C6.-part2

BLK_UUID=$(sudo blkid | grep /dev/disk/by-id/scsi-SNVMe_Seagate_FireCuda6479_A77A_AF00_25C6.-part2 | cut -d"\"" -f2)

echo $BLK_UUID

```

```text
 6dfddfd3-0eb2-42d3-9069-1b57cd8e88bb
```

```bash
sudo mount  UUID=$BLK_UUID /mnt/immich/
```

```bash
sudo mkdir -p /mnt/immich
sudo mount /dev/disk/by-id/scsi-SNVMe_Seagate_FireCuda6479_A77A_AF00_25C6.-part2 /mnt/immich

```

###  Then if you want it to auto-mount within WSL: *(was this the right way to do it? time will tell)*

```bash
echo "UUID="6dfddfd3-0eb2-42d3-9069-1b57cd8e88bb" /mnt/immich ext4 defaults 0 1" | sudo tee -a /etc/fstab
sudo mount -a

```

Assume Docker will move the disk around the data intact we mount using the UUID. Remember to sudo your mount.

![](https://articles.akadata.co.uk/content/images/2025/02/image-38.png)

## [Step 3: Configure Docker for Immich](#Step 3: Configure Docker for Immich)

### [A. Prepare Volumes](#A. Prepare Volumes)

You got this far and you are working through this doing it alone then assuming you have your NVMe mounted on /mnt/immich/ you can copy paste three lines below.

Before you proceed, make a note of the new UUID of the disk added, it's apparent it may not always be in the same place so we can not rely on disk names, 

![](https://articles.akadata.co.uk/content/images/2025/02/image-37.png)

Here we keep the disk, partition and UUID

```text
/dev/disk/by-id/scsi-SNVMe_Seagate_FireCuda6479_A77A_AF00_25C6.-part2 
/dev/sd|x|2: 
UUID="6dfddfd3-0eb2-42d3-9069-1b57cd8e88bb"
```

```bash
sudo mkdir -p /mnt/immich/storage /mnt/immich/db /mnt/immich/model-cache
sudo chown -R 999:999 /mnt/immich/db /mnt/immich/model-cache
sudo chmod -R 777 /mnt/immich/storage /mnt/immich/db /mnt/immich/model-cache

```

- `999:999` often matches the default Postgres UID/GID.
- `777` ensures the Immich containers can write to these paths.

### [B. Prepare Docker](#B.  Prepare Docker)

### [1.Clone immich ](#1.Clone immich )

For this article I forked [immich ](https://github.com/immich-app/immich?ref=articles.akadata.co.uk)from its home, a branch with the changes below and maybe a letsbelasy script to help help you along on Windows. 

```bash
cd /mnt/immich/
git clone https://github.com/akadatalimited/immich.git
cd immich
ls
```

### [Set Up Docker Compose](#Set Up Docker Compose)

Create a `.env` file (example): this 

```ini
IMMICH_VERSION=release
UPLOAD_LOCATION=/mnt/immich/storage
DB_DATA_LOCATION=/mnt/immich/db
TZ=Europe/London
DB_PASSWORD=YourSuperSecret
DB_USERNAME=postgres
DB_DATABASE_NAME=immich

```

Sample `docker-compose.yml` snippet:

```yaml
#
# WARNING: To install Immich, follow our guide: https://immich.app/docs/install/docker-compose
#
# Make sure to use the docker-compose.yml of the current release:
#
# https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
#
# The compose file on main may not be compatible with the latest release.

name: immich

services:
  immich-server:
    container_name: immich_server
    image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
    extends:
      file: hwaccel.transcoding.yml
      service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
    volumes:       # Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
      - ${UPLOAD_LOCATION}:/usr/src/app/upload
      - /etc/localtime:/etc/localtime:ro
    env_file:
      - .env # Blog: Immich on Windows 11 with WSL2, EXT4 NVMe, and Hardware Acceleration
    ports:
      - '2283:2283'
    depends_on:
      - redis
      - database
    restart: always
    healthcheck:
      disable: false

  immich-machine-learning:
    container_name: immich_machine_learning
    # For hardware acceleration, add one of -[armnn, cuda, openvino] to the image tag.
    # Example tag: ${IMMICH_VERSION:-release}-cuda
    image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
    # extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration
    #   file: hwaccel.ml.yml
    #   service: cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference - use the `-wsl` version for WSL2 where applicable
    volumes:
      - model-cache:/cache
    env_file:
      - .env
    restart: always
    healthcheck:
      disable: false

  redis:
    container_name: immich_redis
    image: docker.io/redis:6.2-alpine@sha256:148bb5411c184abd288d9aaed139c98123eeb8824c5d3fce03cf721db58066d8
    healthcheck:
      test: redis-cli ping || exit 1
    restart: always

  database:
    container_name: immich_postgres
    image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_DB: ${DB_DATABASE_NAME}
      POSTGRES_INITDB_ARGS: '--data-checksums'
    volumes:
      # Do not edit the next line. If you want to change the database storage location on your system, edit the value of DB_DATA_LOCATION in the .env file
      - ${DB_DATA_LOCATION}:/var/lib/postgresql/data
    healthcheck:
      test: >-
        pg_isready --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" || exit 1;
        Chksum="$$(psql --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" --tuples-only --no-align
        --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')";
        echo "checksum failure count is $$Chksum";
        [ "$$Chksum" = '0' ] || exit 1
      interval: 5m
      start_interval: 30s
      start_period: 5m
    command: >-
      postgres
      -c shared_preload_libraries=vectors.so
      -c 'search_path="$$user", public, vectors'
      -c logging_collector=on
      -c max_wal_size=2GB
      -c shared_buffers=512MB
      -c wal_compression=on
    restart: always

volumes:
  immich-storage:
    driver: local
    driver_opts:
      type: none
      device: /mnt/immich/storage
      o: bind

  immich-db:
    driver: local
    driver_opts:
      type: none
      device: /mnt/immich/db
      o: bind

  model-cache:
    driver: local
    driver_opts:
      type: none
      device: /mnt/immich/model-cache
      o: bind

```

### C. Start Immich

```bash
docker-compose up -d

```

![](https://articles.akadata.co.uk/content/images/2025/02/image-42.png)

Does not take long on a modern internet connection, 

![](https://articles.akadata.co.uk/content/images/2025/02/image-45.png)

Head to `http://localhost:2283`. Create your initial admin user and begin exploring Immich.

![](https://articles.akadata.co.uk/content/images/2025/02/image-47.png)

![](https://articles.akadata.co.uk/content/images/2025/02/image-50.png)

Click through the welcome screen, learn and configure and have an amazing day. 

![](https://articles.akadata.co.uk/content/images/2025/02/image-51.png)

> **Log checks**:

![](https://articles.akadata.co.uk/content/images/2025/02/image-48.png)

---

## [GPU Acceleration & Advanced Tweaks](#GPU Acceleration & Advanced Tweaks)

Running Immich on Windows via WSL2 is fantastic for CPU tasks, but if you want to leverage **GPU acceleration**—especially for machine learning or video transcoding—you must ensure:

1. [**NVIDIA Setup on Windows**:](#NVIDIA Setup on Windows:)
  - Install the **latest NVIDIA driver** (with WSL support) on Windows.
  - Confirm `nvidia-smi` works on the **Windows** side. For example, open Command Prompt or PowerShell and run `nvidia-smi`.
  - (Optional) Install CUDA (e.g., CUDA 12.x) on Windows if you plan to develop or run advanced GPU code outside Docker.
  - WSL2 will pass your GPU through automatically if the driver is up to date.
2. [**Confirming GPU Visibility in WSL2**:](#Confirming GPU Visibility in WSL2:)
  - Run `nvidia-smi`. It should show your GPU.
  - If it does not, verify you have the correct driver version on Windows, and that your WSL is up to date.
3. [**Machine Learning Container (immich-machine-learning)**:](#Machine Learning Container %28immich-machine-learning%29:)
  - Immich’s ML container supports CUDA or OpenVINO. For CUDA, set the container image to `ghcr.io/immich-app/immich-machine-learning:release-cuda`.
  - In your `docker-compose.yml`, enable the **extends** section (e.g., `hwaccel.ml.yml`) to map the GPU into the container.
4. [**Transcoding (immich-server)**:](#Transcoding %28immich-server%29:)
  - Immich can transcode videos with FFmpeg using NVENC (NVIDIA) or potentially `qsv` (Intel).
  - For NVIDIA, set `immich-server` to use a hardware-accelerated config (e.g., `hwaccel.transcoding.yml`) specifying `service: nvenc` or `service: cuda`.
  - Confirm GPU usage in logs or by checking `docker logs immich_server`.
5. [**Testing AI/ML Functions**:](#Testing AI/ML Functions:)
  - Once everything is running, Immich’s face recognition or object detection should automatically use the GPU if configured.
  - You can upload a set of photos with faces, then watch the **immich\_machine\_learning** logs to confirm it’s processing them with CUDA.

### [After launching, check logs:](#After launching, check logs:)

```bash
docker logs immich_machine_learning --tail 100 --follow

```

It may log messages about finding a GPU or using CUDA. If it does, you’re set!

Inside Ubuntu on WSL2, install the `nvidia-cuda-toolkit` or at least the CLI tools if you want to run `nvidia-smi` in WSL. Example:

```bash
sudo apt update && sudo apt install -y nvidia-cuda-toolkit

```

> **Intel QuickSync**: While theoretically possible, it’s not fully reliable in WSL2\. Some users see `qsv` in `ffmpeg -hwaccels`, but transcoding might fail. If your iGPU is recognized, you can attempt `vaapi-wsl`. Otherwise, rely on CPU or NVIDIA.

> **AMD GPUs**: Partial support might be possible via `vaapi-wsl`, but official AMD GPU pass-through in WSL2 is limited. NVIDIA is the most reliable.

### [**How Immich’s Containers Talk**:](#How Immich’s Containers Talk:)

- **immich-server**: The main API and web endpoint.
- **immich-machine-learning**: Provides AI features (face/object detection). Communicates with `immich-server` over Docker’s internal network.
- **database (Postgres)**: Stores metadata, user data, etc.
- **redis**: Provides caching.

By default, Docker Compose still creates a virtual network for service-to-service communication (they find each other by container name). Meanwhile, we’ve explicitly bound each service’s data to `/mnt/immich` via local volumes, ensuring everything is stored on your EXT4 disk in WSL2 rather than a default Docker Desktop VHDX.

---

## [Potential Pitfalls & Performance Considerations](#Potential Pitfalls & Performance Considerations)

While this setup often runs smoothly, it’s not always bulletproof:

```wsl
The Windows Subsystem for the Linux instance has terminated.
Error code: Wsl/Service/0x80072745
```

**Attempt WSL Recovery**: Open a new PowerShell window as admin and run:

```powershell
# Cleanly shut down any running WSL instances
wsl --shutdown

# Optionally, you can also try
Restart-Service LxssManager -Force

```

Then relaunch your WSL distro (`wsl`) and check if the environment recovers without a full system reboot.

**Large Upload Freezes**: If you attempt massive uploads (e.g., 0.5 TB from a mobile device), WSL can sometimes hang or crash. You might see errors like:

```powershell
wsl
The Windows Subsystem for Linux instance has terminated.
Error code: Wsl/Service/0x80072745

```

In some cases, the screen might go black for 60–90 seconds before recovering. If this happens repeatedly, try:

In some cases, the screen might go black for 60–90 seconds before recovering. If this happens repeatedly, try throttling uploads, splitting them into smaller batches, or verifying that your GPU drivers and Docker setup are stable.

## [Checking Your Directory Structure](#Checking Your Directory Structure)

After you start uploading content, you’ll notice folders and files being created under `/mnt/immich`. For instance, here’s an example structure:

```bash
smalley@demoa:/mnt/c/Users/kingd$ sudo ls /mnt/immich/*

/mnt/immich/db:
PG_VERSION  current_logfiles  log           pg_dynshmem  pg_ident.conf  pg_multixact  pg_replslot  pg_snapshots  pg_stat_tmp  pg_tblspc    pg_vectors  pg_xact      postgresql.conf  postmaster.pid
base        global            pg_commit_ts  pg_hba.conf  pg_logical     pg_notify     pg_serial    pg_stat       pg_subtrans  pg_twophase  pg_wal      postgresql.auto.conf postmaster.opts

/mnt/immich/lost+found:

/mnt/immich/model-cache:
clip  facial-recognition

/mnt/immich/storage:
backups  encoded-video  library  profile  thumbs  upload

```

- **/mnt/immich/db**: Stores the Postgres database files.
- **/mnt/immich/model-cache**: Caches machine-learning models or data (e.g., CLIP, face recognition data).
- **/mnt/immich/storage**: Houses user-uploaded media, thumbnails, backups, etc.

This confirms your Immich instance is actively reading/writing data to the raw disk on WSL2.

## [Final Thoughts & Future Enhancements](#Final Thoughts & Future Enhancements)

By combining **WSL2**, **EXT4**, and **NVMe**, you avoid Docker Desktop’s 1TB limit, gain near-native performance for large media libraries, and unlock Immich’s full AI/ML potential.

### [Future Topics](#Future Topics)

- Automating WSL2 Mounts on Boot
- Trying ZFS on WSL2 for deduplication
- Expanding beyond 2TB with multiple drives
- Integrating Immich with Google/Amazon Photos for hybrid storage
- Using VPN-bonded or bridged networks for faster remote access

Until next time—**happy hosting!** 🚀

---

## [Want the Docker Way (with Its Limits)?](#limits)

If you’d rather use Docker Desktop alone (or Docker on TrueNAS, Ubuntu, etc.) and can accept potential size/performance limits, Immich is more straightforward to install:

### [Docker Desktop / Windows](#Docker Desktop / Windows)

```powershell
docker volume create immich-data

docker run -d `
  --name immich_db `
  -v immich-data:/var/lib/postgresql/data `
  -e POSTGRES_USER=postgres `
  -e POSTGRES_PASSWORD=YourPass `
  -p 5432:5432 `
  postgres:14

# Then Immich:
docker run -d --name immich_server -p 2283:2283 ^
ghcr.io/immich-app/immich-server:release

```

### [TrueNAS Scale](#TrueNAS Scale)

- Search for **Immich** in the Apps catalog or manually add the Docker image.

### [Linux Docker (Any Distro)](#Linux Docker %28Any Distro%29)

```bash
# For Postgres:
docker run -d \
  --name immich_db \
  -v /path/on/host/db:/var/lib/postgresql/data \
  -e POSTGRES_USER=postgres \
  -e POSTGRES_PASSWORD=YourPass \
  -p 5432:5432 \
  postgres:14

# For Immich:
docker run -d \
  --name immich_server \
  -v /path/on/host/storage:/usr/src/app/upload \
  -p 2283:2283 \
  ghcr.io/immich-app/immich-server:release

```

Remember, Docker Desktop relies on a **VHDX** file that can be limited in size and performance. If that’s enough for you or you just don’t want to mess with WSL2—this is still a valid approach and one much less painful

---

## [Further Reading](#Further Reading)

- **Immich Documentation**: [immich.app](https://immich.app/docs?ref=articles.akadata.co.uk) – Official install guides, environment variables, hardware acceleration.
- **WSL Official Docs**: [docs.microsoft.com/windows/wsl/](https://docs.microsoft.com/windows/wsl/?ref=articles.akadata.co.uk) – Details on `wsl --mount`, fstab usage, and advanced config.
- **Docker on WSL2**: [Docker Docs](https://docs.docker.com/desktop/windows/wsl/?ref=articles.akadata.co.uk) – Tips for best performance.
- **GPU Acceleration**: [NVIDIA on WSL2](https://developer.nvidia.com/cuda/wsl?ref=articles.akadata.co.uk) – Details on enabling CUDA.

## [Warning](#Warning)

Let's wrap this up with a heads-up—a disclaimer, if you will. This setup won't survive a reboot without manual intervention. You'll need to re-import the disk into WSL, remount it to /mnt/immich, and restart the Docker Compose stack. Yep, I learned that the hard way, and here we are, cutting this blog short with that reality in mind.

That said, my data is safe and intact. Getting things back up and running is just a matter of time—just be mindful of upload speeds. Everything went sideways when I installed the Immich app on my S23 Ultra and tried uploading two years of files.

Happy tweaking, my friends! Enjoy your self-hosted Immich setup and experiment with different storage solutions and optimizations. If you hit any roadblocks, the Immich community on GitHub and Discord is always there to help.

Happy hosting! 🚀