Bootstrap a Raspberry Pi 5 into a self-hosted AI node using Ansible. One command takes a fresh Raspberry Pi OS Lite install (SSH only) to a fully configured machine with Docker, Node.js, and Claude Code.
| Role | What it does |
|---|---|
| base | System upgrade, essential packages (git, curl, vim, htop, tmux, jq...), locale, timezone, hostname, UFW firewall (SSH only) |
| docker | Docker CE from official repo, Compose plugin, user added to docker group |
| claude-code | Node.js LTS via NodeSource, @anthropic-ai/claude-code globally via npm |
- A Raspberry Pi 5 running Raspberry Pi OS Lite (64-bit) with SSH enabled
- SSH access from your machine to the Pi (key-based auth recommended)
- Ansible installed on your local machine:
# macOS brew install ansible # Ubuntu/Debian sudo apt install ansible
- Ansible collections:
ansible-galaxy collection install -r requirements.yml
Edit inventory/hosts.yml with your Pi's IP and SSH user:
all:
hosts:
raspi:
ansible_host: 192.168.1.100 # Your Pi's IP
ansible_user: pi # Your SSH user
ansible_ssh_private_key_file: ~/.ssh/id_ed25519All settings can be overridden directly in inventory/hosts.yml. Uncomment and change any value:
# base_hostname: raspi-ai
# base_locale: en_US.UTF-8
# base_timezone: Europe/Paris
# nodejs_major_version: "22"See each role's defaults/main.yml for the full list of variables.
ansible all -m pingExpected output:
raspi | SUCCESS => { "ping": "pong" }
# Dry-run first (shows what would change, applies nothing)
ansible-playbook playbooks/bootstrap.yml --check
# Run for real
ansible-playbook playbooks/bootstrap.ymlThe API key is managed securely with Ansible Vault. Create an encrypted vars file:
ansible-vault create inventory/group_vars/all/vault.ymlAdd your key inside:
anthropic_api_key: "sk-ant-..."Then run the playbook with --ask-vault-pass:
ansible-playbook playbooks/bootstrap.yml --ask-vault-passThe key will be deployed to /etc/profile.d/claude.sh (mode 0600, root only). If you skip this step, the file is created with a commented-out placeholder instead.
Tip: To avoid typing the vault password every time, store it in a file and reference it:
echo 'my-vault-password' > .vault_pass ansible-playbook playbooks/bootstrap.yml --vault-password-file .vault_pass
.vault_passis already in.gitignore.
ansible-playbook playbooks/bootstrap.yml --tags base
ansible-playbook playbooks/bootstrap.yml --tags docker
ansible-playbook playbooks/bootstrap.yml --tags claude-codeThe project uses Molecule for integration testing. It runs the full playbook against a Debian Bookworm Docker container and validates:
- Converge: all tasks execute without errors
- Idempotence: a second run produces zero changes
- Verify: all expected packages and tools are installed
pip install molecule molecule-plugins[docker]
molecule testApache 2.0