--- # ============================================================================== # Dawarich LXC — Self-hosted location history (Google Timeline alternative) # ============================================================================== # Rails app + Sidekiq worker + Redis + PostGIS, all on this LXC. PostGIS lives # here (not central DB VM .172) because the DB VM's postgres:16-alpine image # doesn't bundle the postgis extension — see memory project_dawarich for the # convention-exception rationale. # # Ingests: OwnTracks (HTTP, no MQTT broker needed), Dawarich's own iOS/Android # app, Google Takeout exports. Auth: Authentik OIDC end-to-end. # ============================================================================== - name: Deploy Dawarich LXC hosts: all become: true vars_files: - vars/main.yml - vars/vault.yml pre_tasks: - name: Deploy banner debug: msg: "===== {{ ansible_play_name }} → {{ inventory_hostname }} ({{ ansible_host }}) =====" - name: Install infisicalsdk on controller pip: name: infisicalsdk state: present extra_args: --break-system-packages delegate_to: localhost become: false run_once: true - name: Authenticate with Infisical infisical.vault.login: url: "{{ infisical_url }}" auth_method: universal_auth universal_auth_client_id: "{{ infisical_client_id }}" universal_auth_client_secret: "{{ infisical_client_secret }}" register: infisical_login delegate_to: localhost become: false run_once: true - name: Read dawarich secrets infisical.vault.read_secrets: login_data: "{{ infisical_login.login_data }}" project_id: "{{ infisical_project_id }}" env_slug: "prod" path: "/dawarich" as_dict: true register: repo_secrets delegate_to: localhost become: false run_once: true # OIDC creds live in /oidc alongside every other Authentik client (the same # pair pi-auth pushes into Authentik). default('') keeps the play # idempotent before secrets exist / OIDC is flipped on. - name: Read oidc secrets infisical.vault.read_secrets: login_data: "{{ infisical_login.login_data }}" project_id: "{{ infisical_project_id }}" env_slug: "prod" path: "/oidc" as_dict: true register: oidc_secrets delegate_to: localhost become: false run_once: true - name: Read shared secrets infisical.vault.read_secrets: login_data: "{{ infisical_login.login_data }}" project_id: "{{ infisical_project_id }}" env_slug: "prod" path: "/shared" as_dict: true register: shared_secrets delegate_to: localhost become: false run_once: true - name: Map secrets to vars set_fact: dawarich_db_password: "{{ repo_secrets.secrets.vault_dawarich_db_password }}" dawarich_secret_key_base: "{{ repo_secrets.secrets.vault_dawarich_secret_key_base }}" # OTP encryption keys — Dawarich ships built-in defaults but rotating them # off the public defaults is a one-line hardening win. All three required. dawarich_otp_primary_key: "{{ repo_secrets.secrets.vault_dawarich_otp_primary_key }}" dawarich_otp_deterministic_key: "{{ repo_secrets.secrets.vault_dawarich_otp_deterministic_key }}" dawarich_otp_salt: "{{ repo_secrets.secrets.vault_dawarich_otp_salt }}" dawarich_oidc_client_id: "{{ oidc_secrets.secrets.vault_dawarich_oidc_client_id | default('') }}" dawarich_oidc_client_secret: "{{ oidc_secrets.secrets.vault_dawarich_oidc_client_secret | default('') }}" watchtower_gotify_url: "{{ shared_secrets.secrets.vault_watchtower_gotify_url }}" watchtower_api_token: "{{ shared_secrets.secrets.vault_watchtower_api_token }}" roles: - dawarich - alloy