Skip to main content

On a NAS

The NAS that runs Immich runs this too, on its own, and makes the whole film there. A GPU or a model makes it better later (what each one adds). The install is the Docker Compose one; this page is what is different on a Synology, QNAP, TrueNAS or Unraid box. It has run on a Synology DS423+ (Celeron J4125, four cores); when, and on which release: Supported and tested.

Install​

Synology Container Manager, QNAP Container Station, TrueNAS SCALE Apps and the Unraid Docker Compose Manager plugin all take the compose file as a project. Put docker-compose.yml and your .env (from example.env) in the project folder, create an output folder beside them, and start the project. Then, from an SSH session in that folder:

sudo docker compose exec immich-memories immich-memories models fetch
sudo docker compose exec immich-memories immich-memories preflight

The compose file uses tier: auto, which picks the nas tier here: the eight context heads and two detectors run on the NAS CPU, and no caption or model service is needed.

Set the home base in .env before the first cut (IMMICH_MEMORIES_TRIPS__HOMEBASE_LATITUDE and ..._LONGITUDE). It also picks your country's public holidays. Without it no day counts as away from home, so a three-week holiday arrives as three weekly stories instead of one trip. Then confirm who's who once: Teach it your family.

The output folder​

The container runs as UID 1000. On Synology the folder a DSM user creates belongs to that user, usually not 1000, and the first cut refuses with Output directory is not writable. Either sudo chown -R 1000:1000 output over SSH, or set user: "<your uid>:<your gid>" on the service (id prints them) and chown the config volume to match. If neither suits, drop the ./output mount and turn on upload-back: the film goes to Immich instead.

Do not use cpus: on a Synology​

cpus: is a CFS quota, and DSM runs a cgroup v1 kernel built without the CFS bandwidth controller. A DS423+ answers docker compose up with NanoCPUs can not be set, as your kernel does not support CPU CFS scheduler or the cgroup is not mounted and starts nothing. The shipped file sets no CPU limit for that reason. To keep cores free for Immich, pin them instead:

    cpuset: "0-2"      # three of four cores; works without CFS

Memory limits work on every NAS tested.

Reaching the UI​

The UI is on the NAS's loopback only. From your desktop:

ssh -L 8080:localhost:8080 you@your-nas

then open http://localhost:8080. To put it on the LAN instead, turn on authentication first, then change the mapping to "8080:8080". UniFi and other NAS apps often hold 8080 already: change the left side (127.0.0.1:8081:8080) and tunnel to that port.

What to expect​

The first cut of a month reads every picture it can reach once, on the NAS CPU, and banks the answers. Run it in the evening. Later cuts reuse matching facts; new pictures and changed producers can require more work. immich-memories runs show prints where the time went, phase by phase and per picture. NAS timings are being re-measured; Measured has the rest.

Start with one month, not a year: preparation grows with the pictures in the window, not with the length of the film. To read a bigger window ahead of time, run immich-memories prepare --year 2025 overnight; later cuts inside it start warm.

Encoding​

The default codec is H.264, which Intel Quick Sync encodes in hardware. Pass the render node through to use it; the compose file carries the block commented out:

    devices:
- /dev/dri:/dev/dri
group_add:
- "937" # the GID that owns /dev/dri/renderD128 on DSM

stat -c '%g' /dev/dri/renderD128 on the host prints the GID. Without group_add the device is there and the container cannot open it. More on Hardware encoding.

With output.codec: h265, remember that Gemini Lake (the J4125 class) has no HEVC encode: that part goes to software, and the log says vaapi cannot encode h265 on this device. ARM NAS models have no hardware encoder here at all.

The J4125 has no AVX either, so the CPU fallback draws the titles instead of the animated kernels: CPUs without AVX.

Long films​

A long album on two cores is a long encode, and after the music is mixed in the app decodes the whole film once to prove it plays. That check can take as long again as a 1080p encode, logs Checking the finished film: ... decoded once a minute, and a film that fails it stays on disk: Troubleshooting. Keep 4K for a box with more cores, or send the render to a GPU box.

Memory and disk​

The 4 GB limit in the compose file is what the tested runs used. The render blends one clip at a time, so its memory does not grow with the number of clips.

Size cache.thumbnail_cache_max_size_mb against your library: too small and the next overlapping memory downloads every preview again, which on a NAS is the slow part. The budget per picture is in the config reference.

A NAS volume is usually the smallest disk in the setup, and often shared with everything else on the box. A run that uploads to Immich has its local film removed as soon as the upload is confirmed, so nightly automation does not grow output.directory on its own. A run kept local (upload_enabled: false, or a delivery that stays pending) does not clean up on its own: watch it with immich-memories runs storage and clear it with runs delete. Below output.min_free_space_gb (5 GB by default) on the output or cache volume, a run warns; if a film would not fit at all, the run stops before rendering rather than filling the volume mid-encode. See health, logs and caches.

What a NAS can't do​

  • Run GPU selection without GPU inference. A render-only GPU does not count. A configured LLM alone leaves selection on NAS, while still supplying titles and music mood: Add a reader.
  • Caption quickly on a small CPU. Use a GPU caption service for the selected shots and actual candidates. Captioning a whole library is a separate prepare job. An LLM can supply captions only with explicit opt-in, which is less efficient and can cost much more on hosted services: Add captions.
  • Generate music: MusicGen and ACE-Step want a GPU. The bundled tracks and your own uploads work.

Every night​

Uncomment IMMICH_MEMORIES_AUTOMATION__ENABLED and IMMICH_MEMORIES_AUTOMATION__DAILY_AT in the compose file and set TZ in .env. The UI process makes one memory a day by itself; there is no cron to install. Daily automation, which also says how the daily film reaches Immich.

Everything else​

Same container, same commands, prefixed with sudo over SSH on most NAS systems. On the Docker page: the API key, films into Immich, logs and health, backups and the store, updating, hardening and the add-ons.