- vless_mesh: root-owned checkout, idempotent clone, stale-checkout guard, dashboard_bind default, reinitialize toggle, restart handlers for env/unit changes - netbird_client: tolerate consumed setup keys via fresh reinit flow - add rustdesk role + playbooks, openbao schema/seed scripts, tests - ignore controller-local secrets and recovery backups |
||
|---|---|---|
| .kilo | ||
| .pi/extensions/pi-permission-system | ||
| .wiki | ||
| ansible | ||
| meta | ||
| patch | ||
| plan | ||
| raw/sources | ||
| scripts | ||
| wiki | ||
| .gitattributes | ||
| .gitignore | ||
| anytype-client-netbird.yml | ||
| Caddyfile | ||
| credentials.auto.tfvars.example | ||
| docker_vms.tf | ||
| fix_vault.py | ||
| guidelines.md | ||
| index.md | ||
| iptables-restore.service | ||
| LICENSE | ||
| providers.tf | ||
| read-guide.md | ||
| README.md | ||
| run.sh | ||
| show_vault.sh | ||
| variables.tf | ||
| WIKI_SCHEMA.md | ||
home-vps
Contains the following configuration:
- OpenTofu for VM
- Ansible for deployment
nuageinit — FreeBSD cloud-init for OPNsense
What changed
The FreeBSD 14 BASIC-CLOUDINIT template builder (scripts/freebsd-14-cloudinit+opnsense.py) and the Tofu OPNsense VM (opnsense_vm.tf) have been updated to use nuageinit — FreeBSD's native cloud-init implementation shipped in base since FreeBSD 13.3 — instead of the Python cloud-init package.
The Python vendor-snippet mechanism (cicustom vendor=…) has been removed because nuageinit reads only the standard Proxmox cloud-init ISO (the ide2 drive: user-data, meta-data, network-config) and does not process vendor data.
rc.conf edits inside runcmd now use sysrc (idempotent key=value updates) and route add includes || true so the first-boot script is safe to re-apply; nuageinit itself writes a run-marker after first boot and will not execute again on subsequent reboots.
Credentials and configuration
All existing variables in credentials.auto.tfvars are sufficient; no new Nuage SDN credentials are required (this deployment has no external Nuage VSP/VSD controller).
The only values that affect the OPNsense seed bootstrap are opnsense_vtnet5_ip, gateway, dns_servers, ssh_keys, and vm_username, all already present in the example file.
OpenBao secret workflow
OpenBao runs in LXC 1060 at http://192.168.16.60:8200 with the UI enabled. The Terraform-sensitive values from credentials.auto.tfvars are stored at secret/home-vps/tofu in the KV v2 engine. The backup copies beside the original Terraform and Ansible secret files use the .bak suffix; they are mode 600 and must not be committed.
OpenTofu reads the KV v2 record through the Vault-compatible provider, and Ansible reads host-var fields through community.hashi_vault lookups. The deployment entrypoints export the standard Vault environment variables:
scripts/deploy.sh --ansible
scripts/deploy_tui.py
scripts/tofu-openbao.sh and scripts/ansible-openbao.sh remain optional environment-loading helpers for manual commands. Direct commands must have VAULT_ADDR and VAULT_TOKEN set.
The wrappers use OPENBAO_TOKEN when set, otherwise /home/debian/.config/openbao/home-vps-read.token. Set OPENBAO_ADDR and OPENBAO_TOKEN_FILE when running from another control host. The read token is deliberately limited to secret/data/home-vps/*; do not use the initialization root token for automation.
The backup_host_ssh_private_key Terraform value is intentionally not in the first import. SSH key material remains outside this migration until a separate, explicit mapping is approved.
Scalar secret fields in the Ansible host vars are stored per file under secret/home-vps/ansible/<host-var-name> and are resolved with community.hashi_vault lookups at inventory load time. The OpenBao LXC host var remains local for bootstrap: its NetBird setup key must be available before OpenBao can provide lookups to its own provisioning play.
VLESS mesh OpenBao configuration
The VLESS mesh LXC uses the KV v2 record secret/data/home-vps/ansible/vless-mesh-lxc as the source of truth for the complete upstream server .env.example schema. The OpenBao field names intentionally match the dotenv names exactly (VLESS_* and NEXT_PUBLIC_*). NETBIRD_CLIENT_SETUP_KEY is the additional field consumed by the shared Ansible netbird_client role.
Ansible resolves the full record at runtime with community.hashi_vault.hashi_vault and renders /etc/vless-mesh/vless.env plus the dashboard .env.production. Empty optional fields are valid and disable optional features; VLESS_ADMIN_PASSWORD and VLESS_JWT_SECRET remain required runtime credentials.
- KV engine:
secret(KV v2) - GUI path:
home-vps/ansible/vless-mesh-lxc - Template:
scripts/vless-mesh-openbao.template.json - Required runtime fields:
NETBIRD_CLIENT_SETUP_KEY,VLESS_ADMIN_PASSWORD(12+ characters), andVLESS_JWT_SECRET(32+ characters) - Every server
.env.examplekey must exist, including disabled Reality/WSS/OIDC andNEXT_PUBLIC_*fields - The only intentionally empty upstream defaults are
NEXT_PUBLIC_BASE_PATHand deprecatedNEXT_PUBLIC_API_ORIGIN.
The O action is target-scoped: it reads the selected target role .env.example and credentials.auto.tfvars.example, then creates or extends secret/data/home-vps/ansible/. It also merges that target's related credentials.auto.tfvars.example fields into the shared secret/data/home-vps/tofu record for OpenTofu. Existing values are preserved.
scripts/seed-vless-mesh-openbao.sh
RUN_ANSIBLE=1 sudo bash run.sh
The template and new O records now carry the upstream .env.example placeholder defaults for the optional Reality, WSS, and OIDC fields instead of leaving them blank. Bootstrap feature flags remain password-mode with Reality/WSS disabled; replace every example.com, replace-with-*, and platform-specific path before enabling those modes. The upstream .env.example also documents production front-door components (Xray, Caddy, Cloudflare, and OPNsense). Storing those fields in OpenBao does not by itself deploy those components; the Ansible role currently renders the bootstrap service and leaves Reality/WSS disabled unless their runtime support is added.
Deploy TUI OpenBao initialization
scripts/deploy_tui.py displays O A T D VM columns. Checking O on one or more rows initializes or checks OpenBao once, then processes each selected target independently:
- If OpenBao is already initialized, the TUI asks for the token once in a hidden modal and keeps it only in memory until exit.
- If OpenBao is not initialized, the TUI asks for confirmation, calls the OpenBao initialization API with 5 recovery keys and a 3-key threshold, and saves the returned recovery data as a mode-0600 JSON file under ~/.config/openbao/.
- For every selected host, O resolves that target's .env.example and the safe credentials.auto.tfvars.example, scopes Terraform fields to that target, and writes secret/data/home-vps/ansible/.
- O also merges the selected target's related credentials.auto.tfvars.example fields into secret/data/home-vps/tofu, which is the OpenTofu KV v2 record.
- Existing fields are never overwritten. A missing target .env.example stops that target with an explicit schema-discovery error instead of writing another service's record.
- The O action no longer creates a VLESS record for unrelated rows.
Recovery data must be moved to offline secure storage and deleted from the host after it is secured.
Verifying nuageinit succeeded
After scripts/init_opnsense.sh finishes and the VM is reachable on opnsense_vtnet5_ip:
# Check nuageinit log directly on the VM
ssh admin@<opnsense_vtnet5_ip> 'cat /var/log/nuageinit.log'
# Confirm seed IP is live and SSH is up
ssh -o ConnectTimeout=5 admin@<opnsense_vtnet5_ip> 'uname -a && id'
# Confirm packages were installed
ssh admin@<opnsense_vtnet5_ip> 'pkg info curl python311 sudo'
Assumptions, prerequisites, and risks
- FreeBSD version: nuageinit is present in FreeBSD 14
BASIC-CLOUDINITimages; do not substitute a plainRELEASEorMINIimage — those do not have nuageinit pre-enabled. - Proxmox version: any Proxmox VE version that supports the
bpg/proxmox0.96 provider and cloud-init ISO generation (PVE 7+). - pkg mirrors:
runcmdretriespkg updateandpkg installup to 3 times with a 15-second back-off to tolerate slow or temporarily unavailable mirrors at first boot. - No vendor-snippet removal needed: the old snippet file
/var/lib/vz/snippets/freebsd-14-opnsense.yamlcan be deleted manually from the Proxmox host — it is no longer referenced. - Unsupported cloud-config keys (
fqdn,timezone,ssh_pwauth,package_update) have been removed from the user-data; if timezone needs to be set, addsysrc timezone="Region/City"andadjkerntz -itoruncmdinopnsense_vm.tf. - Manual step: if an existing template VM 8010 was built with the old script it must be rebuilt (
scripts/freebsd-14-cloudinit+opnsense.py) so thecicustomtag is absent before re-deploying the OPNsense VM.
Command to ensure connection via vmbr5
sudo ip link set ens19 up && sudo dhcpcd ens19 && sudo ip route del default && sudo ip route add default via 192.168.16.1 dev ens19 && ip route get 8.8.8.8 sudo ip route del default; sudo ip link set eth0 up && sudo dhcpcd --static ip_address=192.168.16.13/24 --static routers=192.168.16.1 --static domain_name_servers=8.8.8.8 eth0 && sudo ip route del default && sudo ip route add default via 192.168.16.1 dev eth0 && ip route get 8.8.8.8