DEV Community

Cover image for DIY Homelab NAS Mark-1: Build Log (Ubuntu Server + Docker + Immich)
Samwaran Banerjee
Samwaran Banerjee

Posted on Edited on AI-assisted

DIY Homelab NAS Mark-1: Build Log (Ubuntu Server + Docker + Immich)

TL;DR

Repurposed an old HP laptop into a home NAS running Ubuntu Server + Docker for ~₹8K. Handles photo backup (Immich), file sharing (Samba),
and remote access (Tailscale).

Specs & Parts

Bought:

# Type Part Cost Qty Net Cost
1 Storage WD Green 480 GB SSD 2899 1 2899
2 Storage WD Green 240 GB SSD 1751.25 1 1751.25
3 Connector WAVLINK USB 3.0 to SATA 2.5" External Hard Drive Enclosure with UASP Protocol 754 1 754
4 Hardware Justec 270pcs M2 Male Female Brass Spacer Standoff Screw Nut Assortment Kit" 499 1 499
5 Connector 22Pin (7+15) Female Jack Connector SATA Serial ATA Data Power Combo Extension Cables Wire Cords 164.5 2 329
6 Connector Optical Bay 2nd Hard Drive Caddy, Caddy 9.5mm for Laptop 189 1 189
7 RAM Hi-tech Hynix 8GB DDR3L Laptop RAM 1600 Mhz PC3L-12800S 1.35 Volt 204 Pin SODIMM 750.775 2 1501.55
8 Storage SanDisk Ultra Fit 3.1 64GB USB Flash Drive 864 1 864

Reused / already had:

# Type Part
1 Motherboard HP 15-r041tx Motherboard
2 CPU 4th Gen Intel Core i3 4005U 1.7 GHz Cores Dual Core, 4 Threads 3 MB Cache
3 GPU 2 GB, Nvidia Geforce 820m (2 Gb Ddr3 Dedicated) Graphics
4 Storage Seagate Mobile SDC001 1TB HDD

Total spent: ₹8786.8

Architecture

POWER
↓
MOTHERBOARD + CPU + RAM + GPU (Integrated)
│
├── SATA CONTROLLER → SATA Port 1 → SSD 250GB (primary)
│
├── CD Bay → CD to SATA Adapter → SSD 480GB (Secondary)
│
└── USB CONTROLLER
          ├── USB 2.0 → SanDisk Ultra Fit 64GB [Ubuntu Server (OS Only)]
          ├── USB 2.0 (Unused / available)
          └── USB 3.0 → SATA to USB Adapter → 2.5" HDD 1TB
Enter fullscreen mode Exit fullscreen mode

Storage Layout

Drive Size Purpose Notes
sda (64 GB USB) OS only Ubuntu Server Plenty of space for OS, updates, logs (if kept on tmpfs or minimal), very safe for writes.
sdb (240 GB SSD) Data + Docker volumes Fast storage for Docker containers, apps, and frequently accessed data SSD ensures fast container performance; avoid putting heavy media here to reduce wear.
sdc (500 GB SSD) Data + Docker volumes Additional fast storage for apps, media caches, or working datasets Same as sdb; great for splitting Docker workloads or high-speed media access.
sdd (1 TB External HDD via USB) Media + backups Bulk storage for movies, photos, and periodic backups Slower, but perfect for large, sequential file storage; reduces wear on SSDs.

Network Layout

[ Internet ]  
      ↓
[ Router / Modem ] (LAN / DHCP)  
      ↓
[ NAS Server (Ubuntu Server) ]  
      │  
      ├── SSH (22)  → Remote Management  
      │  
      ├── Web Services  
      │      ├─ Immich (2283)  
      │      ├─ Webmin (10000)  
      │      └─ Dockge (5001)  
      │  
      ├── Security Layer  
      │      ├─ UFW (Firewall)  
      │      └─ Fail2Ban (Intrusion Protection)  
      │  
      ├── Backup Services  
      │     └─ Restic (Scheduled Backups)  
      │  
      ├── Local Tools  
      │     ├─ htop (Process Monitor)  
      │     └─ neofetch (System Info)  
      │  
      ├── Remote Access  
      │      └─ Tailscale (Secure VPN)  
      │  
      ├── File Services  
      │      └─ Samba (445)  
      │  
      └── Monitoring  
             └─ Netdata (19999)

Enter fullscreen mode Exit fullscreen mode

Software Stack (Optimized)

1.  Ubuntu Server OS
2.  Dockge (Docker control)
3.  Immich (Photos)
4.  Samba (File sharing)
5.  Webmin (Admin UI)
6.  Netdata (Monitoring)
7.  Restic (Backups)
8.  UFW + Fail2Ban (Security)
9.  htop (Process monitor)
10. neofetch (Info display)
11. Tailscale (Remote access)
12. Avahi (hostname.local)
Enter fullscreen mode Exit fullscreen mode

The Build

1. Teardown

Popped the back panel and battery off the laptop and pulled the motherboard free from the chassis to see exactly what it had to offer. Booted a Ubuntu live USB briefly just to confirm what the board could actually see:

lsblk -o NAME,SIZE,TYPE,MOUNTPOINT
lscpu | grep "Model name"
dmesg | grep -i sata

Enter fullscreen mode Exit fullscreen mode

What turned up: a single onboard SATA port (already claimed by the original 1TB Seagate HDD), a CD-ROM SATA header that a caddy adapter could repurpose into a second SATA connection, two DDR3L SO-DIMM slots, one USB 3.0 port, and a daughterboard riding in on a ribbon cable with two more USB 2.0 ports. The single SATA port was the real constraint — the caddy adapter got it to two, which meant one drive for the OS and exactly one for actual storage until the USB controller got pulled into the plan too.

2. OS Install

Flashed Ubuntu Server 24.04 LTS onto the 64GB USB drive — this is the drive the whole system now boots from, keeping the SSDs free of OS writes:

# From a separate machine
sudo dd if=ubuntu-24.04-live-server-amd64.iso of=/dev/sdX bs=4M status=progress conv=fsync
Enter fullscreen mode Exit fullscreen mode

Booted the laptop off the USB drive, set the BIOS boot order accordingly, and ran the install headless — no GUI, OpenSSH enabled during the setup wizard so it never needed a monitor again after this point.

First-boot config: a static IP over netplan so the server doesn't wander to a new address after every reboot.

sudo nano /etc/netplan/00-installer-config.yaml
Enter fullscreen mode Exit fullscreen mode
network:
  version: 2
  ethernets:
    eth0:
      dhcp4: no
      addresses: [192.168.1.50/24]
      gateway4: 192.168.1.1
      nameservers:
        addresses: [1.1.1.1, 8.8.8.8]
Enter fullscreen mode Exit fullscreen mode
sudo netplan apply
Enter fullscreen mode Exit fullscreen mode

Then formatted and mounted the 240GB SSD, 480GB SSD, and the 1TB HDD (via its USB enclosure) into their assigned roles:

sudo mkfs.ext4 /dev/sda   # 240GB SSD — Docker / fast storage
sudo mkfs.ext4 /dev/sdb   # 480GB SSD — app storage
sudo mkfs.ext4 /dev/sdc   # 1TB HDD — media / backups

sudo mkdir -p /mnt/ssd240 /mnt/ssd480 /mnt/hdd1tb
sudo mount /dev/sda /mnt/ssd240
sudo mount /dev/sdb /mnt/ssd480
sudo mount /dev/sdc /mnt/hdd1tb
Enter fullscreen mode Exit fullscreen mode

Added all three to /etc/fstab so the mounts survive a reboot.

3. Service Setup

Installed Docker and Compose first, since almost everything else runs as a container:

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
sudo apt install docker-compose-plugin -y
Enter fullscreen mode Exit fullscreen mode

Dockge, for managing everything else through a web UI instead of raw CLI:

services:
  dockge:
    image: louislam/dockge:1
    restart: unless-stopped
    ports:
      - 5001:5001
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./data:/app/data
      - /mnt/ssd240/stacks:/opt/stacks
Enter fullscreen mode Exit fullscreen mode

Immich, pointed at the HDD for actual photo storage:

services:
  immich-server:
    image: ghcr.io/immich-app/immich-server:release
    volumes:
      - /mnt/hdd1tb/immich:/usr/src/app/upload
    ports:
      - 2283:2283
    restart: unless-stopped
Enter fullscreen mode Exit fullscreen mode

Samba, for file sharing across the network:

sudo apt install samba -y
sudo nano /etc/samba/smb.conf
Enter fullscreen mode Exit fullscreen mode
[nas-share]
   path = /mnt/hdd1tb/shared
   browseable = yes
   writable = yes
   guest ok = no
Enter fullscreen mode Exit fullscreen mode
sudo smbpasswd -a yourusername
sudo systemctl restart smbd
Enter fullscreen mode Exit fullscreen mode

Webmin, Netdata, htop, neofetch — the admin panel and the day-to-day visibility tools:

wget -qO- https://raw.githubusercontent.com/webmin/webmin/master/webmin-setup-repo.sh | sh
sudo apt install webmin -y

wget -qO- https://get.netdata.cloud/kickstart.sh | sh

sudo apt install htop neofetch -y
Enter fullscreen mode Exit fullscreen mode

UFW, Fail2Ban, Tailscale — locked the server down, then opened exactly one secure door back in:

sudo apt install ufw fail2ban -y
sudo ufw allow OpenSSH
sudo ufw allow 2283/tcp   # Immich
sudo ufw allow 5001/tcp   # Dockge
sudo ufw enable

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
Enter fullscreen mode Exit fullscreen mode

Challenges & Fixes

Only one SATA port

Used an "Optical Bay 2nd Hard Drive Caddy, Caddy 9.5mm for Laptop" to increase one more SATA connection

Immediate case/cabinet for the NAS - minimal

For a Case or enclosure for the whole self made NAS I am using a plasic box which costed me INR 200 in local market to be used here. I removed the seperators withn the plastic box with hand tools like hacksaw and a file to finish it of.

Ubuntu wasn't booting at first

Checked the boot menu to keep the pendrive at top of the boot menu and remove secure boot due to a few driver conflicts. Also using the grub 2 boot menu and the UEFI option rathe than legacy boot.

Immich container stuck after a bad SSH script

A careless SSH script deleted Immich's installation folders mid-experiment.
The container still showed up in OMV's UI afterward and wouldn't remove
through the interface. Rather than patch around it, switched to a clean
headless Ubuntu Server install instead of continuing on OMV.


Results & Lessons Learned

Final cost: ~₹8,200 (₹8,000 in drives/adapters + ₹200 for the case) — against ₹20,000-25,000 for even an entry-level commercial NAS. Reusing the laptop's motherboard, CPU, and RAM instead of buying new is what made that gap possible.

What actually held up:

  • Separating storage by purpose (OS on USB, fast storage on SSD, bulk media on HDD) kept the system predictable — no single drive doing double duty and choking under load.
  • Running everything in Docker meant mistakes were cheap. When the Immich install got wiped by a bad SSH script, the fix was "redeploy the container," not "reinstall the OS."
  • Netdata turned troubleshooting from guessing into just... looking. The Immich indexing CPU spike is a good example — you can watch it happen instead of assuming it's happening.

What I'd do differently:

  • Test a backup before you need one. Losing the first Immich instance mid-experiment was low-stakes because there wasn't real data on it yet — it wouldn't have been if there was.
  • One SATA port on a repurposed motherboard is a hard ceiling, not a minor inconvenience. If I were doing this again, I'd check port count before falling in love with a specific piece of donor hardware.

What's Next

  1. Adding a 3D printed case.
  2. Extending the number of SATA ports for data storage to 6 from 2
  3. Ensuring proper cooling by adding external fans
  4. Using full potential for n8n and other tools test as well
  5. adding another server for other services from another laptop motherboard lying around
  6. Adding both to a 10" server rack system

Links

  • 📖 Full story (the "why" behind this build): Medium
  • 💼 More projects like this: Portfolio

Top comments (0)