- name: Install firewalld and systemd-networkd packages ansible.builtin.dnf: name: - firewalld - systemd-container - systemd-networkd - openssl - python3-libsemanage - policycoreutils state: present - name: Configure Polkit to allow machinectl fast user auth ansible.builtin.copy: src: 60-machinectl-fast-user-auth.rules dest: /etc/polkit-1/rules.d/60-machinectl-fast-user-auth.rules mode: "0644" notify: Restart Polkit - name: Ensure firewalld and systemd-networkd are running ansible.builtin.systemd: name: "{{ item }}" state: started enabled: yes loop: - firewalld - systemd-networkd - name: Enable masquerading for container internet access ansible.posix.firewalld: masquerade: yes state: enabled permanent: yes zone: public notify: Reload Firewalld - name: Open HTTP and HTTPS (TCP) for Nginx ansible.posix.firewalld: service: "{{ item }}" state: enabled permanent: yes zone: public loop: - http - https notify: Reload Firewalld - name: Open HTTPS (UDP) for HTTP/3 QUIC support ansible.posix.firewalld: port: 443/udp state: enabled permanent: yes zone: public notify: Reload Firewalld - name: Configure Host Firewall Port Forwarding dynamically ansible.posix.firewalld: port_forward: - port: "{{ item.1 }}" proto: tcp toaddr: "{{ item.0.value.ip }}" toport: "{{ item.1 }}" permanent: yes state: enabled loop: "{{ containers | dict2items | subelements('value.forward_ports', skip_missing=True) }}" notify: Reload Firewalld - name: Create bridge netdev on host ansible.builtin.copy: dest: /etc/systemd/network/10-nspawn-br0.netdev content: | [NetDev] Name=nspawn-br0 Kind=bridge notify: Restart Host systemd-networkd - name: Assign IP to the host bridge ansible.builtin.copy: dest: /etc/systemd/network/10-nspawn-br0.network content: | [Match] Name=nspawn-br0 [Network] Address={{ bridge_ip }}/24 notify: Restart Host systemd-networkd - name: Apply networking changes immediately ansible.builtin.meta: flush_handlers - name: Ensure containers are bootstrapped (AlmaLinux 10) ansible.builtin.dnf: installroot: "/var/lib/machines/{{ item.key }}" releasever: "10" name: - almalinux-release - systemd - dbus - systemd-networkd - passwd - dnf - iproute state: present loop: "{{ containers | dict2items }}" - name: Initialize machine-id for containers ansible.builtin.command: systemd-machine-id-setup --root=/var/lib/machines/{{ item.key }} args: creates: "/var/lib/machines/{{ item.key }}/etc/machine-id" loop: "{{ containers | dict2items }}" - name: Fix SELinux contexts in container rootfs ansible.builtin.command: restorecon -R /var/lib/machines/{{ item.key }} register: restorecon_result changed_when: "'Relabeled' in restorecon_result.stdout" loop: "{{ containers | dict2items }}" - name: Ensure systemd-nspawn directory exists ansible.builtin.file: path: /etc/systemd/nspawn state: directory mode: "0755" - name: Ensure Let's Encrypt mock directories exist ansible.builtin.file: path: "{{ item }}" state: directory mode: '0755' loop: - "/etc/letsencrypt/archive/{{ vault_public_domain }}" - "/etc/letsencrypt/live/{{ vault_public_domain }}" - name: Check if Let's Encrypt certificate exists ansible.builtin.stat: path: "/etc/letsencrypt/live/{{ vault_public_domain }}/fullchain.pem" register: le_cert - name: Generate self-signed fallback cert in Let's Encrypt paths if missing ansible.builtin.command: > openssl req -x509 -nodes -days 365 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -keyout /etc/letsencrypt/live/{{ vault_public_domain }}/privkey.pem -out /etc/letsencrypt/live/{{ vault_public_domain }}/fullchain.pem -subj "/CN={{ vault_public_domain }}" args: creates: "/etc/letsencrypt/live/{{ vault_public_domain }}/fullchain.pem" when: not le_cert.stat.exists - name: Create systemd-nspawn configuration ansible.builtin.template: src: nspawn.j2 dest: "/etc/systemd/nspawn/{{ item.key }}.nspawn" loop: "{{ containers | dict2items }}" notify: Restart Containers - name: Enable and Start Containers ansible.builtin.systemd: name: "systemd-nspawn@{{ item.key }}" state: started enabled: yes loop: "{{ containers | dict2items }}" - name: Install Nginx ansible.builtin.dnf: name: nginx state: present - name: Allow Nginx to connect to upstream servers (SELinux) ansible.posix.seboolean: name: httpd_can_network_connect state: yes persistent: yes - name: Configure Nginx dynamically ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf validate: nginx -t -c %s notify: Restart Nginx - name: Ensure Nginx is enabled and running ansible.builtin.systemd: name: nginx state: started enabled: yes - name: Ensure Let's Encrypt renewal hook directory exists ansible.builtin.file: path: /etc/letsencrypt/renewal-hooks/post state: directory mode: '0755' - name: Deploy Let's Encrypt post-renewal hook for Nginx ansible.builtin.template: src: nginx-reload.sh.j2 dest: /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh mode: '0755'