--- # Deploy Homarr dashboard via Docker Compose. # Usage (Semaphore Task Template): playbook = playbooks/deploy-homarr.yml, inventory = inventory/hosts.yml, limit = racknerd1 # # REQUIRED extra var (set in Semaphore -> Variable Groups / Survey, NOT committed): # homarr_secret_encryption_key : 64-char hex (openssl rand -hex 32). Homarr v1 refuses to start without it. - name: Deploy Homarr hosts: racknerd1 become: true vars: homarr_dir: /opt/homarr homarr_port: 7575 homarr_image: ghcr.io/homarr-labs/homarr:latest # homarr_secret_encryption_key: "" tasks: - name: Ensure Docker is present ansible.builtin.command: docker version register: docker_check changed_when: false failed_when: docker_check.rc != 0 - name: Fail early if encryption key not provided ansible.builtin.assert: that: - homarr_secret_encryption_key is defined - homarr_secret_encryption_key | length == 64 fail_msg: >- homarr_secret_encryption_key must be a 64-char hex string. Generate with `openssl rand -hex 32` and set it as a Semaphore variable. - name: Create Homarr directories ansible.builtin.file: path: "{{ item }}" state: directory mode: "0755" loop: - "{{ homarr_dir }}" - "{{ homarr_dir }}/appdata" - name: Write docker-compose.yml ansible.builtin.copy: dest: "{{ homarr_dir }}/docker-compose.yml" 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_secret_encryption_key }} ports: - "{{ homarr_port }}:7575" - name: Pull and start Homarr community.docker.docker_compose_v2: project_src: "{{ homarr_dir }}" pull: always state: present register: compose_result - name: Wait for Homarr to answer ansible.builtin.uri: url: "http://127.0.0.1:{{ homarr_port }}/" status_code: [200, 302, 307] register: health retries: 12 delay: 5 until: health.status is defined - name: Report ansible.builtin.debug: msg: "Homarr is up on {{ inventory_hostname }}:{{ homarr_port }} (status {{ health.status | default('n/a') }})"