---
title: "Immich — RAM Requirements and OOM Recovery in LXC"
aliases: [immich-oom, immich-ram, immich-lxc, immich-memory]
tags: [immich, lxc, proxmox, homelab, ram, oom, selfhosted, photos]
sources:
  - "daily/2026-04-24.md"
created: 2026-04-24
updated: 2026-04-24
---

# Immich — RAM Requirements and OOM Recovery in LXC

Immich (the self-hosted photo/video backup service) consumes approximately 5–5.5 GB of RAM under load inside a Proxmox LXC container. Allocating only 6 GB leaves almost no headroom — the `immich-web.service` will crash with an OOM kill when the ML service and web service are both active. Without an explicit `OOMPolicy=continue` in the systemd unit, the service stays dead after the OOM kill and photo sync stops silently.

## Key Points

- **Immich peak RAM: ~5–5.5 GB** in LXC during active sync (web + ML services combined)
- **6 GB allocation is insufficient** — only ~500 MB–1 GB headroom; OOM under any load spike
- **`immich-web.service` does not auto-restart after OOM by default** — systemd's default OOMPolicy kills the service and doesn't restart it
- **Fix:** add `MemoryMax=7G`, `OOMPolicy=continue`, `RestartSec=10` to the unit file — service restarts automatically on OOM instead of staying dead
- **Recommended allocation: 8 GB** — gives ~2.5 GB headroom above peak consumption
- The ML service (`immich-machine-learning`) can be briefly unhealthy (~27 sec) during startup and will self-recover; this is normal and does not require intervention

## Details

### The Failure Pattern

The incident on 2026-04-24 illustrates the silent failure mode:

1. `immich-ml.service` starts, briefly unhealthy at 11:12 — recovers on its own (~27 sec)
2. During a sync load spike at 11:39, RSS climbs to 5.1 GB out of 6 GB allocated
3. Linux OOM killer fires, kills `immich-web.service`
4. systemd's default behavior: service enters `failed` state, no restart
5. User notices phone sync stopped — no visible error until `journalctl` is checked

The result: Immich appeared "running" (ML service up, container up) but photos were not syncing. `curl http://<IP>:2283/api/server-info/ping` returns connection refused until `immich-web.service` is manually restarted.

### RAM Sizing Guide

| Allocation | Headroom at 5.5 GB load | Verdict |
|------------|------------------------|---------|
| 4 GB | None — crashes at startup | Too small |
| 6 GB | ~500 MB | Insufficient — OOMs under load |
| 8 GB | ~2.5 GB | Recommended for home use |
| 10 GB | ~4.5 GB | Comfortable for large libraries or active ML |

The ML service (face detection, CLIP embeddings) is the main RAM consumer during initial library scan. After the initial scan, steady-state RAM usage drops to ~2–3 GB.

### Systemd Unit Fix

Add memory limits and OOM recovery to `/etc/systemd/system/immich-web.service`:

```ini
[Service]
# ... existing directives ...

# Memory limit — prevents OOM from consuming the entire container
MemoryMax=7G

# OOM behavior — restart instead of dying permanently
OOMPolicy=continue
Restart=always
RestartSec=10
```

Apply the changes:
```bash
systemctl daemon-reload
systemctl restart immich-web
```

**`OOMPolicy=continue`** tells systemd to restart the service when the OOM killer fires. Without this, the default `OOMPolicy=stop` kills the service and leaves it in `failed` state.

**`MemoryMax=7G`** sets a hard memory ceiling (with 8 GB container, leaves 1 GB for the OS and other processes). This ensures the OOM killer targets `immich-web` specifically rather than randomly killing other processes.

### Verifying the Fix

After applying, confirm the unit loaded the new directives:
```bash
systemctl show immich-web --property=MemoryMax,OOMPolicy,RestartSec
# Expected: MemoryMax=7516192768 OOMPolicy=continue RestartSec=10000000
```

Monitor RAM usage over 24 hours with Beszel or `free -h` to confirm the container stays under the ceiling.

### Uptime Kuma Monitoring

Add an HTTP monitor for the Immich API endpoint to get alerted when the service is down:

- **URL:** `http://<CT_IP>:2283/api/server-info/ping`
- **Expected response code:** 200
- **Interval:** 60 seconds

This catches OOM-related outages within one minute rather than waiting for the user to notice missing phone backups.

## Related Concepts

- [[wiki/concepts/systemd-memory-oom-policy]] — the general systemd OOMPolicy + MemoryMax + RestartSec pattern applicable to any memory-constrained service
- [[wiki/concepts/ollama-lxc-ram-requirements]] — similar RAM-sizing challenge for Ollama in LXC (different overhead source: Intel oneAPI)
- [[wiki/concepts/uptime-kuma-socketio-management]] — Uptime Kuma for monitoring Immich API availability
- [[wiki/concepts/beszel-monitoring-deployment]] — Beszel for monitoring container-level RAM usage
- [[wiki/homelab/_index]] — homelab infrastructure context

## Sources

- [[daily/2026-04-24.md]] — immich-web.service OOM killed at 11:39 (5.1/6 GB), no auto-restart; CT 105 RAM raised 6→8 GB; MemoryMax=7G + OOMPolicy=continue + RestartSec=10 added to unit file; API confirmed healthy post-restart
