diff --git a/ansible.cfg b/ansible.cfg index 19fe4b3..98a364c 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -284,7 +284,7 @@ interpreter_python=auto_silent ;verbosity=0 # (boolean) Toggle to control the showing of deprecation warnings -;deprecation_warnings=True +deprecation_warnings=False # (boolean) Toggle to control showing warnings related to running devel. ;devel_warning=True diff --git a/docker/update-docker-compose.yaml b/docker/update-docker-compose.yaml index 4218679..6f3a000 100644 --- a/docker/update-docker-compose.yaml +++ b/docker/update-docker-compose.yaml @@ -1,18 +1,21 @@ --- - name: Deploy Docker Compose stack with pull and restart - hosts: ki5bhv.com + hosts: killer2.ki5bhv.com become: true tasks: - - name: Qbits community.docker.docker_compose_v2: - project_src: /home/justin/docker/qbits/ + project_src: /home/justin/docker/qbits pull: always - recreate: auto + register: result + retries: 3 + delay: 3 + until: result is not failed + - name: Pause ansible.builtin.pause: - seconds: 10 + seconds: 1 - name: homarr community.docker.docker_compose_v2: @@ -22,7 +25,7 @@ - name: Pause ansible.builtin.pause: - seconds: 10 + seconds: 1 - name: wireguard community.docker.docker_compose_v2: @@ -32,7 +35,7 @@ - name: Pause ansible.builtin.pause: - seconds: 10 + seconds: 1 - name: beszel community.docker.docker_compose_v2: @@ -42,7 +45,7 @@ - name: Pause ansible.builtin.pause: - seconds: 10 + seconds: 1 - name: cup community.docker.docker_compose_v2: @@ -52,17 +55,7 @@ - name: Pause ansible.builtin.pause: - seconds: 10 - - - name: nginx-proxy - community.docker.docker_compose_v2: - project_src: /home/justin/docker/nginx-proxy/ - pull: always - recreate: auto - - - name: Pause - ansible.builtin.pause: - seconds: 10 + seconds: 1 - name: ntfy community.docker.docker_compose_v2: @@ -72,7 +65,7 @@ - name: Pause ansible.builtin.pause: - seconds: 10 + seconds: 1 - name: vaultwarden community.docker.docker_compose_v2: @@ -82,7 +75,7 @@ - name: Pause ansible.builtin.pause: - seconds: 10 + seconds: 1 - name: uptime-kuma community.docker.docker_compose_v2: @@ -92,7 +85,7 @@ - name: Pause ansible.builtin.pause: - seconds: 10 + seconds: 1 - name: overseerr community.docker.docker_compose_v2: @@ -102,7 +95,7 @@ - name: Pause ansible.builtin.pause: - seconds: 10 + seconds: 1 - name: portainer community.docker.docker_compose_v2: @@ -112,7 +105,7 @@ - name: Pause ansible.builtin.pause: - seconds: 10 + seconds: 1 - name: it-tools community.docker.docker_compose_v2: @@ -122,7 +115,7 @@ - name: Pause ansible.builtin.pause: - seconds: 10 + seconds: 1 - name: termix community.docker.docker_compose_v2: @@ -132,7 +125,7 @@ - name: Pause ansible.builtin.pause: - seconds: 10 + seconds: 1 - name: ntfy community.docker.docker_compose_v2: @@ -140,6 +133,218 @@ pull: always recreate: auto + - name: Pause + ansible.builtin.pause: + seconds: 1 + + - name: netalertx + community.docker.docker_compose_v2: + project_src: /home/justin/docker/netalertx/ + pull: always + recreate: auto + + - name: Pause + ansible.builtin.pause: + seconds: 1 + + - name: homarr + community.docker.docker_compose_v2: + project_src: /home/justin/docker/homarr/ + pull: always + recreate: auto + + - name: Pause + ansible.builtin.pause: + seconds: 1 + + - name: wireguard + community.docker.docker_compose_v2: + project_src: /home/justin/docker/wireguard/ + pull: always + recreate: auto + + - name: Pause + ansible.builtin.pause: + seconds: 1 + + - name: beszel + community.docker.docker_compose_v2: + project_src: /home/justin/docker/beszel/ + pull: always + recreate: auto + + - name: Pause + ansible.builtin.pause: + seconds: 1 + + - name: cup + community.docker.docker_compose_v2: + project_src: /home/justin/docker/cup/ + pull: always + recreate: auto + + - name: Pause + ansible.builtin.pause: + seconds: 1 + + + - name: ntfy + community.docker.docker_compose_v2: + project_src: /home/justin/docker/ntfy/ + pull: always + recreate: auto + + - name: Pause + ansible.builtin.pause: + seconds: 1 + + - name: vaultwarden + community.docker.docker_compose_v2: + project_src: /home/justin/docker/vaultwarden/ + pull: always + recreate: auto + + - name: Pause + ansible.builtin.pause: + seconds: 1 + + - name: uptime-kuma + community.docker.docker_compose_v2: + project_src: /home/justin/docker/uptime-kuma/ + pull: always + recreate: auto + + - name: Pause + ansible.builtin.pause: + seconds: 1 + + - name: overseerr + community.docker.docker_compose_v2: + project_src: /home/justin/docker/overseerr/ + pull: always + recreate: auto + + - name: Pause + ansible.builtin.pause: + seconds: 1 + + - name: portainer + community.docker.docker_compose_v2: + project_src: /home/justin/docker/portainer/ + pull: always + recreate: auto + + - name: Pause + ansible.builtin.pause: + seconds: 1 + + - name: it-tools + community.docker.docker_compose_v2: + project_src: /home/justin/docker/it-tools/ + pull: always + recreate: auto + + - name: Pause + ansible.builtin.pause: + seconds: 1 + + - name: termix + community.docker.docker_compose_v2: + project_src: /home/justin/docker/termix/ + pull: always + recreate: auto + + - name: Pause + ansible.builtin.pause: + seconds: 1 + + - name: ntfy + community.docker.docker_compose_v2: + project_src: /home/justin/docker/ntfy/ + pull: always + recreate: auto + + - name: Pause + ansible.builtin.pause: + seconds: 1 + + - name: netalertx + community.docker.docker_compose_v2: + project_src: /home/justin/docker/netalertx/ + pull: always + recreate: auto + + - name: Pause + ansible.builtin.pause: + seconds: 1 + + - name: Wavelog + community.docker.docker_compose_v2: + project_src: /home/justin/docker/wavelog/ + pull: always + recreate: auto + + - name: Pause + ansible.builtin.pause: + seconds: 1 + + - name: Kometa + community.docker.docker_compose_v2: + project_src: /home/justin/docker/kometa/ + pull: always + recreate: auto + + - name: Pause + ansible.builtin.pause: + seconds: 1 + + - name: Tautulli + community.docker.docker_compose_v2: + project_src: /home/justin/docker/tautulli/ + pull: always + recreate: auto + + - name: Prune non-dangling images + community.docker.docker_prune: + containers: false + images: true + images_filters: + dangling: false + networks: false + volumes: false + builder_cache: false + +- name: Deploy Docker Compose stack with pull and restart + hosts: docker.ki5bhv.com + become: true + tasks: + + - name: code + community.docker.docker_compose_v2: + project_src: /home/justin/Docker/code-server + pull: always + recreate: auto + + - name: Prune non-dangling images + community.docker.docker_prune: + containers: false + images: true + images_filters: + dangling: false + networks: false + volumes: false + builder_cache: false + +- name: Deploy Docker Compose stack with pull and restart + hosts: proxy-server.ki5bhv.com + become: true + tasks: + - name: nginx proxy + community.docker.docker_compose_v2: + project_src: /home/justin/docker/nginx-proxy + pull: always + recreate: auto + - name: Prune non-dangling images community.docker.docker_prune: containers: false diff --git a/host b/host deleted file mode 100644 index 8e873e2..0000000 --- a/host +++ /dev/null @@ -1,24 +0,0 @@ -[linux] -cloudflare-tunnel.ki5bhv.com -pi-hole-server.ki5bhv.com -mediaserver.ki5bhv.com -webhost.ki5bhv.com -gitserver.ki5bhv.com -ansible.ki5bhv.com -minecraft.ki5bhv.com -ki5bhv.com -coding.ki5bhv.com - -[proxmox] -cloudflare-tunnel.ki5bhv.com -pi-hole-server.ki5bhv.com -webhost.ki5bhv.com -gitserver.ki5bhv.com -ansible.ki5bhv.com -minecraft.ki5bhv.com -ki5bhv.com -coding.ki5bhv.com - -[hardware] -mediaserver.ki5bhv.com - diff --git a/ubuntu/.config-add-sshkey.yaml.swp b/ubuntu/.config-add-sshkey.yaml.swp new file mode 100644 index 0000000..6777e08 Binary files /dev/null and b/ubuntu/.config-add-sshkey.yaml.swp differ diff --git a/ubuntu/fix-ssh-host-keys.yaml b/ubuntu/fix-ssh-host-keys.yaml new file mode 100755 index 0000000..afdba48 --- /dev/null +++ b/ubuntu/fix-ssh-host-keys.yaml @@ -0,0 +1,70 @@ +--- +# fix-ssh-host-keys.yaml +# +# Detects cloned VMs that share the same SSH host key and regenerates a +# unique key set on each one, then refreshes the controller's known_hosts. +# +# Run with host key checking disabled for this one remediation pass, +# since known_hosts is currently in a conflicted state: +# +# ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook fix-ssh-host-keys.yaml +# +# The `duplicate_fingerprint` guard means only hosts presenting the shared +# key get touched. Hosts with an already-unique key are left alone. + +- name: Regenerate shared SSH host keys on cloned guests + hosts: all + become: true + gather_facts: false + vars: + # The shared key every clone is currently presenting. + duplicate_fingerprint: "SHA256:AZekUU+Wwn6S6sCjGD0SdkhVgj3WVqVdiVYa1AXYW8A" + tasks: + - name: Read current ED25519 host key fingerprint + ansible.builtin.command: + cmd: ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub + register: hostkey_fp + changed_when: false + failed_when: false + + - name: Regenerate host keys if this host shares the duplicate key + when: duplicate_fingerprint in (hostkey_fp.stdout | default('')) + block: + - name: Remove existing host keys + ansible.builtin.shell: + cmd: rm -f /etc/ssh/ssh_host_* + # rm on a glob isn't idempotent-reportable; treat as changed. + changed_when: true + + - name: Generate a fresh unique set of host keys + ansible.builtin.command: + cmd: ssh-keygen -A + changed_when: true + + - name: Restart SSH so the new key is served + ansible.builtin.service: + name: ssh + state: restarted + + - name: Note that this host was remediated + ansible.builtin.debug: + msg: "{{ inventory_hostname }} had the shared key and was regenerated." + +- name: Refresh known_hosts on the Ansible controller + hosts: localhost + gather_facts: false + vars: + known_hosts_path: "{{ lookup('env', 'HOME') }}/.ssh/known_hosts" + target_hosts: "{{ groups['all'] | difference(['localhost']) }}" + tasks: + - name: Remove stale entries for every managed host + ansible.builtin.command: + cmd: "ssh-keygen -f {{ known_hosts_path }} -R {{ item }}" + loop: "{{ target_hosts }}" + changed_when: false + + - name: Rescan and add current keys + ansible.builtin.shell: + cmd: "ssh-keyscan -t ed25519,rsa,ecdsa {{ item }} >> {{ known_hosts_path }}" + loop: "{{ target_hosts }}" + changed_when: true diff --git a/ubuntu/open-all-ports.yml b/ubuntu/open-all-ports.yml new file mode 100755 index 0000000..1cdb0ab --- /dev/null +++ b/ubuntu/open-all-ports.yml @@ -0,0 +1,38 @@ +--- +# open-all-ports.yml +# +# Opens all inbound ports on the target Ubuntu servers. +# +# Default behavior: UFW stays enabled but its default incoming +# policy is set to allow, so every port is reachable. +# +# To turn the firewall OFF entirely instead, run with: +# ansible-playbook -i inventory.ini open-all-ports.yml -e "disable_ufw=true" +# +# Uses the community.general.ufw module. +# +# Usage: +# ansible-playbook -i inventory.ini open-all-ports.yml + +- name: Open all inbound ports + hosts: ubuntu_servers + become: true + + vars: + disable_ufw: false + + tasks: + - name: Set default incoming policy to allow (opens all ports) + community.general.ufw: + direction: incoming + policy: allow + + - name: Set default outgoing policy to allow + community.general.ufw: + direction: outgoing + policy: allow + + - name: Optionally disable UFW entirely + community.general.ufw: + state: disabled + when: disable_ufw | bool diff --git a/ubuntu/plex.yaml b/ubuntu/plex.yaml index f4d16bd..de32ae7 100644 --- a/ubuntu/plex.yaml +++ b/ubuntu/plex.yaml @@ -1,6 +1,6 @@ --- - name: Update Plex Sever - hosts: media.ki5bhv.com + hosts: mediaserver.ki5bhv.com become: yes tasks: diff --git a/ubuntu/restrict-ssh.yml b/ubuntu/restrict-ssh.yml new file mode 100755 index 0000000..c85c636 --- /dev/null +++ b/ubuntu/restrict-ssh.yml @@ -0,0 +1,60 @@ +--- +# restrict-ssh.yml +# +# Restricts SSH access on Ubuntu servers to a single IP range using UFW. +# Uses the community.general.ufw module. +# +# Usage: +# ansible-playbook -i inventory.ini restrict-ssh.yml +# +# Override the range or port at runtime: +# ansible-playbook -i inventory.ini restrict-ssh.yml -e "ssh_allowed_range=10.0.0.0/24 ssh_port=2222" + +- name: Restrict SSH access to an allowed IP range + hosts: ubuntu_servers + become: true + + vars: + ssh_allowed_range: "192.168.1.0/24" + ssh_port: 22 + + tasks: + - name: Ensure UFW is installed + ansible.builtin.apt: + name: ufw + state: present + update_cache: true + + - name: Set default policy to deny incoming traffic + community.general.ufw: + direction: incoming + policy: deny + + - name: Set default policy to allow outgoing traffic + community.general.ufw: + direction: outgoing + policy: allow + + - name: Allow SSH only from the permitted range + community.general.ufw: + rule: allow + from_ip: "{{ ssh_allowed_range }}" + to_port: "{{ ssh_port }}" + proto: tcp + + - name: Remove any rule allowing SSH from anywhere (by port) + community.general.ufw: + rule: allow + to_port: "{{ ssh_port }}" + proto: tcp + delete: true + + - name: Remove any rule allowing the OpenSSH application profile from anywhere + community.general.ufw: + rule: allow + name: OpenSSH + delete: true + + - name: Enable UFW + community.general.ufw: + state: enabled diff --git a/ubuntu/revert-ssh.yml b/ubuntu/revert-ssh.yml new file mode 100755 index 0000000..33ec5e7 --- /dev/null +++ b/ubuntu/revert-ssh.yml @@ -0,0 +1,47 @@ +--- +# revert-ssh.yml +# +# Reverts the SSH IP-range restriction applied by restrict-ssh.yml. +# Removes the range-limited SSH rule and re-opens SSH from anywhere so +# you don't lose access. Optionally disables UFW entirely. +# +# Uses the community.general.ufw module. +# +# Usage: +# ansible-playbook -i inventory.ini revert-ssh.yml +# +# To also disable UFW completely: +# ansible-playbook -i inventory.ini revert-ssh.yml -e "disable_ufw=true" +# +# Override the range or port to match what restrict-ssh.yml used: +# ansible-playbook -i inventory.ini revert-ssh.yml -e "ssh_allowed_range=10.0.0.0/24 ssh_port=2222" + +- name: Revert SSH IP-range restriction + hosts: ubuntu_servers + become: true + + vars: + ssh_allowed_range: "192.168.1.0/24" + ssh_port: 22 + disable_ufw: false + + tasks: + - name: Remove the range-restricted SSH rule + community.general.ufw: + rule: allow + from_ip: "{{ ssh_allowed_range }}" + to_port: "{{ ssh_port }}" + proto: tcp + delete: true + + - name: Re-open SSH from anywhere + community.general.ufw: + rule: allow + to_port: "{{ ssh_port }}" + proto: tcp + when: not disable_ufw | bool + + - name: Disable UFW entirely (optional) + community.general.ufw: + state: disabled + when: disable_ufw | bool diff --git a/ubuntu/ssh-hardening.yml b/ubuntu/ssh-hardening.yml new file mode 100644 index 0000000..cbfb494 --- /dev/null +++ b/ubuntu/ssh-hardening.yml @@ -0,0 +1,233 @@ +--- +# ssh-hardening.yml +# ============================================================================= +# Disable SSH password authentication and apply baseline hardening on Ubuntu. +# +# Usage: +# ansible-playbook -i inventory.ini ssh-hardening.yml +# ansible-playbook -i inventory.ini ssh-hardening.yml --limit coding +# ansible-playbook -i inventory.ini ssh-hardening.yml --check # dry run +# +# Example inventory.ini: +# [servers] +# coding ansible_host=192.168.1.21 ansible_user=justin +# +# SAFETY FEATURES: +# * Refuses to run if the login user has no authorized_keys (no lockout). +# * Fixes the cloud-init "first value wins" precedence trap automatically. +# * Validates config with `sshd -t` BEFORE restarting. +# * Verifies password auth is actually off at the end via `sshd -T`. +# +# Optional extras (fail2ban / UFW) use the community.general collection: +# ansible-galaxy collection install community.general +# ============================================================================= + +- name: Harden SSH (key-only authentication + baseline) + hosts: all + become: true + + vars: + # User whose key access is verified before passwords are disabled. + # Defaults to whoever Ansible connects as. + ssh_login_user: "{{ ansible_user | default(lookup('env', 'USER')) }}" + + # ---- Core SSH settings ------------------------------------------------- + ssh_permit_root_login: "prohibit-password" # "no" to block root entirely + ssh_allow_users: [] # e.g. ["justin", "deploy"]; [] = no restriction + ssh_port: 22 # change to move SSH off 22 + + # ---- Optional hardening toggles --------------------------------------- + manage_firewall: false # true = install + enable UFW + install_fail2ban: false + install_unattended_upgrades: false + + handlers: + # Handlers run in the order defined here, so validation always precedes restart. + - name: Validate sshd config + ansible.builtin.command: sshd -t + changed_when: false + listen: "restart ssh stack" + + - name: Restart ssh + ansible.builtin.systemd: + name: ssh + state: restarted + listen: "restart ssh stack" + + - name: Restart ssh.socket + ansible.builtin.systemd: + name: ssh.socket + state: restarted + when: ssh_socket_present | default(false) | bool + listen: "restart ssh stack" + + tasks: + # ---- Pre-flight: prove we won't lock ourselves out -------------------- + - name: Resolve login user's home directory + ansible.builtin.getent: + database: passwd + key: "{{ ssh_login_user }}" + + - name: Set authorized_keys path + ansible.builtin.set_fact: + ssh_authorized_keys_path: "{{ getent_passwd[ssh_login_user][4] }}/.ssh/authorized_keys" + + - name: Stat the login user's authorized_keys + ansible.builtin.stat: + path: "{{ ssh_authorized_keys_path }}" + register: ak + + - name: Refuse to continue if no SSH key is present + ansible.builtin.assert: + that: + - ak.stat.exists + - (ak.stat.size | default(0) | int) > 0 + fail_msg: >- + {{ ssh_login_user }} has no authorized_keys at {{ ssh_authorized_keys_path }}. + Aborting so you don't get locked out. Run `ssh-copy-id {{ ssh_login_user }}@` + first, verify key login works, then re-run this playbook. + success_msg: "Key-based auth verified for {{ ssh_login_user }} - safe to proceed." + + # ---- Detect socket activation (Ubuntu 22.10+ / 24.04 / 26.04) --------- + - name: Check whether ssh.socket exists + ansible.builtin.command: systemctl list-unit-files ssh.socket + register: ssh_socket_check + changed_when: false + failed_when: false + + - name: Record socket-activation state + ansible.builtin.set_fact: + ssh_socket_present: "{{ 'ssh.socket' in ssh_socket_check.stdout }}" + + # ---- Fix the cloud-init precedence trap ------------------------------- + # sshd uses the FIRST value it sees for a directive. Files load in + # alphanumeric order, so 50-cloud-init.conf (PasswordAuthentication yes) + # beats a later 99-hardening.conf. Neutralize it at the source. + - name: Check for the cloud-init SSH drop-in + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d/50-cloud-init.conf + register: cloud_init_conf + + - name: Force PasswordAuthentication off in the cloud-init drop-in + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/50-cloud-init.conf + regexp: '^\s*PasswordAuthentication\s+' + line: "PasswordAuthentication no" + state: present + when: cloud_init_conf.stat.exists + notify: "restart ssh stack" + + # ---- Authoritative hardening drop-in ---------------------------------- + - name: Deploy SSH hardening drop-in + ansible.builtin.copy: + dest: /etc/ssh/sshd_config.d/99-hardening.conf + owner: root + group: root + mode: "0644" + validate: "sshd -t -f %s" + content: | + # Managed by Ansible - ssh-hardening.yml. Do not edit by hand. + PasswordAuthentication no + PubkeyAuthentication yes + KbdInteractiveAuthentication no + PermitRootLogin {{ ssh_permit_root_login }} + {% if ssh_allow_users | length > 0 %} + AllowUsers {{ ssh_allow_users | join(' ') }} + {% endif %} + {% if ssh_port != 22 %} + Port {{ ssh_port }} + {% endif %} + notify: "restart ssh stack" + + # ---- Stop cloud-init from re-enabling passwords on rebuild ------------ + - name: Check for cloud-init config directory + ansible.builtin.stat: + path: /etc/cloud/cloud.cfg.d + register: cloud_init_dir + + - name: Pin ssh_pwauth off for cloud-init + ansible.builtin.copy: + dest: /etc/cloud/cloud.cfg.d/99-disable-password-auth.cfg + owner: root + group: root + mode: "0644" + content: | + # Managed by Ansible - ssh-hardening.yml + ssh_pwauth: false + when: cloud_init_dir.stat.exists + + # ---- Optional: UFW firewall ------------------------------------------- + - name: Configure UFW firewall + when: manage_firewall | bool + block: + - name: Install UFW + ansible.builtin.apt: + name: ufw + state: present + update_cache: true + + - name: Allow the SSH port through UFW + community.general.ufw: + rule: allow + port: "{{ ssh_port }}" + proto: tcp + + - name: Enable UFW with a default-deny inbound policy + community.general.ufw: + state: enabled + policy: deny + direction: incoming + + # ---- Optional: fail2ban ----------------------------------------------- + - name: Install and enable fail2ban + when: install_fail2ban | bool + block: + - name: Install fail2ban + ansible.builtin.apt: + name: fail2ban + state: present + update_cache: true + + - name: Enable and start fail2ban + ansible.builtin.systemd: + name: fail2ban + enabled: true + state: started + + # ---- Optional: unattended security upgrades --------------------------- + - name: Enable unattended security upgrades + when: install_unattended_upgrades | bool + block: + - name: Install unattended-upgrades + ansible.builtin.apt: + name: unattended-upgrades + state: present + update_cache: true + + - name: Turn on periodic update + upgrade + ansible.builtin.copy: + dest: /etc/apt/apt.conf.d/20auto-upgrades + owner: root + group: root + mode: "0644" + content: | + APT::Periodic::Update-Package-Lists "1"; + APT::Periodic::Unattended-Upgrade "1"; + + # ---- Apply restarts, then verify the result --------------------------- + - name: Apply any pending SSH restarts now + ansible.builtin.meta: flush_handlers + + - name: Read the effective sshd configuration + ansible.builtin.command: sshd -T + register: sshd_effective + changed_when: false + + - name: Confirm password authentication is actually disabled + ansible.builtin.assert: + that: + - "'passwordauthentication no' in sshd_effective.stdout" + fail_msg: >- + Password auth is STILL enabled in the effective config. + Check drop-in precedence with: sudo sshd -T | grep -i passwordauth + success_msg: "Confirmed: password authentication is disabled." diff --git a/ubuntu/update.yaml b/ubuntu/update.yaml index 0cc3d8d..76a1394 100755 --- a/ubuntu/update.yaml +++ b/ubuntu/update.yaml @@ -1,22 +1,17 @@ --- -- name: Send Start update - hosts: localhost - - tasks: - - name: send ntfy - ansible.builtin.command: - cmd: 'curl -d "Starting updating with ansible" ntfy.ki5bhv.com/server' - - name: Proxmox Update and upgrade apt packages hosts: proxmox become: yes serial: 1 tasks: + - name: Update packages with apt when: ansible_facts['pkg_mgr'] == 'apt' ansible.builtin.apt: update_cache: true + cache_valid_time: 3600 + lock_timeout: 600 - name: Installing proxmox guest agent when: ansible_facts['pkg_mgr'] == 'apt' @@ -45,10 +40,13 @@ become: yes tasks: + - name: Update packages with apt when: ansible_facts['pkg_mgr'] == 'apt' ansible.builtin.apt: update_cache: true + cache_valid_time: 3600 + lock_timeout: 600 - name: Upgrade packages with apt when: ansible_facts['pkg_mgr'] == 'apt' @@ -72,10 +70,3 @@ name: net-tools state: latest -- name: Send completed update - hosts: localhost - - tasks: - - name: send ntfy - ansible.builtin.command: - cmd: 'curl -d "Updated with ansible" ntfy.ki5bhv.com/server' diff --git a/ubuntu/{changed: b/ubuntu/{changed: new file mode 100644 index 0000000..e69de29