Jarvis homelab
A repurposed laptop and two Oracle Cloud VMs on one Tailscale mesh, running 20+ self-hosted containers for ₹0 a month.
- Role
- Solo project: hardware, networking, services, monitoring and backups.
- Stack
-
- Ubuntu 24.04
- Docker Compose
- Oracle Cloud
- Tailscale
- Caddy
- Cosmos
- Let's Encrypt
- Pi-hole
- Unbound
- Uptime Kuma
- Glances
- n8n
- Bash
- cron
The problem
I wanted my own cloud: file sync, photo backup, a password manager and a media server, without paying a subscription for any of it.
The harder goal was that no single failure should take everything down, or go unnoticed.
How it's built
Three servers sit on one Tailscale mesh. Jarvis, a laptop at home, runs most of the services. Two Oracle Cloud Always Free VMs handle the rest: a small AMD instance that holds only the password manager and a monitor, and an Arm instance that runs a Minecraft server for friends.
Jarvis
Home serverRepurposed laptop at home
- Intel Core i3-6006U, 2 cores
- 8 GB RAM, 490 GB SSD
- Intel HD 520 for VAAPI transcoding
- Cosmos
- Pi-hole
- Unbound
- Nextcloud
- Immich
- Jellyfin
- Media automation ×7
- Homepage
- Uptime Kuma
- Glances
- n8n
- Code-Server
- DuckDNS
- iSponsorBlockTV
vault-server
Password vaultOracle Cloud, AMD Micro
- 1 OCPU, 1 GB RAM
- 2 GB swap file
- Always Free tier
- Vaultwarden
- Caddy
- Uptime Kuma
- Glances
oracle-1
Game serverOracle Cloud, Ampere A1
- 2 OCPU (Arm), 12 GB RAM
- 100 GB backup volume
- Always Free tier
- Crafty Controller
- Glances
Laptop
Tailscale peerMy Windows laptop
- Receives new media from Jarvis
Key decisions
Monitor every server from a different server
A monitor can't report its own outage. Jarvis and vault-server each run Uptime Kuma and watch each other every minute; both also watch oracle-1, which runs no monitor of its own. Alerts go out by email.
Give the password manager a machine of its own
Vaultwarden started on Jarvis, next to a media server that gets restarted all the time. I moved it to its own 1 GB VM, bound it to localhost and put Caddy in front for automatic TLS, so nothing else on the box can reach it directly.
That VM had about 227 MB free under normal load and the vault sometimes hung while loading. A 2 GB swap file fixed it. Every day a cron job copies the vault to Jarvis over Tailscale and keeps the last seven copies.
tar -czf "$TMP_PATH" -C "$DATA_DIR" .
scp -i "$SSH_KEY" "$TMP_PATH" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/"
rm -f "$TMP_PATH"
# On Jarvis, keep only the last 7 backups
ssh -i "$SSH_KEY" "$REMOTE_USER@$REMOTE_HOST" \
"cd $REMOTE_DIR && ls -t vaultwarden-backup-*.tar.gz | tail -n +8 | xargs -r rm --" Resolve DNS without a third party
Devices ask Pi-hole, which blocks ads and trackers and forwards the rest to Unbound. Unbound walks the DNS tree from the root servers itself, so no public resolver sees every lookup the house makes.
Results
- CPU per media stream after switching Jellyfin to VAAPI
- 90% → 15%
- monthly cost: Always Free VMs and a laptop I already had
- ₹0
- health-check interval, each server watched from another
- 1 min
The i3 laptop could barely transcode one stream in software. Hardware transcoding on its Intel HD 520 made streaming usable while everything else keeps running.