Back to Blog
ThinkPad Photo NAS

ThinkPad Photo NAS

· 7 min read

Intro

When Google started giving me emails saying I was running out of space on my drive, and if I filled it I wouldn’t be able to store photos or send emails anymore, it was a choice between paying a monthly amount for the rest of my life, or do it myself. I don’t like the idea of someone else controlling access to my own property, so I decided on the latter option. One option was using a prebuilt NAS, however this cost money and it wasn’t much of a challenge. I had an old ThinkPad T480 lying around that I used for past projects, so I thought this was perfect for making my own NAS. So using only this ThinkPad, I started this project.

Selecting my toolkit

  • I used Ubuntu Server 24.04 LTS for my ThinkPad server operating system. I chose this simply because it’s the most widely used Linux server OS, which means it has the best documentation and longest support life (LTS means long term support, so it’ll be maintained until 2029).
  • Immich is the only self-hosted photos solution that matches Google Photos features (auto backup, face recognition, object search, albums, map view, shared libraries, mobile app). The alternative choices for this were Photoprism and Piwigo, which are slower to develop, have fewer features and are harder to set up. Immich was exactly the right tool I needed for this project.
  • Immich is made up of multiple services (main server, machine learning worker, database, cache). Running all of those manually would be tricky to set up and maintain, so I chose to use Docker to solve this. Docker wraps each service in a container so they’re isolated. I also used Docker Compose which lets me start/stop/update all of them with a single command. It also means when Immich releases an update, I can just run one command: docker compose pull && docker compose up -d. Because of this, I won’t need to manually reinstall anything. Immich’s Docker Compose file defines four services: the main Immich server (core application), a machine learning worker (a separate process for face recognition, object detection and semantic search, which means I can search for certain people, places or scenarios and see matching photos from my library — all run locally and privately), a Postgres database (stores all the metadata for the photos — who’s in them, when they were taken, which album they’re in, location, etc), and a Valkey cache (an in-memory data store that speeds up the app significantly by holding frequently accessed data so Immich doesn’t have to query the database every time).
  • I needed a way to access my server off my home network. The simplest option would be to use port forwarding - simply open a port on my router to expose Immich to the internet directly. This would work, but is insecure, as anyone on the internet scanning that port can access Immich directly, allowing anyone to reach my login page from the internet. Bots are constantly scanning the internet for open ports, so this can be exploited within a few minutes of the port being open. The best solution I found was to use Tailscale, which creates an encrypted private network (like a VPN, but without needing to configure or manage one yourself) between my connected devices so nothing is ever exposed publicly. It’s also simple to set up, which for this project is much better than self-managing a VPN.

Setting up my server

Step 1 - Installing Ubuntu Server

First, I downloaded Ubuntu Server 24.04 LTS, and flashed it to a USB stick using Balena Etcher. I booted the ThinkPad from the USB by pressing f12 during boot to enter the boot menu, and selecting the USB stick. I went through the normal install process, making sure to install OpenSSH server during the install so I could SSH into the server from other devices. This means I can manage the server remotely, without ever having access to the physical device after setup. After the install was complete, I made note of the IP address.

Step 2 - Setting a Static Local IP

From this point, I used SSH to do the rest of the setup from my main computer for convenience. I needed the ThinkPad to always have the same IP address all the time, otherwise the address can change which means I’ll have to get the new IP address constantly. To do this, I simply logged into my router and assigned a DHCP reservation to the ThinkPad’s MAC address. I chose this over setting a static IP in Ubuntu’s Netplan config because it keeps the network settings managed in one place — the router — rather than split across two devices.

Step 3 - Installing Docker

Installing docker takes one quick command: curl -fsSL https://get.docker.com | sudo sh. After installing, I added the user to the docker group for convenience, so I don’t need to use sudo every time I use it. This is standard practice for Docker on Linux, and means any docker command just works without extra permissions.

Step 4 - Installing Immich

To install Immich, I downloaded the Docker Compose file using wget -O docker-compose.yml https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml. The example .env file (storing the location of the uploaded images on the ThinkPad, password for the Postgres database that Docker will use, and the version of Immich that will run) is installed by running wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env. I needed to fill this with my correct information, so I changed the upload location to the correct location. After that, I started it using docker compose up -d, and checked it was running with docker compose ps.

Step 5 - Setup Immich

I opened Immich in my browser at port 2283, created an admin account and logged in. Then I made sure machine learning was enabled in the administration section. Just like that, Immich was completely set up. I installed the Immich app on my phone, and pointed it at the URL of the server, and enabled auto backup.

Step 6 - Setting Up Remote Access with Tailscale

I needed to set this up without exposing anything to the internet directly. On my ThinkPad, I installed Tailscale using curl -fsSL https://tailscale.com/install.sh | sh, and started it using sudo tailscale up. This generates a link to create an account and authenticate. I installed the Tailscale app on my phone and linked them all. Now, I can access my Immich server through the Tailscale IP.

Conclusion

This project gave me a fully functional Google Photos replacement running entirely on hardware I already owned. My photos are backed up automatically from my phone, searchable by face and object thanks to Immich’s machine learning, and accessible from anywhere through Tailscale — all without exposing a single port to the internet. The total cost was nothing beyond the electricity to keep the ThinkPad running. The only real limitation right now is storage — the internal SSD is around 98GB, which won’t last forever with full-resolution photo backups. My next step is to add external storage, either a USB drive or a networked solution, to give the server room to grow. If you’ve got an old laptop sitting in a drawer, this is one of the most practical things you can do with it. The entire setup took an afternoon, and the result is something you’ll actually use every day.

ZG

Written by Zac Godfrey

Networks & Cyber Security student at Northumbria University. Passionate about penetration testing, CTF challenges, and sharing security knowledge.