# Quadlet unit: ComfyUI (rootless, boot-persistent). # # Install path on dankclaw: ~/.config/containers/systemd/comfyui.container # Unit name: comfyui.service (container name: comfyui) # # WHY THIS FILE EXISTS. ComfyUI ran from `dankclaw/compose.yaml` through a # hand-written `~/.config/systemd/user/comfyui.service` that called # `podman compose up -d`. Its container was created 2026-09-15 14:12, BEFORE the # GPU declarations were added to the compose service, and `restart: # unless-stopped` then kept restarting that stale container — so it started # without /dev/kfd, without /dev/dri and without keep-groups, died on # `RuntimeError: No HIP GPUs are available`, and had restarted 9,146 times when # this was found. A recreate via compose would have fixed the container; a unit # fixes the class: one owner per container name, repo-tracked, boot-persistent # through the generator. # # GPU ACCESS. /dev/kfd + /dev/dri plus keep-groups. A literal `render` group # entry cannot work under rootless Podman (the group name does not resolve # inside the user namespace), and the companion udev rule # (dankclaw/udev/99-comfyui-gpu-access.rules) keeps those nodes MODE 0666 so a # user-unit spawn — which carries no supplementary groups — can still open them. # Both halves are asserted by tests/comfyui_rocm.bats. # # EXPOSURE. LAN-reachable, no auth. ComfyUI has no authentication and executes # arbitrary node graphs. It is internal-only (no public vhost, no guard chain); # it is reached on the LAN via the Pi-hole DNS record # (comfyui.franksdank.cloud -> 192.168.0.143, in dankclaw/pihole/addn-hosts), # which resolves to this host's IP — so the bind is widened from loopback to # 0.0.0.0:8188. The homepage admin card links to that URL and probes # 127.0.0.1:8188. # # DATA. Models, input, output and custom_nodes live under # /home/dank/comfyui-data (host state, not in the repo). [Unit] Description=ComfyUI (gfx1151 ROCm image generation) After=network-online.target Wants=network-online.target [Container] ContainerName=comfyui Image=localhost/comfyui-rocm:gfx1151 Pull=never Network=dankclaw_default PublishPort=0.0.0.0:8188:8188 AddDevice=/dev/kfd AddDevice=/dev/dri GroupAdd=keep-groups Volume=/home/dank/comfyui-data/models:/opt/ComfyUI/models Volume=/home/dank/comfyui-data/input:/opt/ComfyUI/input Volume=/home/dank/comfyui-data/output:/opt/ComfyUI/output Volume=/home/dank/comfyui-data/custom_nodes:/opt/ComfyUI/custom_nodes Volume=/home/dank/serverAppConfigs/dankclaw/comfyui/comfyui-healthcheck.py:/usr/local/bin/comfyui-healthcheck.py:ro Exec=/opt/ComfyUI/comfyui-start.sh # The probe lives in a file because the podman 5.x v1 generator splits # HealthCmd on spaces into an argv array; an inline `python3 -c "..."` becomes # a puzzle of quoting that fails silently. HealthCmd=python3 /usr/local/bin/comfyui-healthcheck.py HealthInterval=30s HealthTimeout=10s HealthRetries=3 # First start loads torch and the node graph; give it room before the probe # counts against it. HealthStartPeriod=300s [Service] Restart=always RestartSec=10 [Install] WantedBy=default.target