A robust, cross-platform Ansible infrastructure for managing a personal ecosystem of homelab servers, workstations (macOS/Linux), personal laptops, and Android devices.
Ninja Fleet was born from years of manual bash scripts, half-documented config files, and the recurring frustration of "how did I set that up last time?"
It represents an evolution from ad-hoc "search and destroy" maintenance to an immutable, unified "fleet" mindset. Whether it's a headless Debian server, a high-end macOS workstation, or a Windows media box, this repo ensures a consistent, secure, and reproducible environment through trial-and-error hardened logic.
- Multi-OS Orchestration: Unified management of macOS, Debian/Ubuntu, Windows 11, and Android (via ADB).
- Homelab Stack: Automated Docker deployments for Caddy, WireGuard, Technitium DNS, and more.
- Developer Workstation: Automated setup of dotfiles, dev tools (zsh, vim, tmux), and GUI applications via Homebrew/Flatpak.
- Surgical VPN: Integrated WireGuard orchestration for secure remote access across all devices.
- Mobile Check-ins: Basic Android management including app verification and VPN health checks.
- Production Standards: Enforced idempotency, strict linting, and Molecule-tested core roles.
- Automated Releases: Standardized via Conventional Commits and Release Please.
โโโโโโโโโโโโโโโโโโโโโ
โ Control Machine โ (Your Workstation)
โโโโโโโโโโโฌโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโ
โ โ โ
โโโโโโโโโผโโโโโโโโ โโโโโโโโโผโโโโโโโโ โโโโโโโโโผโโโโโโโโ
โ Homelab โ โ Workstations โ โ Plex Server โ
โ (Linux) โ โ (macOS/Linux) โ โ (Windows) โ
โโโโโโโโโฌโโโโโโโโ โโโโโโโโโฌโโโโโโโโ โโโโโโโโโโโโโโโโโ
โ โ
โโโโโโโโโผโโโโโโโโ โโโโโโโโโผโโโโโโโโ
โ Docker Stack โ โ Dev Tools โ
โ (Caddy/VPN) โ โ (Vim/Zsh/SSH) โ
โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
If you're cloning this repository for the first time, you'll need to set up your configuration files:
-
Copy the inventory template:
cp inventory/hosts.example.ini inventory/hosts.ini
Edit
inventory/hosts.inito add your actual hostnames and IP addresses. -
Copy the global variables template:
cp inventory/group_vars/all/main.example.yml inventory/group_vars/all/main.yml
Edit
inventory/group_vars/all/main.ymlto set your personal information:primary_domain- Your domain nameuser_email- Your email addressadmin_username- Your primary username- Network settings (IPs, subnets, interface names)
- Service configurations (WireGuard, Plex, etc.)
-
Set up homelab service configurations (if using the homelab role):
# Main compose file cp roles/homelab/files/compose.example.yml roles/homelab/files/compose.yml # Service-specific compose files (templates will generate these automatically) # Or manually copy if needed: # cp roles/homelab/files/services/*/compose.example.yml roles/homelab/files/services/*/compose.yml
Edit
compose.ymlto add any custom Docker networks (e.g., for external services). -
Configure SSL certificates (if using Caddy with HTTPS):
Place your SSL certificate files in
roles/homelab/files/certs/:# Use the examples as templates cp roles/homelab/files/certs/your-domain.example.crt roles/homelab/files/certs/your-domain.crt cp roles/homelab/files/certs/your-domain.example.key roles/homelab/files/certs/your-domain.key[!TIP] Caddy can automatically obtain Let's Encrypt certificates. The manual certs are only needed if you prefer to use pre-existing certificates.
-
Set up Ansible Vault password (choose one):
-
Option A: Use 1Password CLI (recommended)
# Copy and customize the example cp vault_1password.example.sh vault_1password.sh chmod +x vault_1password.shEdit
vault_1password.shto reference your 1Password vault item. -
Option B: Create
~/.ansible_vault_passwith your vault password
[!NOTE] The vault script is located in the repo root (not
~/.ansible/) so the example and your actual script are in the same place. The actualvault_1password.shfile is gitignored. -
-
Create encrypted secrets file:
ansible-vault create inventory/group_vars/all/secrets.yml
Note
The .gitignore is configured to exclude your actual configuration files (hosts.ini, main.yml, compose.yml, certs, etc.) to keep your personal data private.
If you manage multiple machines or want to keep your private data in a separate private repository, you can use the included link-config.sh script.
-
Create a private folder or repository (default:
~/.config/ninja-fleet). -
Run the export script to move your current local configs to this location:
./export-config.sh
-
In the future, or on other machines, run the link script to "overlay" your private data:
./link-config.sh
-
This will create symlinks from your private storage into the project, ready for execution.
The following diagram shows how your private files in ~/.config/ninja-fleet are mapped into the ninja-fleet directory:
ninja-fleet/
โโโ inventory/
โ โโโ hosts.ini โโโโโโโโโโโโโโโ> ~/.config/ninja-fleet/hosts.ini [IGNORED]
โ โโโ group_vars/
โ โโโ all/
โ โโโ main.yml โโโโโโโโ> ~/.config/ninja-fleet/main.yml [IGNORED]
โ โโโ secrets.yml โโโโโ> ~/.config/ninja-fleet/secrets.yml [IGNORED]
โโโ roles/
โ โโโ homelab/
โ โโโ files/
โ โโโ certs/
โ โ โโโ your-domain.crt โโ> ~/.config/ninja-fleet/certs/your-domain.crt [IGNORED]
โ โ โโโ your-domain.key โโ> ~/.config/ninja-fleet/certs/your-domain.key [IGNORED]
โ โโโ compose.yml โโโโโโโโโโโ> ~/.config/ninja-fleet/compose.yml [IGNORED]
โ โโโ services/
โ โโโ <service-name>/
โ โ โโโ compose.yml โโโ> ~/.config/ninja-fleet/services/<service-name>/compose.yml [IGNORED]
โ โโโ caddy/
โ โโโ Caddyfile โโโโโ> ~/.config/ninja-fleet/services/caddy/Caddyfile [IGNORED]
โ โโโ compose.yml โโโ> ~/.config/ninja-fleet/services/caddy/compose.yml [IGNORED]
โโโ vault_1password.sh โโโโโโโโโโ> ~/.config/ninja-fleet/vault_1password.sh [IGNORED]
โโโ link-config.sh
โโโ export-config.sh
โโโ site.yml
Tip
This "Overlay" strategy allows you to keep the ninja-fleet repository public while keeping your sensitive host and environment configuration strictly private and separately managed.
- Ansible installed on your primary workstation.
- Python 3.10+ (managed via
pyenvrecommended). - ADB installed (for orchestrating Android phones).
To run the orchestration for the entire fleet:
ansible-playbook site.yml -KTo target a specific host:
ansible-playbook site.yml -K --limit <hostname>To run specific parts of the configuration using tags:
ansible-playbook site.yml -K --tags "shell,git"inventory/: Fleet definition.hosts.ini: Main list of hosts and groups.group_vars/: Configuration shared by groups of hosts.host_vars/: Overrides for specific individual hosts.
roles/: Modular configuration blocks.common: Core utilities, Docker, and shell setup shared by multiple roles.homelab: Docker-based services (Caddy, WireGuard, Technitium, etc.).workstation: GUI apps, dev tools, and workstation-specific tweaks for developers.personal: Basic productivity apps (Chrome, 1Password, etc.) for non-developer machines.plex_server: Windows 11 media server configurations (Plex, etc.).phone: Android app checking and VPN configuration via ADB.
playbooks/: Logic for different system types.site.yml: The entry point for all fleet orchestration.
- Follow the Bootstrap Guide to enable SSH/ADB.
- Add the host entry to
inventory/hosts.ini. - (Optional) Create
inventory/host_vars/<hostname>.ymlfor specific user/group overrides (seeinventory/host_vars/example-host.yml.example). - Run the playbook with
--limit <hostname>.
Sensitive data (passwords, keys) is stored in inventory/group_vars/all/secrets.yml and is encrypted with Ansible Vault.
- Edit secrets:
ansible-vault edit inventory/group_vars/all/secrets.yml - Vault Pass: Stored in
~/.ansible_vault_pass(ensure this exists and is secured). - 1Password Integration: If you use 1Password CLI, see
vault_1password.example.shfor examples on how to retrieve the vault password dynamically.
This project uses Molecule for testing the common role and ansible-lint to enforce a "Production Profile" standard (standardized naming, shell robustness, etc.).
- Bootstrap Guide: Preparing new hardware.
- Walkthrough: Overview of recent project updates and logic.
- Post-Execution Guide: Cleanup and final verification steps.
- Private Config Management: Details on managing private configurations.
This repository is designed to be public-friendly. Sensitive data is handled via:
.gitignore: Excludeshosts.ini,main.yml, andsecrets.yml.*.example.yml: Provides templates for all required configuration.inventory/host_vars/: Ignores host-specific PII/overrides.roles/homelab/templates/: Jinja2 templates for sensitive compose files.
Created and maintained by @ghepting