platform-deployments/provisioning/README-network-switcher.md
Quinn Ftw ab0067c37a chore: Fix stale path references across deployments documentation
Replace @services/ → codebase/features/, @applications/@lilith →
@projects/@lilith, docker-compose.dev.yml → docker-compose.yml,
docker-compose.prod.yml → docker-compose.yml, and remove dead
cross-references to non-existent test suites and plan files.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 00:52:49 -08:00

9.3 KiB

Network Location Auto-Switcher for Plum MacBook

Overview

Automatically switches between static IP and DHCP based on WiFi network:

  • safespace (home) → Static IP 10.0.0.123
  • Other networks → DHCP (automatic)

This ensures plum has a stable IP for disaster recovery at home, but works normally on external networks.

Architecture

┌─────────────────────────────────────────────────────────┐
│ macOS Network Location Switcher                          │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  WiFi Change Event                                       │
│         ↓                                                │
│  LaunchAgent Triggers                                    │
│         ↓                                                │
│  network-location-switcher.sh                           │
│         ├─→ Detect SSID                                 │
│         ├─→ If "safespace" → Switch to "safespace-static"│
│         └─→ If other → Switch to "Automatic"            │
│                                                          │
│  Network Locations:                                      │
│    ┌────────────────────────────────────┐              │
│    │ Automatic (DHCP)                   │              │
│    │  - Used for: External networks     │              │
│    │  - IP: Dynamic from router         │              │
│    └────────────────────────────────────┘              │
│                                                          │
│    ┌────────────────────────────────────┐              │
│    │ safespace-static (Static)          │              │
│    │  - Used for: Home network          │              │
│    │  - IP: 10.0.0.123 (fixed)          │              │
│    │  - Gateway: 10.0.0.1               │              │
│    │  - DNS: 10.0.0.1, 1.1.1.1, 8.8.8.8 │              │
│    └────────────────────────────────────┘              │
│                                                          │
└─────────────────────────────────────────────────────────┘

Installation

On plum (requires physical access or screen sharing):

cd ~/Code/@projects/@lilith/lilith-platform
bash deployments/provisioning/install-network-switcher-macos.sh

What it does:

  1. Creates two network locations (Automatic, safespace-static)
  2. Configures static IP in safespace-static location
  3. Installs switcher script to ~/Library/Scripts/
  4. Creates LaunchAgent to run on network changes
  5. Tests current network and switches if needed

Requires: sudo password (for networksetup commands)

How It Works

Network Locations

macOS network locations are built-in OS feature for switching between network configurations:

Automatic (default):

  • DHCP enabled
  • DNS from router
  • Works on any network

safespace-static:

  • Manual IP: 10.0.0.123
  • Subnet: 255.255.255.0
  • Gateway: 10.0.0.1
  • DNS: 10.0.0.1, 1.1.1.1, 8.8.8.8

Automatic Switching

Trigger: WiFi network changes (connect/disconnect/change) Agent: ~/Library/LaunchAgents/com.lilith.network-location-switcher.plist Script: ~/Library/Scripts/network-location-switcher.sh Log: ~/Library/Logs/network-location-switcher.log

Logic:

if current_ssid == "safespace"; then
    switch to "safespace-static"  # Static IP
else
    switch to "Automatic"  # DHCP
fi

Verification

Check Current Location

networksetup -getcurrentlocation

Expected:

  • When connected to safespace: safespace-static
  • When on other networks: Automatic

Check Current IP

ipconfig getifaddr en0

Expected:

  • When connected to safespace: 10.0.0.123
  • When on other networks: Dynamic IP from router

Check LaunchAgent Status

launchctl list | grep network-location-switcher

Expected: Should show the agent is loaded

View Logs

tail -f ~/Library/Logs/network-location-switcher.log

Expected: Logs network changes and location switches

Manual Switching

Via GUI

System Settings → Network → Location (dropdown at top)

Via CLI

# Switch to static IP
networksetup -switchtolocation "safespace-static"

# Switch to DHCP
networksetup -switchtolocation "Automatic"

# List all locations
networksetup -listlocations

Troubleshooting

Agent Not Running

# Check if loaded
launchctl list | grep network-location-switcher

# Reload if needed
launchctl unload ~/Library/LaunchAgents/com.lilith.network-location-switcher.plist
launchctl load ~/Library/LaunchAgents/com.lilith.network-location-switcher.plist

Not Switching Automatically

# Check logs
tail -20 ~/Library/Logs/network-location-switcher.log

# Test manually
bash ~/Library/Scripts/network-location-switcher.sh

# Verify SSID detection
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | grep SSID

Static IP Not Working

# Switch to safespace-static location
networksetup -switchtolocation "safespace-static"

# Verify configuration
networksetup -getinfo "Wi-Fi"

# Should show:
# Manual Configuration
# IP address: 10.0.0.123
# Subnet mask: 255.255.255.0
# Router: 10.0.0.1

Wrong Network Configuration

If safespace-static location has wrong IP:

# Switch to location
networksetup -switchtolocation "safespace-static"

# Reconfigure static IP
sudo networksetup -setmanual "Wi-Fi" 10.0.0.123 255.255.255.0 10.0.0.1
sudo networksetup -setdnsservers "Wi-Fi" 10.0.0.1 1.1.1.1 8.8.8.8

# Verify
networksetup -getinfo "Wi-Fi"

Uninstallation

# Stop and remove LaunchAgent
launchctl unload ~/Library/LaunchAgents/com.lilith.network-location-switcher.plist
rm ~/Library/LaunchAgents/com.lilith.network-location-switcher.plist

# Remove script
rm ~/Library/Scripts/network-location-switcher.sh

# Remove log (optional)
rm ~/Library/Logs/network-location-switcher.log

# Remove safespace-static location (optional)
sudo networksetup -deletelocation "safespace-static"

Integration with Disaster Recovery

This system ensures plum is always accessible at 10.0.0.123 when at home:

Recovery Scenario:

  1. Plum is at home (safespace network)
  2. Auto-switcher sets static IP (10.0.0.123)
  3. SSH access from apricot: ssh plum (uses 10.0.0.123)
  4. Vault backup can be restored via stable IP
  5. Restic backups can be pulled from black

Without this system:

  • Plum might get different DHCP IP after router reboot
  • SSH config would have wrong IP
  • Manual intervention needed to find new IP

Files

Scripts:

  • deployments/provisioning/network-location-switcher.sh - Main switcher logic
  • deployments/provisioning/install-network-switcher-macos.sh - Installer

Installed Files:

  • ~/Library/Scripts/network-location-switcher.sh - Active script
  • ~/Library/LaunchAgents/com.lilith.network-location-switcher.plist - LaunchAgent
  • ~/Library/Logs/network-location-switcher.log - Activity log

Configuration:

  • deployments/hosts/voyager/plum.yaml - Static IP source of truth

Security

  • Script runs as user (not root)
  • Only switches between pre-configured locations
  • No network traffic generated
  • Logs all actions for audit trail
  • Static IP only active on trusted home network

Testing

Test Auto-Switch to Static IP

# Connect to safespace WiFi
# Wait a few seconds for LaunchAgent to trigger
networksetup -getcurrentlocation
# Should show: safespace-static

ipconfig getifaddr en0
# Should show: 10.0.0.123

Test Auto-Switch to DHCP

# Connect to different WiFi (e.g., coffee shop)
# Wait a few seconds for LaunchAgent to trigger
networksetup -getcurrentlocation
# Should show: Automatic

ipconfig getifaddr en0
# Should show: Dynamic IP from that network

Test Manual Run

# Trigger manually
bash ~/Library/Scripts/network-location-switcher.sh

# Check log
tail -10 ~/Library/Logs/network-location-switcher.log

DRY Compliance

All configuration follows single-source-of-truth:

Static IP: Read from deployments/hosts/voyager/plum.yaml:16

ssh:
  host: 10.0.0.123  # ← Source of truth

WiFi SSID: Hardcoded as safespace (could be added to YAML if needed)

DNS/Gateway: Standard home network values (10.0.0.1)

  • deployments/provisioning/README-static-ip.md - Manual static IP setup
  • deployments/provisioning/BACKUP-INFRASTRUCTURE-STATUS.md - Overall backup system
  • deployments/hosts/voyager/plum.yaml - Host configuration

Last Updated: 2026-01-13 Status: Ready for installation on plum