--- # ============================================================================ # deploy-homarr.yml — deploy Homarr as the `ansible` user # ============================================================================ # PLAY 1 (precheck, runner): pull HOMARR_SECRET_ENCRYPTION_KEY from Infisical, # validate it. Stops with a reason if missing/invalid — no target change. # PLAY 2: connect as `ansible`, create ~/docker/homarr/, write compose, start it. # # Prereq: host already bootstrapped (bootstrap.yml) so `ansible` user + key exist. # Infisical auth env vars: same as bootstrap.yml (INFISICAL_CLIENT_ID/SECRET/PROJECT_ID). # # Usage: playbook playbooks/deploy-homarr.yml, extra vars: target=racknerd1 # ============================================================================ - name: "PRECHECK — fetch Homarr secret from Infisical" hosts: localhost gather_facts: false vars: infisical_url: "{{ lookup('env','INFISICAL_URL') | default('http://192.168.122.41:8080', true) }}" infisical_env_slug: "{{ lookup('env','INFISICAL_ENV_SLUG') | default('dev', true) }}" tasks: - name: "[precheck] Infisical auth vars present?" ansible.builtin.assert: that: - lookup('env','INFISICAL_CLIENT_ID') | length > 0 - lookup('env','INFISICAL_CLIENT_SECRET') | length > 0 - lookup('env','INFISICAL_PROJECT_ID') | length > 0 fail_msg: "Missing INFISICAL_CLIENT_ID / _SECRET / _PROJECT_ID in Semaphore Environment." - name: "[precheck] Login to Infisical" infisical.vault.login: url: "{{ infisical_url }}" auth_method: universal_auth universal_auth_client_id: "{{ lookup('env','INFISICAL_CLIENT_ID') }}" universal_auth_client_secret: "{{ lookup('env','INFISICAL_CLIENT_SECRET') }}" register: infisical_login - name: "[precheck] Read secrets" infisical.vault.read_secrets: login_data: "{{ infisical_login.login_data }}" project_id: "{{ lookup('env','INFISICAL_PROJECT_ID') }}" env_slug: "{{ infisical_env_slug }}" path: "/" as_dict: true register: infisical_secrets - name: "[precheck] Validate Homarr key (64 hex)" ansible.builtin.assert: that: - infisical_secrets.secrets.HOMARR_SECRET_ENCRYPTION_KEY is defined - infisical_secrets.secrets.HOMARR_SECRET_ENCRYPTION_KEY | length == 64 fail_msg: "HOMARR_SECRET_ENCRYPTION_KEY missing or not 64 hex chars in env '{{ infisical_env_slug }}'." - name: "[precheck] stash secrets for deploy play" ansible.builtin.set_fact: pc_homarr_key: "{{ infisical_secrets.secrets.HOMARR_SECRET_ENCRYPTION_KEY }}" pc_ssh_privkey: "{{ infisical_secrets.secrets.SSH_PRIVATE_KEY }}" no_log: true - name: "[precheck] write deploy private key to runner temp (0600)" ansible.builtin.copy: dest: "/tmp/homarr_deploy_key" content: "{{ pc_ssh_privkey }}\n" mode: "0600" no_log: true - name: "[precheck] OK" ansible.builtin.debug: msg: "Homarr secret retrieved + valid. Proceeding to deploy." - name: "Deploy Homarr (rootless, as ansible user)" hosts: "{{ target | default('racknerd1') }}" gather_facts: false vars: deploy_user: ansible homarr_dir: "/home/{{ deploy_user }}/docker/homarr" homarr_port: 7575 homarr_image: ghcr.io/homarr-labs/homarr:latest homarr_encryption_key: "{{ hostvars['localhost'].pc_homarr_key }}" # Connect AS the ansible user (created by bootstrap) using the deploy key. NOT root. ansible_user: ansible ansible_ssh_private_key_file: "/tmp/homarr_deploy_key" ansible_ssh_common_args: "-o StrictHostKeyChecking=accept-new -o IdentitiesOnly=yes" tasks: - name: Reset connection so docker group membership is active in this session ansible.builtin.meta: reset_connection - name: Gather facts (after connection reset) ansible.builtin.setup: - name: Docker available (rootless, via docker group)? ansible.builtin.command: docker version register: dv changed_when: false failed_when: dv.rc != 0 - name: Create ~/docker/homarr tree ansible.builtin.file: path: "{{ item }}" state: directory owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: "0755" loop: - "/home/{{ deploy_user }}/docker" - "{{ homarr_dir }}" - "{{ homarr_dir }}/appdata" - name: Write docker-compose.yml ansible.builtin.copy: dest: "{{ homarr_dir }}/docker-compose.yml" owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: "0644" content: | services: homarr: container_name: homarr image: {{ homarr_image }} restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock - {{ homarr_dir }}/appdata:/appdata environment: - SECRET_ENCRYPTION_KEY={{ homarr_encryption_key }} ports: - "{{ homarr_port }}:7575" no_log: true - name: Pull + start Homarr community.docker.docker_compose_v2: project_src: "{{ homarr_dir }}" pull: always state: present - name: Wait for Homarr ansible.builtin.uri: url: "http://127.0.0.1:{{ homarr_port }}/" status_code: [200, 302, 307] register: health retries: 15 delay: 5 until: health.status is defined and health.status in [200, 302, 307] - name: Result ansible.builtin.debug: msg: "Homarr up on {{ inventory_hostname }}:{{ homarr_port }} (HTTP {{ health.status }})" - name: "Cleanup runner temp key" hosts: localhost gather_facts: false tasks: - name: "remove temp deploy key from runner" ansible.builtin.file: path: /tmp/homarr_deploy_key state: absent