Machine Management
These notes are still a work-in-progress and are currently largely for my personal use only.
Home-Manager Example
- Install Nix standalone:
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
- Set proper Nix settings in
/etc/nix/nix.conf:
substituters = https://cache.nixos.org/ https://github-public.cachix.org
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= github-public.cachix.org-1:xofQDaQZRkCqt+4FMyXS5D6RNenGcWwnpAXRXJ2Y5kc=
narinfo-cache-positive-ttl = 0
narinfo-cache-negative-ttl = 0
experimental-features = nix-command flakes auto-allocate-uids
- Add these Nix channels via
nix-channel --add URL NAME:
$ nix-channel --list
home-manager https://github.com/nix-community/home-manager/archive/release-25.11.tar.gz
nixpkgs https://nixos.org/channels/nixos-25.11
- Install home-manager: https://nix-community.github.io/home-manager/index.xhtml#sec-install-standalone
Example home.nix file for personal use:
{ config, pkgs, lib, ... }:
let
user = "andrew";
homedir = "/home/${user}";
anixsrc = ./path/to/sources/anixpkgs/.;
in with import ../dependencies.nix; {
home.username = user;
home.homeDirectory = homedir;
programs.home-manager.enable = true;
imports = [
"${anixsrc}/pkgs/nixos/components/opts.nix"
"${anixsrc}/pkgs/nixos/components/base-pkgs.nix"
"${anixsrc}/pkgs/nixos/components/base-dev-pkgs.nix"
"${anixsrc}/pkgs/nixos/components/x86-rec-pkgs.nix"
"${anixsrc}/pkgs/nixos/components/x86-graphical-pkgs.nix"
"${anixsrc}/pkgs/nixos/components/x86-graphical-dev-pkgs.nix"
"${anixsrc}/pkgs/nixos/components/x86-graphical-rec-pkgs.nix"
];
mods.opts.standalone = true;
mods.opts.homeDir = homedir;
mods.opts.homeState = "23.05";
mods.opts.browserExec = "google-chrome-stable";
}
*-rec-* packages can be removed for non-recreational use.
Symlink to ~/.config/home-manager/home.nix.
Corresponding ~/.bashrc:
export NIX_PATH=$HOME/.nix-defexpr/channels:/nix/var/nix/profiles/per-user/root/channels${NIX_PATH:+:$NIX_PATH}
. "$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh"
export NIXPKGS_ALLOW_UNFREE=1
# alias code='codium'
# eval "$(direnv hook bash)"
Personal Machine Installation Instructions
Sources
- https://nixos.wiki/wiki/NixOS_Installation_Guide
- https://alexherbo2.github.io/wiki/nixos/install-guide/
- Build the installation ISO with
NIXPKGS_ALLOW_UNFREE=1 nix build .#nixosConfigurations.installer-personal.config.system.build.isoImage - Plug in a USB stick large enough to accommodate the image.
- Find the right device with
lsblkorfdisk -l. Replace/dev/sdXwith the proper device (do not use/dev/sdX1or partitions of the disk; use the whole disk/dev/sdX). - Burn ISO to USB stick with
dd if=result/iso/[...]linux.iso of=/dev/sdX bs=4M status=progress conv=fdatasync - On the new machine, one-time boot UEFI into the USB stick on the computer (will need to disable Secure Boot from BIOS first)
- Login as the user
andrew - Connect to the internet
- Within the installer, run
sudo anix-install - If everything went well, reboot
- On the next reboot, login as user
andrewagain - Connect to the internet
- Run
anix-init - Enjoy!
JetPack Machine Installation Instructions
- Ensure that the device has UEFI firmware installed. See https://github.com/anduril/jetpack-nixos.
- Build the installation ISO with
nix build .#nixosConfigurations.installer-jetpack.config.system.build.isoImage - Plug in a USB stick large enough to accommodate the image.
- Find the right device with
lsblkorfdisk -l. Replace/dev/sdXwith the proper device (do not use/dev/sdX1or partitions of the disk; use the whole disk/dev/sdX). - Burn ISO to USB stick with
dd if=result/iso/[...]linux.iso of=/dev/sdX bs=4M status=progress conv=fdatasync - Insert the USB drive into the Jetson device. On the AGX devkits, I’ve had the best luck plugging into the USB-C slot above the power barrel jack. You may need to try a few USB options until you find one that works with both the UEFI firmware and the Linux kernel.
- Press power / reset as needed. When prompted, press ESC to enter the UEFI firmware menu. In the “Boot Manager”, select the correct USB device and boot directly into it.
- Connect to the internet
- Within the installer, run
sudo anix-install - If everything went well, reboot
- On the next reboot, login as user
andrewagain - Connect to the internet
- Run
anix-init - Enjoy!
Upgrading NixOS versions with anixpkgs
Aside from the source code changes in anixpkgs, ensure that your channels have been updated for the root user:
# e.g., upgrading to 25.11:
home-manager https://github.com/nix-community/home-manager/archive/release-25.11.tar.gz
nixos https://nixos.org/channels/nixos-25.11
nixpkgs https://nixos.org/channels/nixos-25.11
sudo nix-channel --update. Then upgrade with
anix-upgrade [source specification] --local --boot
Build a JetPack Installer ISO
Cross-compiled from x86_64. Requires binfmt support for aarch64 (enabled by default on NixOS with boot.binfmt.emulatedSystems).
nix build .#nixosConfigurations.installer-jetpack.config.system.build.isoImage
dd if=result/iso/[...]linux.iso of=/dev/sdX bs=4M status=progress conv=fdatasync
Build a NixOS ISO Image
TODO (untested); work out hardware configuration portion.
nixos-generate -f iso -c /path/to/personal/configuration.nix [-I nixpkgs=/path/to/alternative/nixpkgs]
sudo dd if=/path/to/nixos.iso of=/dev/sdX bs=4M conv=fsync status=progress
Local SSL Setup for HTTPS Access
For machines configured with runWebServer = true (like ATS), you can enable HTTPS access from devices on your local network (especially phones) to avoid browser security warnings.
Quick Start
-
Generate SSL certificates on the server:
generate-local-ssl-certsThe script will auto-detect your LAN IP address and create certificates in
~/secrets/vpn/.If you need to specify a different IP address:
generate-local-ssl-certs 192.168.1.100 -
Install the CA certificate on your client devices:
Transfer
~/secrets/vpn/rootCA.pemto your phone and install it:Android:
- Settings → Security → Encryption & credentials → Install a certificate
- Choose “CA certificate” and select
rootCA.pem - Give it a name like “ATS Local CA”
iPhone/iPad:
- Email or AirDrop
rootCA.pemto your device - Open the file to install the profile
- Settings → General → VPN & Device Management → Install the profile
- Settings → General → About → Certificate Trust Settings → Enable full trust
-
Access your server via HTTPS:
https://ats.local:443Or use HTTP if you prefer (no automatic redirect):
http://ats.local:80
How It Works
- The nginx server listens on both HTTP (port 80) and HTTPS (port 443)
- There is no automatic redirect from HTTP to HTTPS - both protocols are supported
- The certificates are valid for:
[hostname].local(e.g.,ats.local)*.[hostname].local(wildcard for subdomains)localhost,127.0.0.1, and your LAN IP address
- Certificates are stored in
~/secrets/vpn/and backed up byrcrsync - Certificates expire after ~825 days and can be regenerated anytime
Regenerating Certificates
If your server IP changes or certificates expire:
generate-local-ssl-certs [new-ip-address]
The script will backup old certificates and create new ones. You won’t need to reinstall the CA on your devices if you’re replacing server certificates signed by the same CA.
Troubleshooting
SSL warnings still appear:
- Verify you installed
rootCA.pem(the CA certificate), notchain.pem - On iOS, ensure you enabled full trust in Certificate Trust Settings
- Try clearing browser cache or restarting the browser
Connection refused:
- Check firewall allows ports 80 and 443:
sudo iptables -L -n | grep -E '80|443' - Verify nginx is running:
systemctl status nginx
See Local SSL Setup for complete documentation.
Vikunja Task Management (ATS Only)
ATS machines automatically include Vikunja, an open-source task management system designed for collaboration between you and Claude Code.
Accessing Vikunja
Once your ATS machine is running, Vikunja is accessible at:
- Web UI (HTTPS):
https://ats.local:3457/ - Web UI (HTTP):
http://ats.local:3457/ - API:
https://ats.local/vikunja/api/v1/orhttp://ats.local/vikunja/api/v1/
The web UI is mobile-friendly and served through nginx on port 3457 with both HTTP and HTTPS support. The API is accessible at /vikunja/ on the default ports (80/443) due to how the frontend is built in nixpkgs.
Note: For HTTPS access to work without certificate warnings, you need to install the SSL certificate on your client devices. See the Local SSL Setup section above.
Initial Setup
-
Create your first user (registration is disabled after first use for security):
# Open https://ats.local:3457/ in a browser and register # After registration, the service will reject new registrations -
Get your API token for MCP integration:
- Log in to Vikunja
- Go to Settings → API Tokens
- Create a new token and save it securely
-
Configure Claude Code MCP (see MCP Integration section below)
Using Vikunja with Claude Code
Once you’ve configured the MCP integration (see below), Claude Code can directly interact with your Vikunja tasks during conversations.
Typical Workflow
You (via Web/Phone):
- Open
https://ats.local:3457/on your device - Create projects for different areas (e.g., “Development”, “Personal”, “Research”)
- Create tasks with descriptions, priorities, and due dates
- Review and comment on tasks Claude has worked on
Claude Code (via MCP):
- Lists your tasks when you start a conversation: “What should I work on?”
- Creates subtasks as it breaks down complex work
- Updates task status and adds progress comments
- Marks tasks complete when finished
- Creates new tasks for follow-up work or issues discovered
Example Interactions
-
You: “What tasks do I have in the Development project?”
- Claude lists all tasks with their status, priority, and descriptions
-
You: “Work on task 42”
- Claude reads the task details and gets to work
- Creates subtasks for each step
- Adds comments with progress updates
- Marks task complete when done
-
You: “Create a task to implement user authentication with JWT”
- Claude creates the task with a detailed description
- Can immediately start working on it if requested
MCP Integration
The Vikunja MCP server (vikunja-mcp-server) is automatically installed on ATS machines and provides direct integration between Claude Code and Vikunja.
Getting Your API Token
- Log in to Vikunja at
https://ats.local:3457/ - Go to Settings → API Tokens
- Click “Create new token”
- Copy the generated token (you won’t be able to see it again!)
Configuring Claude Code
Option 1: Automatic Configuration (Recommended)
The easiest way is to store your API token in ~/secrets/vikunja/secrets.json on the ATS machine:
{
"token": "your-api-token-here"
}
After adding the token, rebuild your system configuration to install the MCP server:
sudo nixos-rebuild switch
Then run the claude-setup script to register the MCP server:
claude-setup
The setup script will automatically:
- Install Claude Code plugins
- Register the Vikunja MCP server using your token from
~/secrets/vikunja/secrets.json - Configure other development tools (gh CLI, etc.)
To verify the MCP server is registered:
claude mcp list
Manual MCP Configuration
If you need to manually configure the Vikunja MCP server (without using claude-setup), you can use:
claude mcp add -s user \
-e VIKUNJA_URL=https://ats.local:3457 \
-e VIKUNJA_API_TOKEN=your-token-here \
-- vikunja /run/current-system/sw/bin/vikunja-mcp-server
Note: Use HTTPS (https://ats.local:3457) for the URL to ensure secure API access.
Available MCP Tools
Once configured, Claude Code has native access to these Vikunja tools:
vikunja_list_projects,vikunja_get_project- Browse and view projectsvikunja_list_tasks,vikunja_get_task- View tasksvikunja_create_task- Create new tasksvikunja_update_task- Update task fields (title, description, priority, etc.)vikunja_complete_task- Mark tasks as donevikunja_add_comment,vikunja_get_comments- Add and view task comments
Usage Examples
With the MCP server configured, you can interact with Vikunja directly in Claude Code:
- “What tasks do I have in the Development project?”
- “Create a task in project 5 to implement user authentication”
- “Add a comment to task 42 with the latest progress”
- “Mark task 15 as complete”
- “Update task 23’s priority to high”
Data Location
- Database:
/var/lib/vikunja/vikunja.db(SQLite) - Files:
/var/lib/vikunja/files/ - Logs:
/var/lib/vikunja/logs/ - Configuration:
/etc/vikunja/config.yml
Backup
The Vikunja database is automatically backed up daily at midnight by the ats-vikunja-backup orchestrator job:
- Copies
/var/lib/vikunja/vikunja.dbto~/data/vikunja/vikunja.db - Syncs to cloud storage via
rcrsync override data vikunja
You can manually trigger a backup with:
ssh andrew@ats.local
sudo systemctl start ats-vikunja-backup.service
Or manually copy the database:
ssh andrew@ats.local
sudo cp /var/lib/vikunja/vikunja.db ~/backups/vikunja-$(date +%Y%m%d).db
Architecture
Vikunja is served through nginx as a reverse proxy with HTTPS support:
- Vikunja serves both the web UI and API from a single service on internal port 3456
- Frontend accessible at
https://ats.local:3457(HTTPS) orhttp://ats.local:3457(HTTP) - API accessible at
https://ats.local/vikunja/api/v1/(HTTPS) orhttp://ats.local/vikunja/api/v1/(HTTP) - Internal port: 3456 (centrally managed in
service-ports.nix) - External ports: 3457 (frontend with HTTPS/HTTP), 80/443 (API via
/vikunja/) - SSL certificates: Same self-signed certificates as main web server (
~/secrets/vpn/)
The nixpkgs Vikunja frontend is built with /vikunja/ as the hardcoded API base path, so we serve the frontend on port 3457 while also proxying /vikunja/ on ports 80/443 for API access. Both HTTP and HTTPS are supported without forced redirects.
Miscellaneous
Cloud Syncing
The following mount points are recommended (using rclone to set up):
dropbox:secrets->rclone copy->~/secretsdropbox:configs->rclone copy->~/configsdropbox:Games->rclone copy->~/gamesbox:data->rclone copy->~/databox:.devrc->rclone copy->~/.devrcdrive:Documents->rclone copy->~/Documents
Music with Tidal
If you haven’t already, run:
install-superdirt
Open VSCode, run sclang in the terminal (close with 0.exit), and open up a .tidal file and get to work.
Useful commands:
- Install samples with e.g.,
tidal-download-samples eddyflux/crate crate - When
sclangis running, associate with the correct audio device withsc-route-audio