The dual-machine setup: Apple + Linux

· Tech

TLDR: Keep Apple for personal (iPhone, Watch, iCloud, 1Password). Use a dedicated Linux machine for all development (Docker natively, Firejail, Nix, local LLM inference). Physical separation solves what software isolation cannot. A mini PC costs less than a Mac Mini.


All the software mitigations (Docker, nono, Nix) reduce risk. The cleanest answer is physical separation.

The setup

Apple (personal):
iPhone, Apple Watch, iPad, Apple TV
1Password for personal credentials
iCloud for personal files
Linux (development):
All projects, Docker (native), Infisical
AI agents in sbx sandboxes or nono
Nix or source-built tools
Firejail for CLI sandboxing
No personal data whatsoever

A compromised tool on Linux cannot read your iCloud keychain, personal 1Password vault, or messages. A compromised personal device cannot read your Infisical session or project secrets.

Hardware

Mini PC: AMD Ryzen 7/9, 32-64GB RAM, 1TB NVMe. Minisforum or Beelink.

Laptop: Framework Laptop 16 (AMD, repairable) or ThinkPad X1 Carbon.

With GPU for local LLMs: NVIDIA RTX 4090 (24GB VRAM) or RTX 5090 (32GB VRAM). Alternatively, Apple Silicon with 128GB unified memory handles large models well. Run llama-server so your code never leaves the machine. See Vitalik Buterin’s setup.

OS: Fedora for stability, Arch for control, NixOS for fully declarative configuration.

What gets better

The Expo/iOS problem

iOS Simulator requires macOS. Two options:

Option A: Expo on Mac, API on Linux. npx expo start on Mac, Docker stack on Linux at http://linux-machine.local:3333.

Option B: EAS Build for iOS in the cloud. Test via TestFlight. Zero Mac dependency for daily coding.

Offline development

If Infisical Cloud is unreachable (plane, outage), you cannot start your dev stack. Three options:

Option 1: Encrypted local cache. Before going offline, export and encrypt:

Terminal window
brew install age
# Export and encrypt (dev secrets only, never production)
infisical export --env=dev --format=dotenv \
| age -r age1yourpublickey... > ~/.cache/infisical/myapp-dev.age
# When offline
age -d ~/.cache/infisical/myapp-dev.age \
| docker compose --env-file /dev/stdin up

Add *.age and .cache/infisical/ to .gitignore and .claudeignore. Delete when back online.

Option 2: Keep containers running. If the stack is already up when you lose internet, containers keep secrets in memory. Do not restart them.

Option 3: Accept the constraint. Work on things that do not need the full stack: refactoring, tests, docs, frontend with mock data. Often the most practical approach.