My consolidated Nix configuration for macOS and NixOS systems, including a few services.
- Voyager: macOS (aarch64-darwin)
- Cassini: macOS (aarch64-darwin)
- Kepler: NixOS (x86_64-linux, headless)
- Cubesat: NixOS (x86_64-linux, headless)
# macOS systems (nix-darwin)
darwin-rebuild build --flake .#voyager
darwin-rebuild switch --flake .#voyager
# Alternative with nh
nh darwin build -H voyager .
nh darwin switch -H voyager .
# NixOS systems
nixos-rebuild build --flake .#kepler
sudo nixos-rebuild switch --flake .#kepler
# Alternative with nh
nh os build -H kepler .
nh os switch -H kepler .Secrets are stored encrypted in secrets/secrets.yaml and automatically decrypted using sops-nix.
Key is stored in ~/.config/sops/age.key, make sure that exists.
Edit secrets
sops secrets/secrets.yamlServices are defined as native NixOS or docker services. Not everything has been migrated to native yet.
Kepler service definitions live under hosts/kepler/services/ (Docker services in hosts/kepler/services/docker/).
sudo systemctl status $servicename
sudo systemctl start $servicename
sudo systemctl stop $servicename
sudo systemctl restart $servicename
journalctl -u $servicename -f
journalctl -u $servicename --since "1 hour ago"Docker-based services run in detached mode docker-compose up -d, so their container logs are not captured by journalctl.
cd /etc/docker-compose/$servicename
sudo docker-compose logs -f
# or
sudo docker-compose logs --tail=50This is intentional to keep container logs separate and avoid interleaving multiple container outputs in journald.
Both kepler and cubesat use restic for backups to an SFTP server.
Kepler backs up all services (native NixOS + Docker) daily at 4 AM.
# Run backup manually
sudo systemctl start kepler-backup
# Check backup status/logs
journalctl -u kepler-backup -fThe kepler-backup-restore command is available on kepler:
kepler-backup-restore list # List all snapshots
kepler-backup-restore files latest # Browse files in a snapshot
kepler-backup-restore restore latest # Restore to /var/restore/
kepler-backup-restore restore-db latest # Extract PostgreSQL dumps
kepler-backup-restore shell # Interactive restic shellCubesat backs up pangolin data (/var/lib/pangolin) daily at 3 AM.
# Run backup manually
sudo systemctl start cubesat-backup
# Run pre-upgrade backup (tagged for easy identification)
sudo systemctl start cubesat-backup-preupgrade
# Check backup status/logs
journalctl -u cubesat-backup -fThe cubesat-backup-restore command is available on cubesat:
cubesat-backup-restore list # List all snapshots
cubesat-backup-restore files latest # Browse files in a snapshot
cubesat-backup-restore restore latest # Restore to /var/restore/
cubesat-backup-restore shell # Interactive restic shellUse the deploy script to automatically create a pre-upgrade backup before deploying:
./scripts/deploy-with-backup.sh cubesatThis creates a tagged snapshot that can be used for rollback if needed.
<host>-backup-restore list- find the snapshot you want<host>-backup-restore restore <snapshot-id>- extract to/var/restore/- Stop the relevant service:
sudo systemctl stop <service> - Copy files from restore dir to original location
- For PostgreSQL databases (kepler only):
sudo -u postgres psql <dbname> < /path/to/dump.sql - Start the service:
sudo systemctl start <service>
Backup failures are reported via healthchecks.io. Configure <host>_backup/healthcheck_url in sops secrets to enable.