--- - name: Fail if the connecting user resolved to root ansible.builtin.assert: that: podman_user != 'root' fail_msg: >- podman_user resolved to root, but this playbook configures *rootless* Podman and writes Quadlet units into the user's home. Connect as the unprivileged user that should own the containers, e.g. `ansible-playbook -u tanshu ...`. If this appeared because become was re-enabled at play level, drop it: the root-only tasks below elevate individually. - name: Install Podman and the rootless runtime pieces ansible.builtin.apt: name: - podman state: present update_cache: true cache_valid_time: 3600 become: true # Without lingering, the user manager stops with the last session and units # never start at boot. - name: Enable systemd lingering for {{ podman_user }} ansible.builtin.command: "loginctl enable-linger {{ podman_user }}" args: creates: "/var/lib/systemd/linger/{{ podman_user }}" become: true # Rootless containers cannot bind ports below 1024 unless the kernel floor is # lowered. Applied inline, because a handler would run after Caddy already bound. - name: Read the current unprivileged port floor ansible.builtin.command: sysctl -n net.ipv4.ip_unprivileged_port_start register: podman_port_floor changed_when: false - name: Persist the unprivileged port floor ansible.builtin.copy: dest: /etc/sysctl.d/99-podman.conf owner: root group: root mode: "0644" content: | # Managed by Ansible (podman role). net.ipv4.ip_unprivileged_port_start = {{ podman_unprivileged_port_start }} become: true - name: Apply the unprivileged port floor ansible.builtin.command: >- sysctl -w net.ipv4.ip_unprivileged_port_start={{ podman_unprivileged_port_start }} become: true when: podman_port_floor.stdout | int > podman_unprivileged_port_start changed_when: true - name: Ensure the Quadlet unit directory exists ansible.builtin.file: path: "{{ quadlet_dir }}" state: directory owner: "{{ podman_user }}" group: "{{ podman_user }}" mode: "0755"