Project case study / Self-hosted infrastructure
Replacing Google Photos
with a private family photo cloud.
An old ASUS laptop, a photo library worth keeping, and a practical reason to learn infrastructure. Today, four of us host our photos on the same Immich server.
- People using it
- 4 family members
- Photo storage
- 1 TB HDD
- Battery charge limit
- 60%
- Off-site backup
- AWS Glacier
01 / A useful reason to build a server
I wanted a private alternative to Google Photos for my family: somewhere to upload, browse, and keep our photos on hardware I control. That gave this project a concrete purpose beyond experimenting with another home lab service.
I already had an ASUS VivoBook. Rather than buying a dedicated server, I repurposed it to run Debian and Docker, with Immich providing the photo application. Four members of my family, including me, now host their photos there.
My contribution was the system around Immich: preparing the machine, arranging persistent storage, migrating existing media, configuring remote access, troubleshooting imports, and adapting the laptop for continuous use. Immich itself is the open-source application that makes the photo experience possible.
02 / The system as it exists today
The ASUS has an Intel i3-7020U and 12 GB of RAM. An SSD supports the operating system and Docker, while a 1 TB HDD holds the photo library. Debian provides the host environment; the application runs as Docker services.
ASUS VivoBook · Debian · Docker
The stack includes the Immich server, PostgreSQL, the machine-learning service, and a Redis-compatible service running Valkey. These have different responsibilities: the media files live on disk, while the database preserves the information that makes those files a usable library.
Tailscale provides the remote access path. I verified access from outside the home using the server’s Tailscale IP and Immich’s port. The HTTPS hostname I tried did not work at that stage, so I am not presenting it as a completed part of the setup.
An earlier Raspberry Pi project used Samba and PhotoSync for photo storage. This case study covers the later ASUS-based Immich system; the Pi is not a dependency in the architecture shown here.
03 / The migration was the real work
Getting the application running was only one part of the project. My existing media was spread across folders and ZIP archives, with duplicate files and large videos to work through. A temporary transfer SSD acted as the import source, separate from permanent storage.
- Existing mediaFolders & ZIP archives on a temporary SSD
- Prepare & inspectExtract archives, inspect duplicates, check mounts
- Controlled importImmich CLI · dry runs · retries
- Immich libraryMedia on the HDD, indexed by Immich
A file on the host is not automatically visible in a container
At one point, the extracted files were visible on Debian but missing inside Immich’s container. Inspecting the mounts showed the intended mapping, yet the running container had been started before the transfer SSD was mounted. The issue was the container’s view of storage, rather than the extraction itself.
The configuration separated the writable Immich data directory from read-only import sources. That made the boundary explicit: existing media was input; the managed library was the destination.
A busy machine is not always short of CPU
During migration, the server appeared heavily loaded. A closer look at top showed 72.9% I/O wait in one sample, and the process list revealed five simultaneous Immich import or scan processes. Several were reading the same source.
That evidence changed the diagnosis. High apparent activity did not, by itself, justify a processor upgrade. Storage contention and overlapping work were part of the problem. The response was to stop the overlapping imports and use a controlled sequence, rather than launching more retries alongside them.
I also checked a repeated video using SHA-256 hashes. The matching hashes confirmed that those two copies were identical. That is a useful distinction: matching filenames alone do not prove that files contain the same data.
04 / Making a laptop work as a server
A repurposed laptop brings operational questions with it. Photo imports can create bursts of processing, while everyday use is a different workload. Storage, background jobs, heat, and power all deserve attention alongside CPU and memory.
Implemented / Battery care
A 60% charge ceiling
I configured the server to charge only to 60% and remain around that level while plugged in. The intent is to avoid keeping the battery continuously at full charge while the laptop serves as an always-connected machine.
This is a charging-policy change, not a measured battery-lifespan result. I have not quantified the improvement, and the charging limit does not replace attention to temperature or the condition of the hardware.
The goal is a machine I can keep using and maintaining, with operational choices that fit its new role. Owning the server also means owning its updates, capacity, availability, and recovery plan.
05 / Glacier for off-site recovery
Local storage for everyday use. Off-site cold storage for recovery.
The HDD provides the working photo library. AWS Glacier adds an off-site cold-storage layer, so the home server is not the only place the photo archive lives. Immich remains the everyday application; the remote archive serves a different purpose: recovery if the local copy is lost.
A recoverable Immich backup needs both media and a database backup, with deployment configuration and version information to support restoration. Immich’s documentation explains why a database backup alone does not contain the photos and videos. Immich backup and restore guidance ↗
The architecture separates the live library from the cold archive. The Glacier tier does not sit in the upload path, and everyday browsing does not depend on retrieving archived objects. Backup retention, access control, and recovery procedures remain part of operating the system.
Cold storage is for recovery, not the live Immich media directory. Glacier storage classes have different retrieval characteristics; Flexible Retrieval and Deep Archive require a restore before archived objects can be accessed. That makes retrieval time and cost part of the recovery design, rather than something to discover during an outage. AWS storage-class documentation ↗
The recovery path is to retrieve the backup, rebuild the application, and verify that the expected photos, videos, and library information are usable. I am not claiming a measured recovery time or a completed restore drill here: having an off-site archive and proving restoration are separate milestones.
06 / What this project delivers
This project now serves four family members on hardware I already owned. It combines a useful photo application with hands-on work in Linux, containers, persistent storage, private networking, and troubleshooting.
The most valuable lesson was to inspect the whole system. A missing file can be a mount problem. High load can involve I/O wait. A laptop that becomes a server needs a different charging policy. Each of those details matters to the people relying on the result.
The result is a private photo cloud for four people, with a local library for regular use and Glacier as the off-site archive. The next operational milestone is to document and rehearse recovery, so confidence in the backup comes from a repeatable process.
← Explore the other projects