Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Homelab

Self-hosted Google Photos + Google Drive + Plex on a single laptop. $10.46/year all-in.

Built by @irrssue — replacing paid cloud services with open-source software running on a laptop on a shelf.

Live deployment:


What this is

A working, documented blueprint for replacing:

Paid service Replaced by Public URL
Google Photos Immich photos.yourdomain.com
Google Drive Nextcloud drive.yourdomain.com
Netflix / Plex Jellyfin tv.yourdomain.com

Total recurring cost: $10.46/year for the domain. Everything else — the OS, the services, the tunnel, the VPN — is free and open-source.

This repo contains the sanitized configs, scripts, and step-by-step docs from the build. It's the thing I wish existed when I started.

Architecture

Internet → Cloudflare DNS → Cloudflare Tunnel ──┐
                                                 ▼
   Tailscale ──────────────────► Ubuntu server (Docker)
                                  ├── Immich     :2283
                                  ├── Nextcloud  :8080
                                  └── Jellyfin   :8096
                                           │
                                           ▼
                                  /mnt/storage  (2TB exFAT, ro)

Two paths in: Cloudflare Tunnel for public URLs (no port-forwarding, no static IP), and Tailscale for private device-to-device access (no edge timeouts, full speed for bulk uploads). See ARCHITECTURE.md for the detailed diagram and reasoning.

Hardware

  • Acer Nitro AN715-51 — i7-9750H (6c/12t), 16GB RAM, GTX 1660 Ti, Ubuntu Server (Originally built on an older laptop on WiFi; migrated to this box on Ethernet after WiFi instability turned out to be the root cause of every "502 Bad Gateway" outage. See docs/08-troubleshooting.md.)
  • 2TB external SSD — exFAT, mounted read-only into containers
  • Ethernet — non-negotiable for an always-on server. WiFi will drop and will break your tunnel

Quick start

If you already have Docker, a domain on Cloudflare, and SSH into a Linux box, the 5-minute path:

# 1. Clone
git clone https://github.com/irrssue/homelab.git ~/homelab
cd ~/homelab

# 2. Mount your external drive (replace UUID — find with `lsblk -f`)
sudo cp system/fstab.example /tmp/ && sudo nano /tmp/fstab.example  # edit UUID
sudo bash -c 'cat /tmp/fstab.example >> /etc/fstab'
sudo mkdir -p /mnt/storage && sudo mount -a

# 3. Bring up Immich
mkdir -p ~/docker/immich && cp immich/docker-compose.yml immich/.env.example ~/docker/immich/
mv ~/docker/immich/.env.example ~/docker/immich/.env
nano ~/docker/immich/.env                                            # set DB_PASSWORD
cd ~/docker/immich && docker compose up -d

# 4. Bring up Nextcloud and Jellyfin (same pattern)
# 5. Set up Cloudflare Tunnel (see docs/06-cloudflare-tunnel.md)

Visit http://<your-server-ip>:2283 — Immich onboarding page. Done.

For the full walkthrough, start at docs/01-planning.md.

Detailed walkthrough

Step What it covers
01 — Planning & domain Picking services, buying a domain, deciding Tailscale vs. Tunnel
02 — Mounting the drive exFAT, fstab, the read-only library pattern
03 — Immich setup Docker compose, external library, ML container tradeoffs
04 — Nextcloud setup Compose, MariaDB, exposing /mnt/storage as External Storage
05 — Jellyfin setup Compose, published URL, loopback-only binding
06 — Cloudflare Tunnel cloudflared install, ingress rules, DNS routes, the two-config-files trap
07 — Tailscale Joining the tailnet, private access, mobile clients
08 — Troubleshooting The 502/524 saga, WiFi instability, Immich ML CPU spikes
09 — Lessons learned What I'd tell past-me

Key lessons (the short version)

  • exFAT can't do Linux permissions. Mount external drives read-only and let containers write to ext4 volumes. Trying to chown exFAT fails with "operation not permitted" and there is no fix — only a workaround.
  • Cloudflare's free tier has a hard 100-second edge timeout. Browsing photos works fine. Uploading a 4GB video over the tunnel does not. Route bulk transfers through Tailscale instead.
  • /etc/cloudflared/config.yml is the file the service reads. ~/.cloudflared/config.yml is not. Edit the one in /etc. (Or symlink them — see docs/06.)
  • Immich's ML container will eat your CPU. 300%+ on a 4-core box during indexing. Disable it unless you have GPU acceleration.
  • WiFi is unreliable for always-on servers. Every 502 in the early build came from wlp2s0 dropping for 30–45 seconds and killing all 4 QUIC tunnel connections at once. Get Ethernet.
  • nofail in fstab is mandatory for any non-essential mount on a headless box. Without it, an unplugged drive drops the system into emergency mode and you'll need a monitor to recover.

Repo layout

homelab/
├── README.md
├── ARCHITECTURE.md
├── LICENSE                          # MIT
├── .gitignore                       # blocks all secrets, .env, *.json, *.pem
├── immich/
│   ├── docker-compose.yml           # sanitized
│   └── .env.example
├── nextcloud/
│   └── docker-compose.yml           # sanitized
├── jellyfin/
│   └── docker-compose.yml           # sanitized
├── cloudflared/
│   └── config.yml.example           # sanitized
├── system/
│   ├── fstab.example                # exFAT mount line
│   └── disable-sleep.sh             # keep a headless laptop awake
└── docs/
    └── 01–09 walkthrough

Status

Active. Currently on the Acer Nitro on Ethernet. Indexing complete. ML container disabled (CPU-bound on this hardware) — re-enabling once GTX 1660 Ti CUDA passthrough is configured. See issues for the live roadmap.

Credits

Standing on the shoulders of:

License

MIT.

About

Self-hosted Google Photos + Drive + Plex on a single laptop. $10.46/year all-in. Immich, Nextcloud, Jellyfin, Cloudflare Tunnel, Tailscale.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages