Immich Stack
Self-hosted photo and video management solution with facial recognition, object detection, and smart search - running natively on FreeBSD.

What is Immich?
Immich is a high-performance, self-hosted alternative to Google Photos. It provides automatic backup from mobile devices, facial recognition, object detection, location-based browsing, and a modern web interface. The Daemonless stack runs entirely on native FreeBSD - no Linux emulation required.
Architecture
The Immich stack consists of four containers:
| Service | Image | Description |
|---|---|---|
| Server | ghcr.io/daemonless/immich-server |
Main application server (Node.js) - Web UI and API |
| Machine Learning | ghcr.io/daemonless/immich-ml |
Python/ONNX service for facial recognition and smart search |
| PostgreSQL | ghcr.io/daemonless/immich-postgres |
Database with pgvector extension for ML embeddings |
| Redis | ghcr.io/daemonless/redis |
Cache and job queue |
PostgreSQL Version
immich-postgres:latest and :14 are both PostgreSQL 14 — the current default, matching upstream Immich.
New installs can use :18 (PostgreSQL 18). Upgrading an existing database requires a full dump/restore.
Upstream Immich is working on a migration path; we'll update these docs when that lands.
flowchart TD
Client[Mobile / Web Client]
Client -->|:2283| Server
subgraph stack [Immich Stack]
Server[immich-server<br/>Web UI + API]
Server -->|:3003| ML[immich-ml<br/>Python/ONNX]
Server -->|:5432| DB[immich-postgres<br/>pgvector]
Server -->|:6379| Redis[redis<br/>cache]
end
click Server "immich-server.md" "immich-server"
click ML "immich-ml.md" "immich-ml"
click DB "immich-postgres.md" "immich-postgres"
click Redis "redis.md" "redis"
Prerequisites
Before deploying, ensure your host environment is ready. See the Quick Start Guide for host setup instructions.
Requirements:
- FreeBSD 15.0 with Podman and ocijail
podman-compose- At least 4GB RAM (ML service is memory-intensive)
- Storage for photos (plan for growth)
Deploy
Requires a patched ocijail
Immich needs allow.mlock and allow.sysvipc jail parameters. See the ocijail patch guide before deploying.
1. Save as .env:
# The location where your uploaded files are stored
UPLOAD_LOCATION=./library
# The location where your database files are stored
DB_DATA_LOCATION=./postgres
# To set a timezone, uncomment and change Etc/UTC to a TZ identifier
# TZ=Etc/UTC
# Change to a random password (A-Za-z0-9 only)
DB_PASSWORD=postgres
# The values below do not need to be changed
###################################################################################
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
2. Save as compose.yaml:
name: immich
services:
immich-server:
container_name: immich_server
image: ghcr.io/daemonless/immich-server:latest
network_mode: host
volumes:
- ${UPLOAD_LOCATION}:/data
- /etc/localtime:/etc/localtime:ro
environment:
DB_HOSTNAME: localhost
REDIS_HOSTNAME: localhost
IMMICH_MACHINE_LEARNING_URL: http://localhost:3003
env_file:
- .env
depends_on:
- redis
- database
- immich-machine-learning
restart: always
immich-machine-learning:
container_name: immich_machine_learning
image: ghcr.io/daemonless/immich-ml:latest
network_mode: host
environment:
HF_HOME: /cache/huggingface # ML models are cached here
MPLCONFIGDIR: /tmp
volumes:
- model-cache:/cache
env_file:
- .env
restart: always
redis:
container_name: immich_redis
image: ghcr.io/daemonless/redis:latest
network_mode: host
volumes:
- /etc/localtime:/etc/localtime:ro
- redis-data:/config
restart: always
database:
container_name: immich_postgres
image: ghcr.io/daemonless/immich-postgres:14 # New installs can use :18
network_mode: host
annotations:
org.freebsd.jail.allow.sysvipc: "true"
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
volumes:
- /etc/localtime:/etc/localtime:ro
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
restart: always
volumes:
model-cache:
redis-data:
3. Deploy:
.env:
UPLOAD_LOCATION=/var/appjail-volumes/immich/library
DB_DATA_LOCATION=/var/appjail-volumes/immich/postgres
CACHE_LOCATION=/var/appjail-volumes/immich/cache
REDIS_DATA_LOCATION=/var/appjail-volumes/immich/redis
TZ=America/Caracas
DB_PASSWORD=postgres
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
DIRECTOR_PROJECT=immich
appjail-director.yml:
options:
# Equivalent to 'network_mode: host'
- alias:
- ip4_inherit:
services:
immich-server:
name: immich_server
priority: 100
options:
- from: ghcr.io/daemonless/immich-server:latest
volumes:
- immich-data: /data
oci:
environment:
- DB_HOSTNAME: 127.0.0.1
- REDIS_HOSTNAME: 127.0.0.1
- IMMICH_MACHINE_LEARNING_URL: http://127.0.0.1:3003
- TZ: !ENV '${TZ}'
immich-machine-learning:
name: immich_machine_learning
options:
- from: ghcr.io/daemonless/immich-ml:latest
oci:
environment:
- HF_HOME: /cache/huggingface
- MPLCONFIGDIR: /tmp
- TZ: !ENV '${TZ}'
volumes:
- model-cache: /cache
redis:
name: immich_redis
options:
- from: ghcr.io/daemonless/redis:latest
oci:
environment:
- LANG: C.UTF-8
- TZ: !ENV '${TZ}'
volumes:
- redis-data: /config
database:
name: immich_postgres
options:
- from: ghcr.io/daemonless/immich-postgres:latest
- template: !ENV '${PWD}/immich-postgres-template.conf'
oci:
environment:
- POSTGRES_PASSWORD: !ENV '${DB_PASSWORD}'
- POSTGRES_USER: !ENV '${DB_USERNAME}'
- POSTGRES_DB: !ENV '${DB_DATABASE_NAME}'
volumes:
- db-data: /var/lib/postgresql/data
volumes:
immich-data:
device: !ENV '${UPLOAD_LOCATION}'
owner: 1000
group: 1000
model-cache:
device: !ENV '${CACHE_LOCATION}'
redis-data:
device: !ENV '${REDIS_DATA_LOCATION}'
db-data:
device: !ENV '${DB_DATA_LOCATION}'
immich-postgres-template.conf:
exec.start: "/bin/sh /etc/rc"
exec.stop: "/bin/sh /etc/rc.shutdown jail"
sysvmsg: new
sysvsem: new
sysvshm: new
mount.devfs
persist
Makejail:
Access Immich at: http://your-host:2283
Environment Variables
| Variable | Default | Description |
|---|---|---|
UPLOAD_LOCATION |
/containers/immich/library |
Path to store uploaded photos and videos |
DB_DATA_LOCATION |
/containers/immich/postgres |
Path to store PostgreSQL database files |
DB_PASSWORD |
postgres |
PostgreSQL password (change this!) |
DB_USERNAME |
postgres |
PostgreSQL username |
DB_DATABASE_NAME |
immich |
PostgreSQL database name |
TZ |
System default | Timezone (e.g., America/Los_Angeles) |
Ports
| Port | Service | Description |
|---|---|---|
2283 |
immich-server | Web UI and API |
3003 |
immich-ml | Machine Learning API (internal) |
5432 |
immich-postgres | PostgreSQL (internal) |
6379 |
redis | Redis cache (internal) |
Network Mode
The stack uses network_mode: host for simplicity on FreeBSD. All services communicate via localhost. Only port 2283 needs to be exposed externally.
FreeBSD-Specific Notes
PostgreSQL Shared Memory
PostgreSQL requires System V IPC for shared memory. The compose file includes:
This annotation is processed by ocijail to allow the jail access to shared memory.
Machine Learning Performance
The immich-ml container uses:
- Native FreeBSD onnxruntime - Custom-built wheel with FreeBSD support
- CPU inference - GPU acceleration not currently supported on FreeBSD
- HuggingFace models - Downloaded on first run (~1GB cache)
First startup may be slow as ML models are downloaded. Subsequent starts are fast.
Management
View Logs
# All services
podman-compose logs -f
# Specific service
podman logs -f immich_server
podman logs -f immich_machine_learning
Restart Stack
Stop Stack
Update Images
Component Documentation
For detailed configuration of individual services:
| Component | Documentation |
|---|---|
| Server | immich-server |
| Machine Learning | immich-ml |
| PostgreSQL | immich-postgres |
| Redis | redis |
Troubleshooting
ML service keeps restarting
Check memory - the ML service needs at least 2GB RAM:
If you see OOM errors, increase available memory or disable ML features in Immich settings.Database connection errors
Ensure PostgreSQL has started and the sysvipc annotation is working:
The database needs a few seconds to initialize on first run.Photos not uploading from mobile
Ensure port 2283 is accessible from your network. Check firewall rules:
Facial recognition not working
The ML service downloads models on first use. Check if models are cached:
Implementation Details
- Platform: Native FreeBSD 15.0 (no Linux emulation)
- Runtime: ocijail (FreeBSD jails as OCI containers)
- ML Backend: onnxruntime with custom FreeBSD wheel
- Database: PostgreSQL 14 with pgvector extension
- Process Manager: s6-overlay