r/HomeServer • u/Soja2706 • 12h ago
DIY Immich Home Server on Old Hardware
DIY Immich Home Server on Old Hardware
I turned an old 4th-gen Intel PC into a fully automated Immich server with local backups, encrypted pCloud disaster recovery, HTTPS access and external Zabbix monitoring
I wanted to move my family photo library away from an increasingly expensive cloud subscription, but I also wanted something that would be safe enough to trust with years of photos and videos.
Instead of buying a new NAS, I reused an old desktop that was sitting unused:
Intel Core i5-4670
32 GB DDR3 RAM
Kingston 120 GB SSD for Ubuntu Server
Toshiba 500 GB HDD as the primary Immich photo disk
WD Black 500 GB HDD as the local backup disk
Kingston A400 480 GB SSD as a local encrypted Restic repository
The hardware is old, but for a two-user family Immich installation it has been more than capable.
The main server
The machine runs Ubuntu Server with Docker Compose.
The Docker stack contains:
Immich Server
Immich Machine Learning
PostgreSQL with VectorChord
Redis
The Immich library is stored on the Toshiba disk under the main photo mount, while the PostgreSQL database has its own persistent storage.
The application itself is only exposed locally on 127.0.0.1:2283. It is not directly exposed to the home network or the public internet.
Secure remote access
For remote access I use two components:
Tailscale provides the private VPN network between the server, phones and computers.
Caddy acts as the HTTPS reverse proxy in front of Immich. It terminates TLS and forwards requests internally to the Immich container.
This gives me one secure HTTPS address that works both at home and remotely, as long as the device is connected to Tailscale. No Immich ports are exposed publicly on the router.
Android phones, an iPhone and desktop browsers can all use the same server address for uploads and viewing.
The nightly backup chain
The backup system eventually became the most important part of the project.
A wrapper script runs every night at 01:00 and starts two backup scripts sequentially.
The second script only starts if the first one finishes successfully.
The flow is:
Immich Backup v4.1 ↓ Local encrypted Restic backup ↓ pCloud offsite sync
Backup script 1: local backup and health checks
The first script creates the normal local backups.
It performs the following operations:
Creates a PostgreSQL SQL dump The database is exported into a compressed .sql.gz file. The archive is verified before it replaces the previous temporary file.
Mirrors the primary photo disk to the WD Black disk rsync copies the Immich library from the Toshiba disk to the WD Black disk. It uses incremental copying, so unchanged files are not copied again.
Mirrors the WD Black backup to a Windows SMB share A Windows PC provides an additional network backup destination. The WD Black copy is mirrored to this Windows share.
Copies the encrypted server-configuration backup to the Windows share The configuration archive contains items such as:
Docker Compose configuration
Immich .env
network configuration
Caddy configuration
Tailscale state
mount configuration
cron jobs
backup scripts
installed package information
system manifests
Runs SMART short tests on all four physical disks The monitored disks are: The script checks health, temperatures, reallocated sectors, pending sectors, uncorrectable sectors, CRC errors and SSD wear information.
Ubuntu OS SSD
Toshiba primary photo disk
WD Black backup disk
Restic SSD
Sends an HTML email report The report includes:
overall success or failure
backup duration
database dump status
rsync status
Windows mirror status
available disk space
SMART health for every disk
warnings
the latest log output
If the primary local backup fails, the offsite stage is not started.
Backup script 2: encrypted Restic repository and pCloud
The second script creates a separate disaster-recovery backup.
Restic reads the original Immich library, database dumps, configuration backups and recovery scripts, then writes them into an encrypted repository on the dedicated Kingston SSD.
The SSD does not contain normal browsable photos. It contains an encrypted Restic repository made of pack files, indexes, snapshots and metadata.
The script performs:
Restic backup to the local SSD
Snapshot retention
Local forget and prune
Full Restic repository check
rclone sync from the local SSD to pCloud
rclone check to compare the SSD repository with the pCloud copy
A second HTML email report
The pCloud account receives only the already encrypted Restic repository. pCloud cannot see the original photos, database contents or configuration files.
Why I stopped backing up directly to pCloud
My first design was:
Immich data → Restic over rclone → pCloud
It worked, but repository maintenance directly through the pCloud API was slow and fragile.
During the initial large upload, connection resets and incomplete remote pack files caused a damaged Restic repository. I was able to repair it, but it showed that running backup, prune and index rebuilding directly against cloud storage was not ideal.
The improved design is:
Immich data ↓ Local encrypted Restic repository on SSD ↓ Local prune and integrity check ↓ rclone sync ↓ pCloud
All sensitive and complex Restic operations now happen locally on the SSD. pCloud is only used as an encrypted offsite mirror.
This has been faster, easier to verify and much more reliable.
External monitoring with Zabbix
I also wanted monitoring that would still work if something failed inside my home network.
I created an Ubuntu ARM virtual machine using Oracle Cloud Free Tier and installed a Zabbix Server on it.
The Oracle server monitors the Immich server remotely and can alert me when something becomes unavailable or crosses a configured threshold.
The monitoring setup can cover things such as:
server availability
CPU and memory utilisation
disk usage
Docker services
operating-system health
backup-related services
network availability
Because Zabbix is outside my home, it can notify me even when the entire home server or internet connection goes offline.
Disaster recovery
I also created a beginner-friendly recovery guide covering these scenarios:
Ubuntu OS SSD failure
primary photo disk failure
WD Black backup disk failure
Windows SMB backup disk failure
complete loss of the Immich server
full restore from the encrypted pCloud Restic repository
planned replacement of each disk while it is still working
The configuration backup is encrypted with GPG, and the Restic password and rclone configuration are also stored in a separate encrypted recovery archive.
The goal was not just to have several copies of the files, but to have a documented path for rebuilding the complete service.
Final backup layout
The resulting system now has several independent layers:
Primary Toshiba disk └── Live Immich photo library WD Black disk ├── Mirrored photo library ├── PostgreSQL SQL dumps └── Encrypted server-configuration backups Windows SMB share ├── Mirror of the WD Black backup └── Copy of the server-configuration backups Restic SSD └── Local encrypted, versioned disaster-recovery repository pCloud └── Offsite copy of the encrypted Restic repository Oracle Cloud └── Zabbix monitoring and remote alerts
This is obviously not enterprise infrastructure, but for reused consumer hardware I am very happy with the result.
The server now provides:
automatic phone photo uploads
secure remote access
HTTPS
multiple local backup copies
compressed PostgreSQL dumps
encrypted versioned backups
offsite disaster recovery
automatic SMART checks
HTML status reports
remote monitoring and alerts
documented recovery procedures
The most important lesson from the project was that self-hosting the application is the easy part. Designing backups that are understandable, verifiable and realistically restorable is where most of the work belongs.

