Hosting Your Own Memories with Immich

Published:

Around the time from 2015 to 2020, I was used to using Google Photos, and I was a fan of having an external storage that you can sync your device with and not worry about the storage. However, I slowly realize this is not going to be a scalable solution, speciailly if you have multiple devices and the quality of these captured images and videos becomes increasingly higher. Then I started looking at self-storage solutions that can be scaled well in the future while also being power-efficient, with enough redundancy, and accessible anywhere.

Background

During that time, my good friend and co-worked Daniel Volya mentioned about the Tailscale to me. So that we can solve the accessibility issue, my next objective is to find a reliable tool that works all the time. One day, I came across Immich, and I was impressed. Although during that time Immich was going through the initial development and having frequent breaking changes. Then Immich also released their mobile app that supports iOS and Android.

Now that I figured out the tools, I wanted to build my own NAS servers. By the way, during this time, storage was cheap compared to now. So I wanted to start with a simple server that can be powered using Type-C 5V with a plan of building a larger mechanical HDD version later. In this episode, I am documenting the build log of these two machines.

Environment

tailscale docker immich

Docker is what I used to keep services isolated and easy to update or rollback without reinstalling the whole system. Raid is there because disks will fail eventually, so I wanted redundancy and less chance of losing everything the day a drive decides to die. Immich is the actual photo/video stack that made this whole thing feel like a proper replacement for Google Photos, including the mobile workflow. Samba is for the boring but necessary file access, so I can still use the NAS like a normal network drive when I need to move things around. Tailscale solves the “accessibility anywhere” part because I didn’t want to deal with exposing ports or weird networking just to reach my own storage remotely.

Small CM4 NAS (codenamed ArchNAS.v1)

When I was going through the options, I came across this compact, full-metal NAS board from Waveshare. It looks very nice, supports CM4 (they were cheap back then), and supports 2x2.5” mobile HDDs with a SATA interface.

However, there were a couple of problems with this Waveshare design. There was an intermittant SATA initiailization issue caused by the Switch ASM1184 during the device boot process that prevented the system from booting, triggering a kernel panic. This was the most annoying one because when storage is flaky, it defeats the whole point of having a NAS you can trust. Thermals were also not great, since the board is compact and metal and everything is packed tightly, so you end up having to think about cooling way more than you’d expect. And since this board is designed for the CM4, it did not work with RADXA CM5, which became a limitation later when I wanted to change the compute module and keep the rest of the setup. I was able to fix the thermal issue by using a larger internal heatsink and connecting it direclty to the alumunium housing using a couple of thermal pads.


Slightly modified Waveshare NAS running a modified CM4.

After testing this setup for a while, I wanted a bit more scalable and cheaper solution in the long term, and that is when I decided to make a NAS that supports 3.5” HDDs.

Big CM5 NAS (codenamed ArchNAS.v2)


Everything assembled into a standalone steel enclosure

This is where I wanted to go more “real NAS” style with proper 3.5” drives and a setup that I can keep expanding over time without redoing everything from scratch. I used the CM5 Career (from Geekworm) because it already has a PCIE splitter that devides the PCIE in to two, which made it much easier to attach more storage without immediately hitting a wall. The compute module itself (CM5 16GB 32GB) is basically the brain here, and I wanted enough RAM to keep things smooth when multiple services are running and when Immich indexing/import jobs are going on. Once you start moving to multiple 3.5” drives, cables and power distribution stop being “an afterthought”, so SATA extensions become part of the build. The SATA SWITCH (NVME to 5xSATA with the JMB585) is what makes the build feel scalable instead of being stuck with just one or two drives. With more drives and a real PSU, I also wanted proper control instead of just hard power on and off manually, and that’s where the custom PSU controller comes in. And finally, I didn’t want to rely on random small adapters once I crossed into “multiple HDDs” territory, so a proper server PSU made more sense for stability.

PSU Controller

Since this is a larger-scale server that will host multiple 3.5 HDDs, I decided to go with a used Topower 200W 24 Pin ATX Server Power Supply (model number TOP-200SM). I wanted a controller to manipulate the PSU with automatic shutdowns. In order to achieve this, I created the psuctl🔌 using an ATtiny85 MCU, which you can read about it from here.

Adding a Tiny Framebuffer Display

Similar to the ArchNAS.v1, I wanted to include a small framebuffer display in this build as well. For this, I used a tiny 1.47-inch Waveshare display. After adding an SPI passthrough for the display on the psuctl🔌 PCB with proper pins, I updated the Raspberry Pi configuration so the panel is initialized at boot and works as a framebuffer console.

First, I modified the kernel command-line config at /boot/firmware/cmdline.txt to make the Linux console show up on the tiny TFT instead of (or alongside) the default output. This is useful because it gives you a local “always-on” status screen during boot and troubleshooting, even if you don’t have HDMI plugged in. I also chose a small VGA font so the text stays readable on a 1.47-inch panel.

fbcon=map:10 fbcon=font:VGA6x8

Then I added the panel driver and wiring details to /boot/firmware/config.txt using a device-tree overlay. This tells the Pi which SPI display controller it is (ST7789V), how it’s wired (reset/DC/backlight pins), and how to render it correctly (rotation, width, SPI speed). Without this, the kernel wouldn’t know how to initialize the display at boot.

dtoverlay=fbtft,spi0-0,st7789v,reset_pin=27,dc_pin=25,led_pin=18,rotate=90,width=206,speed=40000000

Conclusion

Looking back, the whole journey started from a very simple goal: keep my photos and videos safe, accessible, and not tied to a single provider forever. Google Photos was convenient, but once the library grows and you have multiple devices pushing higher-quality media, the “just sync it and forget it” model starts to feel less sustainable. Tailscale solved the access part, Immich solved the experience part, and the NAS builds solved the storage part. ArchNAS.v1 was a nice, compact first attempt, and it proved the workflow, but it also showed the real-world limitations around SATA reliability, thermals, and hardware flexibility. ArchNAS.v2 is the step toward something that can actually grow with me over time: more drives, better power, better control, and a setup that feels closer to a long-term home for everything.