---
title: "The always-on Mac"
description: "An old M1 Pro laptop runs local LLMs, pumps my photos out of iCloud and stands by if the main server goes down."
url: "https://michael.zazon.us/notes/the-always-on-mac"
published: "2026-10-17T12:00:00-04:00"
kind: "build-log"
subject: "homelab"
tags: ["ai-coding"]
---
I have always liked old laptops as homelab servers: the battery, screen and keyboard are built in. And you can usually find them pretty cheap on the second hand market. I like to be cost conscious with any home lab purchases, try to minimize ewaste, use what I have regardless of age, etc.

This time it's a 2021 MacBook Pro with the M1 Pro and 32 GB memory. It replaces my 2017 Intel MacBook, which was stuck on a version of macOS that Apple stopped supporting. I manage my dotfiles with chezmoi, just like on my other machines: [chezmoi one source of truth for every dotfile](https://michael.zazon.us/notes/chezmoi-one-source-of-truth-for-every-dotfile). An always-on old M1 Pro with 32 GB runs (small/quantized) local LLMs, embedding models, including models I fine-tuned, backs up iCloud, and is the standby in my DR plan if the main server goes down. It's a great little machine.

[Diagram: The Mac and main server with their jobs and photos flowing between them](https://michael.zazon.us/notes/the-always-on-mac)

## The iCloud “pump”

The iCloud part only works because it's a Mac, so that was the job that justified it. The only way to get at the originals in Photos is through the local Photos library on a Mac.. there's no server-side API. So the Mac is the pump, not the store: it downloads and exports the originals, then the main server keeps a copy and controls the schedule. For the whole pipeline story, see [Photos iCloud is a sync service not a backup](https://michael.zazon.us/notes/photos-icloud-is-a-sync-service-not-a-backup).

The first export run processed 60k+ photos, came to 550 GB, took 5 hours, and encountered 0 errors. I assumed all of my photos would already be on a machine I owned, but my daily laptop was using Optimize Storage and only held 13 GB of originals. So before the first run completed, it was true that no machine in the house had every original. This strategy helped close the gap.

> [!warning]
> Optimize Storage keeps only small versions of most photos on a Mac. A laptop with it turned on is not a backup of your library.

## 28 tokens a second from a 26B model - decent

The biggest surprise was how well an old laptop can run a 26B model at close to 28 tokens a second fully on the GPU. I did a little bake off on my Mac using [Ollama](https://github.com/ollama/ollama) and three models: [Gemma 4 26B-A4B](https://huggingface.co/google/gemma-4-26B-A4B-it) at 27.6 tokens/s decode, Qwen3.8-27B at 7.3, and Muse Glimmer 30B at 6.6.

The difference is in the model design. Gemma is a mixture-of-experts model, so only ~3.8 billion parameters are active for each token, while the two dense models use all their parameters for every token on the M1 Pro, making them compute-bound. I noted previously that this was because Qwen's new architecture didn't have a Metal path, but Muse uses conventional attention and is equally slow, so I went back and questioned other assumptions. A 32k prompt takes about 70 seconds on Gemma and about 13 minutes on either of the dense models.

## Only macOS or Metal

As a rule, I only run jobs on the Mac that require macOS or Metal. Docker on macOS runs in a VM and doesn't support USB passthrough, so Home Assistant will continue to run on the main server with the Z-Wave and Zigbee radios. BirdNET will continue to run there, too. Writing down this rule is one of [A cloud architect's habits applied at home](https://michael.zazon.us/notes/a-cloud-architects-habits-applied-at-home) and helps keep the two machines from drifting into each other's jobs.

The same thinking informed my choice of storage: my Photos library lives on a 1 TB SD card in the Mac's built-in card reader, not on a USB-C SSD (which would be about ten times faster) because this is an always-on machine and nothing should stick out to get knocked loose. If the card fails, I can always re-download from iCloud, so no data will be lost. The copy on the main server is the canonical one.

## Lid closed, always on

The Mac silicon is so efficient and sips power too. So it's easy to leave on. Keeping it awake with the lid closed takes one `pmset` command, and I applied it before anything else because I was away from home during setup and keeping the Mac reachable mattered more than any other step.

```
pmset -a sleep 0 disablesleep 1 displaysleep 0 hibernatemode 0 standby 0 autopoweroff 0 autorestart 1 womp 1 powernap 0 tcpkeepalive 1
```

> [!tip]
> On Apple silicon, `disablesleep` is all you need to keep a closed laptop awake.. no nvram tweak.

## If I lose the main server

If I lose my main server to fire, theft, or a dead board.. the plan is critical services back on the Mac within hours. It'd run under [OrbStack](https://orbstack.dev/) with plain `docker compose` and an override file for each stack. Secrets come from 1Password, which the Mac can already read. I've only drilled this once (cloning the infra repo from the GitHub mirror when the self-hosted git server was unreachable), and it took 5 seconds. I still need to schedule more drills.

The role rule was written for the Mac's first jobs, and where I'm heading now stretches it. Focusing on what's possible next: proving that an always on Mac may be the ideal solution long term for my Linux containers, services, and home server needs. Local LLM inference is a huge benefit to learn data strategy, LLM fine tuning and LLM ops. I may start to migrate services to the machine from my main server to spread the load around a bit.