Pakistani creative agencies, commercial wedding photography studios, digital cinematographers, and tech-forward families face an unsustainable cloud storage bottleneck. As high-resolution mirrorless cameras (Sony A7 IV, Canon R5, Nikon Z8) and 4K60 10-bit smartphone sensors become standard, media asset volumes explode into tens of terabytes.
Simultaneously, commercial cloud storage platforms—such as Google One, Apple iCloud, and Dropbox—present severe operational and financial friction in Pakistan:
- Escalating Recurring USD Overhead: Recurring monthly payments in foreign currency face constant debit/credit card international transaction blocks, State Bank of Pakistan (SBP) foreign exchange compliance hurdles, and aggressive advance withholding taxes (under Section 236Y/F of the Income Tax Ordinance).
- Strict Storage Tier Caps: Beyond 2 TB, mainstream cloud storage prices surge steeply to enterprise tiers, forcing creative teams into fragmented multi-account setups.
- Client Privacy and Cultural Sensitivities: High-end Pakistani wedding studios handle sensitive family photography and bridal portraits. Entrusting unencrypted client archives to US-headquartered cloud hyperscalers—subject to automated algorithmic scanning and foreign jurisdiction subpoenas—poses severe client confidentiality risks.
- Bandwidth Throttling: Uploading 300 GB of multi-day wedding footage (Mehndi, Barat, Walima) through overseas cloud gateways frequently triggers aggressive ISP throttling over international transit links.
Immich has emerged as the definitive enterprise-grade, open-source media storage solution. Designed as a high-performance, self-hosted alternative to Google Photos, Immich delivers an identical mobile experience—complete with automated iOS/Android background photo synchronization, multi-user asset libraries, semantic search (CLIP), and on-device facial recognition clustering—while giving you 100% control over the underlying storage engine and compute nodes.
This engineering manual guides you through architecting, deploying, and maintaining a production-ready Immich cluster on a high-speed Linux Cloud VPS or enterprise Dedicated Servers.
1. Architectural Breakdown: Immich Core Microservices
Immich is not a monolithic script; it is a distributed, containerized microservices application optimized for heavy asynchronous I/O and parallel machine-learning inference. Understanding its component topology is critical for sizing your host server correctly.
+-----------------------------------------------------------------------------------+
| IMMICH SYSTEM ARCHITECTURE |
+-----------------------------------------------------------------------------------+
|
[ Client Layer ]
(iOS / Android Mobile App & Web Browser)
|
HTTPS Port 443
|
[ Reverse Proxy Engine ]
(Caddy 2 / Nginx)
|
Reverse Proxy Upstream :3001
|
+---------------------+---------------------+
| |
[ immich-server ] [ immich-machine-learning ]
(NestJS API & Job Queues) (Python / ONNX Runtime)
- REST Endpoints & WebSockets - Facial Recognition (InsightFace)
- Metadata Extraction (ExifTool) - Semantic Search (CLIP ViT)
- Video Transcoding (FFmpeg) - Hardware Acceleration Support
| ^
+---------------------+---------------------+
|
+------------------------+------------------------+
| |
[ Redis Engine ] [ PostgreSQL + pgvector ]
(Key-Value In-Memory) (Relational & Vector DB)
- BullMQ Asynchronous Queues - File Metadata & Timestamps
- WebSockets Session Cache - 512-dim Image Embeddings
- Background Job State - HNSW / IVFFlat Vector Index
| |
+------------------------+------------------------+
|
[ Storage Subsystem ]
- NVMe Primary Volume (Hot DB / Cache / Thumbs)
- High-Capacity Storage Tier (Raw Originals)
The Microservice Breakdown
-
immich-server(Consolidated API & Microservices): In modern Immich releases, the application core consolidates REST API handling, authentication, WebSocket real-time event broadcasting, and background job workers (previously split asimmich-microservices) into an event-driven NestJS core. It delegates metadata extraction viaexiftool, coordinates thumbnail generation throughlibvips, and schedules video transcoding pipelines viaffmpeg. -
immich-machine-learning: A dedicated Python service running an ONNX Runtime environment. It executes two demanding neural models:- Facial Detection & Recognition: Uses models such as Buffalo_l or Antelopev2 to detect facial bounding boxes, extract 512-dimensional facial feature vectors, and cluster faces across tens of thousands of images.
- Smart Search (CLIP): Transforms images and natural language queries into unified vector embeddings using models such as OpenAI’s ViT-B/32. This enables users to search for “red bridal lehenga” or “vintage car at night” without manual tagging.
-
database(PostgreSQL withpgvector): Immich pairs standard relational tables (users, albums, EXIF tags, GPS geocoding) with thepgvectorextension. The 512-dimensional vector embeddings generated by the machine learning container are indexed using Hierarchical Navigable Small World (HNSW) graphs directly in Postgres, allowing sub-50ms similarity queries across millions of photos. -
redis: Manages high-throughput BullMQ queues. Ingesting a single wedding event with 4,000 RAW images generates over 24,000 distinct background sub-tasks (hashing, EXIF extraction, thumbnail resizing, facial detection, vector embedding, and video proxy encoding). Redis prevents API starvation by buffering these operations.
2. Infrastructure Sizing: Linux VPS vs. Bare-Metal Dedicated Servers
Deploying Immich requires matching hardware allocations to concurrent mobile clients, ingestion pipelines, and library sizes.
Single Linux VPS vs. Dedicated Server Capacity Matrix
| Operational Metric | Standard Cloud VPS (Agencies & Families) | High-Performance Dedicated Server (Commercial Studios) |
|---|---|---|
| Target Audience | Freelance creators, digital agencies, families | Wedding studios, commercial production houses |
| Storage Capacity | 200 GB – 2 TB Enterprise NVMe | 8 TB – 64 TB Enterprise SAS/SATA in Hardware RAID-10 |
| RAM Allocation | 8 GB – 16 GB ECC RAM | 32 GB – 128 GB Registered ECC RAM |
| vCPU / Core Count | 4 – 8 Dedicated vCPUs | 16 – 32 Physical Cores (AMD EPYC or Intel Xeon) |
| Inference Hardware | Multi-threaded CPU ONNX / OpenVINO | Dedicated GPU (NVIDIA RTX / Quadro) or Intel QuickSync |
| Concurrent Uploads | 3 to 8 Mobile Devices | 25+ Field Photographers & Editors |
| Storage Architecture | Single NVMe or NVMe + S3/NFS Block Volume | Multi-Disk ZFS Pool / Hardware RAID array |
| Deployment Fit | Linux Cloud VPS | Dedicated Servers in Pakistan |
For teams processing multi-day events with hundreds of gigabytes per shoot, shared virtual disks will encounter I/O wait bottlenecks during thumbnail generation. Commercial studios managing client archives beyond 10 TB should deploy on Dedicated Servers with dedicated SATA/SAS RAID-10 arrays paired with NVMe cache pools.
3. Host Hardening & System Preparation
Begin with a freshly provisioned Ubuntu 24.04 LTS or Debian 12 64-bit instance. Execute all initial preparation steps over a hardened SSH session.
Kernel and Package Updates
# Update repository indexes and upgrade system packages
sudo apt update && sudo apt full-upgrade -y
# Install essential system utilities and container dependencies
sudo apt install -y curl wget git htop iotop ufw jq ca-certificates gnupg lsb-release
Docker Engine and Docker Compose Plugin Installation
Install the official Docker Engine repository rather than Ubuntu’s snap or standard distribution packages:
# Set up Docker official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add Docker repository to Apt sources
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker Engine, CLI, and Containerd
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Verify installation
docker compose version
Storage Directory Structure
Immich strictly isolates operational assets into discrete directory structures:
library: Immutable, raw originals organized by user and date.thumbs: Generated WebP thumbnails for ultra-fast mobile grid rendering.profile: User avatar assets.encoded-video: Web-compatible H.264/H.265 transcode proxies for smooth streaming.postgres: Persistent database volume.
# Create dedicated production paths
sudo mkdir -p /opt/immich/{library,upload,profile,thumbs,encoded-video,postgres}
cd /opt/immich
4. Production Docker Compose & Environment Configuration
Create a hardened .env file that specifies strict resource limits, database credentials, and operational paths.
Production Environment Variables: /opt/immich/.env
# Core Configuration
IMMICH_VERSION=release
# Base Storage Paths
UPLOAD_LOCATION=/opt/immich/library
DB_DATA_LOCATION=/opt/immich/postgres
# Database Credentials
DB_USERNAME=immich_admin
DB_PASSWORD=SecureProductionImmichPassword_2026_PK!
DB_DATABASE_NAME=immich_production
# Redis Cache
REDIS_HOSTNAME=immich_redis
REDIS_PORT=6379
# Machine Learning Threading Tuning (CPU Optimized)
# Sized according to available physical vCPU allocations
MACHINE_LEARNING_WORKERS=2
MACHINE_LEARNING_WORKER_TIMEOUT=120
# Video Transcoding Settings
# Set to 'vaapi' or 'cuda' if hardware passthrough is available; otherwise 'cpu'
IMMICH_TRANSCODING_ACCELERATION=cpu
Production Docker Compose Stack: /opt/immich/docker-compose.yml
services:
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- /opt/immich/thumbs:/usr/src/app/upload/thumbs
- /opt/immich/profile:/usr/src/app/upload/profile
- /opt/immich/encoded-video:/usr/src/app/upload/encoded-video
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
ports:
- "127.0.0.1:3001:3001"
depends_on:
redis:
condition: service_healthy
database:
condition: service_healthy
restart: always
deploy:
resources:
limits:
memory: 4096M
immich-machine-learning:
container_name: immich_machine_learning
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
volumes:
- model-cache:/cache
env_file:
- .env
restart: always
deploy:
resources:
limits:
memory: 3072M
redis:
container_name: immich_redis
image: docker.io/redis:7-alpine
healthcheck:
test: ["CMD-SHELL", "redis-cli ping || exit 1"]
interval: 10s
timeout: 5s
retries: 5
restart: always
deploy:
resources:
limits:
memory: 1024M
database:
container_name: immich_postgres
image: tensorchord/pgvecto-rs:pg16-v0.2.1
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
POSTGRES_INITDB_ARGS: '--data-checksums'
volumes:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME} -d ${DB_DATABASE_NAME} || exit 1"]
interval: 10s
timeout: 5s
retries: 5
restart: always
deploy:
resources:
limits:
memory: 2048M
volumes:
model-cache:
Launch the cluster in detached mode:
docker compose up -d
Verify that all four containers report healthy states:
docker compose ps
5. Reverse Proxy Configuration with TLS
Because Immich handles continuous multi-gigabyte video uploads, mobile WebSockets, and encrypted streaming, your reverse proxy must avoid standard buffering timeouts.
Below are production configurations for both Caddy 2 and Nginx.
Option A: Caddy 2 (Recommended for Automated Zero-Configuration TLS)
Caddy automatically obtains and renews Let’s Encrypt certificates without external cron jobs:
photos.yourdomain.pk {
encode gzip zstd
# Disable default request body limits for 4K video uploads
request_body {
max_size 50GB
}
reverse_proxy 127.0.0.1:3001 {
header_up Host {upstream_hostport}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
# Essential timeouts for large RAW uploads over domestic ADSL/Fiber connections
transport http {
read_timeout 600s
write_timeout 600s
}
}
}
Option B: Nginx Production Configuration
If using Nginx with Certbot, place this server block in /etc/nginx/sites-available/immich:
server {
listen 80;
server_name photos.yourdomain.pk;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name photos.yourdomain.pk;
ssl_certificate /etc/letsencrypt/live/photos.yourdomain.pk/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/photos.yourdomain.pk/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# Accommodate large video asset payloads
client_max_body_size 50000M;
client_body_timeout 600s;
# Disable proxy buffering for progressive uploads and fast mobile grid streaming
proxy_buffering off;
proxy_request_buffering off;
location / {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
# WebSocket support for instant real-time sync
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
}
}
6. Machine Learning Optimization: Facial Recognition & CLIP Smart Search
Immich’s machine learning container can place high demands on server resources during initial bulk catalog imports. Without proper tuning, a 50,000-photo wedding archive can cause CPU core lockups and memory thrashing.
1. Selecting the Right Facial Recognition Model
Within the Immich Admin UI (Administration -> Settings -> Machine Learning Settings):
- Buffalo_s (Small): Optimal for standard Linux VPS instances with 4 vCPUs and 8 GB RAM. Delivers fast face detection with minimal CPU utilization.
- Buffalo_l (Large): Recommended for studios operating on Dedicated Servers in Pakistan. Delivers precision across complex group shots, varied lighting conditions, and diverse angles typical of Pakistani multi-day wedding events.
2. CLIP Model Quantization and Selection
For multilingual and semantic natural language search:
- Use quantized models such as
XLM-RoBERTa-Large-Vit-B-16or standardViT-B-32-quantized. - Quantized models (INT8) reduce model memory footprint by up to 65% with virtually zero loss in recall precision, preventing Linux OOM killer invocations on virtualized memory tiers.
3. Worker Concurrency Throttling
To ensure uninterrupted mobile sync during bulk ingestion, throttle machine learning concurrency in your .env configuration:
# Limit active inference threads so the host retains headroom for database writes
MACHINE_LEARNING_WORKERS=2
7. Storage Tiering & Hybrid Volume Architectures
Wedding photography catalogs and commercial agency video assets accumulate rapidly. Balancing lightning-fast metadata performance with cost-effective bulk storage requires a tiered storage architecture:
[ NVMe Primary Host Tier ] ──> Fast DB, Thumbnails, WebP Caches
[ External Block / NFS Tier ] ──> High-Capacity RAW Original Media
Mounting External S3-Compatible Buckets via Rclone / FUSE
If your local VPS disk fills up, mount external, affordable S3-compatible cloud storage (such as Wasabi or Backblaze B2) directly as an encrypted filesystem mount:
# Example rclone mount systemd service for Immich media archive
[Unit]
Description=Immich External Media Rclone Mount
After=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/rclone mount b2-archive:studio-immich-media /opt/immich/library \
--vfs-cache-mode full \
--vfs-cache-max-size 100G \
--vfs-read-chunk-size 64M \
--buffer-size 32M \
--dir-cache-time 72h \
--allow-other
ExecStop=/bin/fusermount -u /opt/immich/library
Restart=always
User=root
[Install]
WantedBy=multi-user.target
For zero-latency workflows, however, local storage on Dedicated Servers provides far higher multi-threaded I/O throughput than network-mounted volumes, eliminating FUSE overhead during batch exports.
8. Mobile Background Synchronization Runbook (iOS & Android)
A major hurdle for self-hosted cloud alternatives is configuring mobile operating systems to back up photos silently in the background without requiring users to keep the application actively open.
+-----------------------------------------------------------------------------------+
| MOBILE CLIENT CONFIGURATION MATRIX |
+-----------------------------------------------------------------------------------+
| Setting / Parameter | iOS (Apple iPhone) | Android (Samsung, Xiaomi) |
+-------------------------------+--------------------------+---------------------------+
| Background App Refresh | Mandatory: Enabled | Battery: "Unrestricted" |
| Low Power Mode Bypass | Disables background jobs | Exclude from App Sleep |
| Wi-Fi Only Ingestion | Toggle per data plan | Toggle per data plan |
| Background Location Triggers | Triggers sync on travel | Uses OS WorkManager APIs |
| Certificate Pinning | Standard Valid CA (Let's | Standard Valid CA (Let's |
| | Encrypt / ZeroSSL) | Encrypt / ZeroSSL) |
+-------------------------------+--------------------------+---------------------------+
Apple iOS Optimization Checklist
- Navigate to iOS Settings -> Immich.
- Verify Background App Refresh is toggled ON.
- In the Immich App settings, enable Background Backup.
- Enable Background Location Verification inside Immich. Due to iOS security policies, background tasks are strictly timed. Immich leverages major location changes (such as arriving home or entering the studio) as a system wake event to trigger pending queue backups.
Android Optimization Checklist
- Open Android Settings -> Apps -> Immich -> Battery.
- Change the battery policy from Optimized to Unrestricted.
- On devices running custom skins (Xiaomi HyperOS, Samsung One UI, Oppo ColorOS), lock Immich in the recent apps overview to prevent aggressive OEM memory managers from killing background sync threads.
9. Disaster Recovery: Restic, Database Snapshots, and Rclone Automation
A photo server without automated offsite backups is a critical point of failure. If an NVMe drive degrades or an operator error drops a database table, raw files alone cannot recover album groupings, face tags, or timeline metadata without the PostgreSQL vector database.
1. Automated PostgreSQL Dump Script
Create /opt/immich/scripts/backup-db.sh:
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR="/opt/immich/backups/db"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
mkdir -p "${BACKUP_DIR}"
# Execute clean database dump directly from the running container
docker exec -t immich_postgres pg_dumpall -c -U immich_admin | gzip > "${BACKUP_DIR}/immich_db_${TIMESTAMP}.sql.gz"
# Retain local snapshots for 7 days
find "${BACKUP_DIR}" -type f -name "*.sql.gz" -mtime +7 -exec rm -f {} \;
Ensure execute permissions are granted:
chmod +x /opt/immich/scripts/backup-db.sh
2. Offsite Deduplicated Replication with Restic
Use Restic to encrypt, deduplicate, and push your photos and database snapshots to an offsite destination:
# Initialize restic repository (example targeting remote S3 storage)
export AWS_ACCESS_KEY_ID="YOUR_WASABI_OR_B2_KEY"
export AWS_SECRET_ACCESS_KEY="YOUR_WASABI_OR_B2_SECRET"
export RESTIC_PASSWORD="YourEncryptionPassphrase"
export RESTIC_REPOSITORY="s3:s3.us-east-1.wasabisys.com/immich-remote-backup"
restic init
# Execute daily automated snapshot via cron
restic backup /opt/immich/library /opt/immich/backups/db --exclude "/opt/immich/library/thumbs"
Because thumbnails and proxy videos can be regenerated on demand, excluding the thumbs directory saves up to 35% in offsite storage costs and bandwidth.
10. Financial Comparison: Public Cloud Subscriptions vs. Self-Hosted Infrastructure
For a commercial creative agency or photography studio in Karachi, Lahore, or Islamabad managing 10 TB of active client media, the financial contrast between proprietary cloud subscriptions and self-hosted dedicated infrastructure is substantial.
+-----------------------------------------------------------------------------------+
| 5-YEAR TOTAL COST OF OWNERSHIP: 10 TB ASSET POOL |
+-----------------------------------------------------------------------------------+
| Cost Factor | Google One / Apple iCloud | Self-Hosted Nextgen Server|
+----------------------------+-----------------------------+---------------------------+
| Monthly Base Subscription | ~$50.00 to $100.00 / month | Fixed in PKR |
| Banking WHT (16% Sec 236Y) | Added to every USD invoice | PKR 0 (Local Processing) |
| FX Devaluation Volatility | Constant PKR Price Hikes | Predictable Flat Billing |
| Account Storage Ceiling | Strict Account Max Caps | Easily Expandable Drives |
| Client Privacy Risk | Proprietary Cloud Scanning | 100% Private Sovereignty |
| 3-Year Estimated Outlay | Exceeds PKR 1.8M - 2.5M | Fraction of Cloud Expense |
+----------------------------+-----------------------------+---------------------------+
Beyond the immediate cost savings, self-hosting on high-performance Linux Cloud VPS instances or dedicated bare-metal infrastructure eliminates foreign card declines and secures your intellectual property under your own administrative control.
Related Engineering & Infrastructure Guides
Expand your self-hosted infrastructure and remote computing architecture:
- Zero-Trust Remote Browser Isolation (RBI) on Dedicated RDP/VPS
- How to Access Your Overseas Bank Account Safely from Pakistan Using a Dedicated RDP
- Admin RDP vs User RDP Server Access Guide in Pakistan
- Nextcloud Enterprise Collaboration Server Deployment on Linux VPS
Deploy Immich on Nextgen High-Performance NVMe VPS
Eliminate recurring USD cloud storage invoices, payment gateway rejections, and privacy liabilities. Deploy pure NVMe Linux VPS or bare-metal dedicated servers in Pakistan with zero foreign transaction fees, unmetered bandwidth, and dedicated compute.
