refactor: split monolithic playbook into 9 focused ansible roles
Refactored the single ansible-playbook.yml into granular roles under roles/: - packages: dnf update + package installs - directories: /opt/apps/* directory creation - sysctl: ip_forward, src_valid_mark, vm.max_map_count tuning - network: npm_internal podman network - wireguard: kernel module, wg-easy container, nftables hook patching - npm: Nginx Proxy Manager container - gitea: Gitea container - jellyfin: Jellyfin container - wazuh: cert generation + indexer/manager/dashboard containers Top-level playbook is now a role dispatcher with image pre-pull kept upfront. n8n deployment kept as commented-out guidance with an enable checklist. All variables remain in top-level vars.yml. Done by Sisyphus.
This commit is contained in:
@@ -1,433 +1,47 @@
|
|||||||
---
|
---
|
||||||
- hosts: internal-apps
|
- hosts: internal-apps
|
||||||
become: true
|
become: true
|
||||||
vars_files:
|
vars_files:
|
||||||
- ./vars.yml
|
- ./vars.yml
|
||||||
tasks:
|
tasks:
|
||||||
- name: Update Packages
|
- name: Pull images
|
||||||
ansible.builtin.dnf:
|
|
||||||
update_cache: yes
|
|
||||||
|
|
||||||
- name: Install Packages
|
|
||||||
ansible.builtin.dnf:
|
|
||||||
name:
|
|
||||||
- vim
|
|
||||||
- podman
|
|
||||||
- fail2ban
|
|
||||||
- python3-libdnf5
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Create directories
|
|
||||||
file:
|
|
||||||
path: "{{ item }}"
|
|
||||||
state: directory
|
|
||||||
mode: '0755'
|
|
||||||
loop: "{{ directories }}"
|
|
||||||
|
|
||||||
- name: Create Jellyfin directories
|
|
||||||
file:
|
|
||||||
path: "{{ item }}"
|
|
||||||
state: directory
|
|
||||||
mode: '0777'
|
|
||||||
loop: "{{ directories_jellyfin }}"
|
|
||||||
|
|
||||||
- name: Create internal podman network
|
|
||||||
containers.podman.podman_network:
|
|
||||||
name: npm_internal
|
|
||||||
ip_range: 10.10.0.128/25
|
|
||||||
subnet: 10.10.0.0/24
|
|
||||||
gateway: 10.10.0.1
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Ensure WireGuard kernel module is loaded
|
|
||||||
ansible.builtin.modprobe:
|
|
||||||
name: wireguard
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Persist WireGuard kernel module across reboots
|
|
||||||
ansible.builtin.copy:
|
|
||||||
dest: /etc/modules-load.d/wg-easy.conf
|
|
||||||
content: |
|
|
||||||
wireguard
|
|
||||||
nft_masq
|
|
||||||
mode: '0644'
|
|
||||||
|
|
||||||
- name: Enable IP forwarding on host
|
|
||||||
ansible.posix.sysctl:
|
|
||||||
name: net.ipv4.ip_forward
|
|
||||||
value: '1'
|
|
||||||
sysctl_set: true
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Enable source valid mark on host
|
|
||||||
ansible.posix.sysctl:
|
|
||||||
name: net.ipv4.conf.all.src_valid_mark
|
|
||||||
value: '1'
|
|
||||||
sysctl_set: true
|
|
||||||
state: present
|
|
||||||
reload: true
|
|
||||||
|
|
||||||
- name: Raise vm.max_map_count for Wazuh indexer
|
|
||||||
ansible.posix.sysctl:
|
|
||||||
name: vm.max_map_count
|
|
||||||
value: '262144'
|
|
||||||
sysctl_set: true
|
|
||||||
state: present
|
|
||||||
reload: true
|
|
||||||
|
|
||||||
- name: pull images
|
|
||||||
containers.podman.podman_image:
|
containers.podman.podman_image:
|
||||||
name: "{{ item }}"
|
name: "{{ item }}"
|
||||||
loop: "{{ images }}"
|
loop: "{{ images }}"
|
||||||
|
|
||||||
- name: Deploy Nginx Proxy Manager
|
roles:
|
||||||
containers.podman.podman_container:
|
- packages
|
||||||
image: "docker.io/jc21/nginx-proxy-manager:latest"
|
- directories
|
||||||
name: npm
|
- sysctl
|
||||||
restart_policy: always
|
- network
|
||||||
recreate: true
|
- wireguard
|
||||||
state: started
|
- npm
|
||||||
ports:
|
- gitea
|
||||||
- "80:80"
|
- jellyfin
|
||||||
- "81:81"
|
- wazuh
|
||||||
- "443:443"
|
|
||||||
volumes:
|
|
||||||
- "/opt/apps/npm:/data:z"
|
|
||||||
- "/opt/apps/letsencrypt:/etc/letsencrypt:z"
|
|
||||||
network:
|
|
||||||
- npm_internal
|
|
||||||
ip: '10.10.0.19'
|
|
||||||
|
|
||||||
|
|
||||||
- name: Deploy Gitea
|
|
||||||
containers.podman.podman_container:
|
|
||||||
image: docker.gitea.com/gitea:nightly
|
|
||||||
name: gitea
|
|
||||||
env:
|
|
||||||
USER_UID: 1000
|
|
||||||
USER_GID: 1000
|
|
||||||
restart_policy: always
|
|
||||||
recreate: true
|
|
||||||
state: started
|
|
||||||
volumes:
|
|
||||||
- /opt/apps/gitea:/data:z
|
|
||||||
- /usr/share/zoneinfo/America/Denver:/etc/timezone:ro
|
|
||||||
- /etc/localtime:/etc/localtime:ro
|
|
||||||
network:
|
|
||||||
- npm_internal
|
|
||||||
ip: '10.10.0.25'
|
|
||||||
ports:
|
|
||||||
# - "3000:3000"
|
|
||||||
- "222:22"
|
|
||||||
|
|
||||||
- name: Deploy Jellyfin
|
|
||||||
containers.podman.podman_container:
|
|
||||||
image: lscr.io/linuxserver/jellyfin:latest
|
|
||||||
name: jellyfin
|
|
||||||
env:
|
|
||||||
USER_UID: 1000
|
|
||||||
USER_GID: 1000
|
|
||||||
JELLYFIN_PublishedServerUrl: http://jellyfin.boxswapper.io
|
|
||||||
restart_policy: always
|
|
||||||
recreate: true
|
|
||||||
state: started
|
|
||||||
volumes:
|
|
||||||
- /opt/apps/jellyfin/config:/config:z
|
|
||||||
- /opt/apps/jellyfin/tvseries:/data/tvshows:z
|
|
||||||
- /opt/apps/jellyfin/movies:/data/movies:z
|
|
||||||
- /usr/share/zoneinfo/America/Denver:/etc/timezone:ro
|
|
||||||
- /etc/localtime:/etc/localtime:ro
|
|
||||||
network:
|
|
||||||
- npm_internal
|
|
||||||
ip: '10.10.0.30'
|
|
||||||
# ports:
|
|
||||||
# - 8096:8096
|
|
||||||
# - 8920:8920 #optional
|
|
||||||
# - 7359:7359/udp #optional
|
|
||||||
# - 1900:1900/udp #optional
|
|
||||||
|
|
||||||
# WireGuard Easy VPN (v15) — UI at 10.10.0.36:51821 on npm_internal, fronted by NPM
|
|
||||||
# (vpn.boxswapper.io -> http://10.10.0.36:51821). Login: admin / wireguard_ui_password from vars.yml.
|
|
||||||
# v15 init is ONE-TIME: the INIT_* envs below are consumed only when /etc/wireguard/wg-easy.db is ABSENT.
|
|
||||||
# Force a re-init (wipes clients + server keys): podman rm -f wg-easy && rm -rf /opt/apps/wireguard, then re-run.
|
|
||||||
# NAT from VPN clients to LAN/apps (10.10.1.0/24 -> 10.10.0.0/24) uses NFTABLES hooks —
|
|
||||||
# wg-easy's iptables-legacy hooks cannot init the nat table inside a podman netns
|
|
||||||
# ("Table does not exist"), which makes wg-quick up fail and every client API call
|
|
||||||
# 500 with "Unable to access interface". scripts/patch-wg-hooks.py rewrites the hooks
|
|
||||||
# to nft rules and the tasks below restart wg-easy to apply them. See the official
|
|
||||||
# wg-easy "Podman + nftables" tutorial.
|
|
||||||
# EXTERNAL ACCESS: router MUST forward UDP 51820 -> 192.168.0.98. Test from LTE,
|
|
||||||
# not your LAN — NAT hairpin breaks public-IP handshakes from inside the network.
|
|
||||||
- name: Deploy WireGuard Easy (wg-easy)
|
|
||||||
containers.podman.podman_container:
|
|
||||||
name: wg-easy
|
|
||||||
image: "{{ wireguard_image }}"
|
|
||||||
restart_policy: always
|
|
||||||
recreate: true
|
|
||||||
state: started
|
|
||||||
env:
|
|
||||||
INIT_ENABLED: "true"
|
|
||||||
INIT_USERNAME: "{{ wireguard_ui_username }}"
|
|
||||||
INIT_PASSWORD: "{{ wireguard_ui_password }}"
|
|
||||||
INIT_HOST: "{{ wireguard_host }}"
|
|
||||||
INIT_PORT: "{{ wireguard_port }}"
|
|
||||||
INIT_DNS: "{{ wireguard_default_dns }}"
|
|
||||||
INIT_IPV4_CIDR: "{{ wireguard_cidr }}"
|
|
||||||
INIT_IPV6_CIDR: "{{ wireguard_ipv6_cidr }}"
|
|
||||||
INIT_ALLOWED_IPS: "{{ wireguard_allowed_ips }}"
|
|
||||||
PORT: "{{ wireguard_ui_port }}"
|
|
||||||
INSECURE: "true"
|
|
||||||
DISABLE_VERSION_CHECK: "true"
|
|
||||||
ports:
|
|
||||||
- "{{ wireguard_port }}:{{ wireguard_port }}/udp"
|
|
||||||
- "{{ wireguard_ui_port }}:{{ wireguard_ui_port }}/tcp"
|
|
||||||
volumes:
|
|
||||||
- "/opt/apps/wireguard:/etc/wireguard:z"
|
|
||||||
- "/lib/modules:/lib/modules:ro"
|
|
||||||
cap_add:
|
|
||||||
- NET_ADMIN
|
|
||||||
- SYS_MODULE
|
|
||||||
- NET_RAW
|
|
||||||
sysctl:
|
|
||||||
net.ipv4.ip_forward: "1"
|
|
||||||
net.ipv4.conf.all.src_valid_mark: "1"
|
|
||||||
net.ipv6.conf.all.disable_ipv6: "0"
|
|
||||||
net.ipv6.conf.all.forwarding: "1"
|
|
||||||
net.ipv6.conf.default.forwarding: "1"
|
|
||||||
network:
|
|
||||||
- npm_internal
|
|
||||||
ip: '{{ wireguard_ip }}'
|
|
||||||
|
|
||||||
- name: Copy wg-easy hook repair script
|
|
||||||
ansible.builtin.copy:
|
|
||||||
src: ./scripts/patch-wg-hooks.py
|
|
||||||
dest: /opt/apps/wireguard/patch-wg-hooks.py
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: '0755'
|
|
||||||
|
|
||||||
- name: Replace iptables hooks with nftables (iptables-legacy broken in podman)
|
|
||||||
ansible.builtin.command: python3 /opt/apps/wireguard/patch-wg-hooks.py
|
|
||||||
register: wg_hooks_patch
|
|
||||||
changed_when: "'patched hooks' in wg_hooks_patch.stdout"
|
|
||||||
|
|
||||||
- name: Restart wg-easy to apply nft hooks
|
|
||||||
ansible.builtin.command: podman restart wg-easy
|
|
||||||
when: "'patched hooks' in wg_hooks_patch.stdout"
|
|
||||||
|
|
||||||
- name: Wait for WireGuard Easy web UI
|
|
||||||
ansible.builtin.wait_for:
|
|
||||||
host: '{{ wireguard_ip }}'
|
|
||||||
port: '{{ wireguard_ui_port }}'
|
|
||||||
delay: 5
|
|
||||||
timeout: 120
|
|
||||||
|
|
||||||
# Wazuh SIEM (single-node: indexer + manager + dashboard) on npm_internal
|
|
||||||
# Dashboard is NOT exposed on host ports — NPM proxies wazuh.boxswapper.io to https://10.10.0.40:5601
|
|
||||||
# DNS record must be grey-cloud (Cloudflare 523 lesson from vpn.boxswapper.io), cert via NPM
|
|
||||||
# Config is copied from ./wazuh-docker/config before first deploy
|
|
||||||
- name: Copy Wazuh config files to host
|
|
||||||
ansible.builtin.copy:
|
|
||||||
src: ./wazuh-docker/config/
|
|
||||||
dest: /opt/apps/wazuh/config/
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: preserve
|
|
||||||
force: true
|
|
||||||
|
|
||||||
- name: Check for stale Wazuh certificate residue
|
|
||||||
ansible.builtin.stat:
|
|
||||||
path: /opt/apps/wazuh/config/wazuh_indexer_ssl_certs/root-ca.pem
|
|
||||||
register: wazuh_cert_residue
|
|
||||||
|
|
||||||
- name: Remove stale Wazuh certificate directories
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: /opt/apps/wazuh/config/wazuh_indexer_ssl_certs
|
|
||||||
state: absent
|
|
||||||
when: wazuh_cert_residue.stat.exists and wazuh_cert_residue.stat.isdir
|
|
||||||
|
|
||||||
- name: Recreate Wazuh certificates directory
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: /opt/apps/wazuh/config/wazuh_indexer_ssl_certs
|
|
||||||
state: directory
|
|
||||||
mode: '0755'
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
|
|
||||||
- name: Generate Wazuh certificates
|
|
||||||
ansible.builtin.command: podman run --rm -e CERT_TOOL_VERSION=4.14 -v /opt/apps/wazuh/config/certs.yml:/config/certs.yml:z -v /opt/apps/wazuh/config/wazuh_indexer_ssl_certs/:/certificates:z docker.io/wazuh/wazuh-certs-generator:0.0.3
|
|
||||||
args:
|
|
||||||
creates: /opt/apps/wazuh/config/wazuh_indexer_ssl_certs/root-ca.pem
|
|
||||||
|
|
||||||
- name: Copy root CA as manager root CA
|
|
||||||
ansible.builtin.copy:
|
|
||||||
src: /opt/apps/wazuh/config/wazuh_indexer_ssl_certs/root-ca.pem
|
|
||||||
dest: /opt/apps/wazuh/config/wazuh_indexer_ssl_certs/root-ca-manager.pem
|
|
||||||
remote_src: true
|
|
||||||
force: false
|
|
||||||
|
|
||||||
- name: Deploy Wazuh indexer
|
|
||||||
containers.podman.podman_container:
|
|
||||||
name: wazuh.indexer
|
|
||||||
image: "docker.io/wazuh/wazuh-indexer:{{ wazuh_version }}"
|
|
||||||
hostname: wazuh.indexer
|
|
||||||
restart_policy: always
|
|
||||||
recreate: true
|
|
||||||
state: started
|
|
||||||
env:
|
|
||||||
OPENSEARCH_JAVA_OPTS: "-Xms1g -Xmx1g"
|
|
||||||
ulimit:
|
|
||||||
- "memlock=-1:-1"
|
|
||||||
- "nofile=65536:65536"
|
|
||||||
volumes:
|
|
||||||
- "wazuh-indexer-data:/var/lib/wazuh-indexer"
|
|
||||||
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-indexer/config/certs/root-ca.pem:z"
|
|
||||||
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/wazuh.indexer-key.pem:/usr/share/wazuh-indexer/config/certs/wazuh.indexer.key:z"
|
|
||||||
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/wazuh.indexer.pem:/usr/share/wazuh-indexer/config/certs/wazuh.indexer.pem:z"
|
|
||||||
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/admin.pem:/usr/share/wazuh-indexer/config/certs/admin.pem:z"
|
|
||||||
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/admin-key.pem:/usr/share/wazuh-indexer/config/certs/admin-key.pem:z"
|
|
||||||
- "/opt/apps/wazuh/config/wazuh_indexer/wazuh.indexer.yml:/usr/share/wazuh-indexer/config/opensearch.yml:z"
|
|
||||||
- "/opt/apps/wazuh/config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/config/opensearch-security/internal_users.yml:z"
|
|
||||||
network:
|
|
||||||
- npm_internal
|
|
||||||
ip: '{{ wazuh_indexer_ip }}'
|
|
||||||
|
|
||||||
- name: Wait for Wazuh indexer to be ready
|
|
||||||
ansible.builtin.wait_for:
|
|
||||||
host: '{{ wazuh_indexer_ip }}'
|
|
||||||
port: 9200
|
|
||||||
delay: 10
|
|
||||||
timeout: 300
|
|
||||||
|
|
||||||
- name: Deploy Wazuh manager
|
|
||||||
containers.podman.podman_container:
|
|
||||||
name: wazuh.manager
|
|
||||||
image: "docker.io/wazuh/wazuh-manager:{{ wazuh_version }}"
|
|
||||||
hostname: wazuh.manager
|
|
||||||
restart_policy: always
|
|
||||||
recreate: true
|
|
||||||
state: started
|
|
||||||
env:
|
|
||||||
INDEXER_URL: "https://wazuh.indexer:9200"
|
|
||||||
INDEXER_USERNAME: "admin"
|
|
||||||
INDEXER_PASSWORD: "*WD*oW9m6iKf4hDovy7BbMmhLxC9D?Tv"
|
|
||||||
FILEBEAT_SSL_VERIFICATION_MODE: "full"
|
|
||||||
SSL_CERTIFICATE_AUTHORITIES: "/etc/ssl/root-ca.pem"
|
|
||||||
SSL_CERTIFICATE: "/etc/ssl/filebeat.pem"
|
|
||||||
SSL_KEY: "/etc/ssl/filebeat.key"
|
|
||||||
API_USERNAME: "wazuh-wui"
|
|
||||||
API_PASSWORD: "MyS3cr37P450r.*-"
|
|
||||||
ulimit:
|
|
||||||
- "memlock=-1:-1"
|
|
||||||
- "nofile=655360:655360"
|
|
||||||
ports:
|
|
||||||
- "1514:1514"
|
|
||||||
- "1515:1515"
|
|
||||||
- "514:514/udp"
|
|
||||||
- "55000:55000"
|
|
||||||
volumes:
|
|
||||||
- "wazuh_api_configuration:/var/ossec/api/configuration"
|
|
||||||
- "wazuh_etc:/var/ossec/etc"
|
|
||||||
- "wazuh_logs:/var/ossec/logs"
|
|
||||||
- "wazuh_queue:/var/ossec/queue"
|
|
||||||
- "wazuh_var_multigroups:/var/ossec/var/multigroups"
|
|
||||||
- "wazuh_integrations:/var/ossec/integrations"
|
|
||||||
- "wazuh_agentless:/var/ossec/agentless"
|
|
||||||
- "wazuh_active_response:/var/ossec/active-response/bin"
|
|
||||||
- "wazuh_wodles:/var/ossec/wodles"
|
|
||||||
- "filebeat_etc:/etc/filebeat"
|
|
||||||
- "filebeat_var:/var/lib/filebeat"
|
|
||||||
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/root-ca-manager.pem:/etc/ssl/root-ca.pem:z"
|
|
||||||
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/wazuh.manager.pem:/etc/ssl/filebeat.pem:z"
|
|
||||||
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/wazuh.manager-key.pem:/etc/ssl/filebeat.key:z"
|
|
||||||
- "/opt/apps/wazuh/config/wazuh_cluster/wazuh_manager.conf:/wazuh-config-mount/etc/ossec.conf:z"
|
|
||||||
network:
|
|
||||||
- npm_internal
|
|
||||||
ip: '{{ wazuh_manager_ip }}'
|
|
||||||
|
|
||||||
- name: Deploy Wazuh dashboard
|
|
||||||
containers.podman.podman_container:
|
|
||||||
name: wazuh.dashboard
|
|
||||||
image: "docker.io/wazuh/wazuh-dashboard:{{ wazuh_version }}"
|
|
||||||
hostname: wazuh.dashboard
|
|
||||||
restart_policy: always
|
|
||||||
recreate: true
|
|
||||||
state: started
|
|
||||||
env:
|
|
||||||
INDEXER_USERNAME: "admin"
|
|
||||||
INDEXER_PASSWORD: "*WD*oW9m6iKf4hDovy7BbMmhLxC9D?Tv"
|
|
||||||
WAZUH_API_URL: "https://wazuh.manager"
|
|
||||||
DASHBOARD_USERNAME: "kibanaserver"
|
|
||||||
DASHBOARD_PASSWORD: "kibanaserver"
|
|
||||||
API_USERNAME: "wazuh-wui"
|
|
||||||
API_PASSWORD: "MyS3cr37P450r.*-"
|
|
||||||
volumes:
|
|
||||||
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/wazuh.dashboard.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard.pem:z"
|
|
||||||
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/wazuh.dashboard-key.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard-key.pem:z"
|
|
||||||
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-dashboard/certs/root-ca.pem:z"
|
|
||||||
- "/opt/apps/wazuh/config/wazuh_dashboard/opensearch_dashboards.yml:/usr/share/wazuh-dashboard/config/opensearch_dashboards.yml:z"
|
|
||||||
- "/opt/apps/wazuh/config/wazuh_dashboard/wazuh.yml:/usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml:z"
|
|
||||||
- "wazuh-dashboard-config:/usr/share/wazuh-dashboard/data/wazuh/config"
|
|
||||||
- "wazuh-dashboard-custom:/usr/share/wazuh-dashboard/plugins/wazuh/public/assets/custom"
|
|
||||||
network:
|
|
||||||
- npm_internal
|
|
||||||
ip: '{{ wazuh_dashboard_ip }}'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#----N8N deployment, no GPU avail for deployment ------#
|
#----N8N deployment, no GPU avail for deployment ------#
|
||||||
|
# To enable n8n:
|
||||||
# - name: Deploy n8n
|
# 1. Uncomment the n8n image in vars.yml (images list)
|
||||||
# containers.podman.podman_container:
|
# 2. Uncomment the n8n directory in vars.yml (directories list)
|
||||||
# image: docker.n8n.io/n8nio/n8n
|
# 3. Create roles/n8n/tasks/main.yml with the n8n container block
|
||||||
# name: n8n
|
# 4. Add "n8n" to the roles list above
|
||||||
# env:
|
#
|
||||||
# N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS: true
|
# - name: Deploy n8n
|
||||||
# N8N_RUNNERS_ENABLED: true
|
# containers.podman.podman_container:
|
||||||
# restart_policy: always
|
# image: docker.n8n.io/n8nio/n8n
|
||||||
# recreate: true
|
# name: n8n
|
||||||
# state: started
|
# env:
|
||||||
# volumes:
|
# N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS: true
|
||||||
# - /opt/apps/n8n/data:/home/node/.n8n:z
|
# N8N_RUNNERS_ENABLED: true
|
||||||
# - /opt/apps/n8n/files:/files:z
|
# restart_policy: always
|
||||||
# - /usr/share/zoneinfo/America/Denver:/etc/timezone:ro
|
# recreate: true
|
||||||
# - /etc/localtime:/etc/localtime:ro
|
# state: started
|
||||||
|
# volumes:
|
||||||
# network:
|
# - /opt/apps/n8n/data:/home/node/.n8n:z
|
||||||
# - npm_internal
|
# - /opt/apps/n8n/files:/files:z
|
||||||
# ip: '10.10.0.35'
|
# - /usr/share/zoneinfo/America/Denver:/etc/timezone:ro
|
||||||
# # ports:
|
# - /etc/localtime:/etc/localtime:ro
|
||||||
# # - 5678:5678
|
# network:
|
||||||
|
# - npm_internal
|
||||||
|
# ip: '10.10.0.35'
|
||||||
|
|||||||
14
roles/directories/tasks/main.yml
Normal file
14
roles/directories/tasks/main.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
- name: Create directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop: "{{ directories }}"
|
||||||
|
|
||||||
|
- name: Create Jellyfin directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0777'
|
||||||
|
loop: "{{ directories_jellyfin }}"
|
||||||
20
roles/gitea/tasks/main.yml
Normal file
20
roles/gitea/tasks/main.yml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
- name: Deploy Gitea
|
||||||
|
containers.podman.podman_container:
|
||||||
|
image: docker.gitea.com/gitea:nightly
|
||||||
|
name: gitea
|
||||||
|
env:
|
||||||
|
USER_UID: 1000
|
||||||
|
USER_GID: 1000
|
||||||
|
restart_policy: always
|
||||||
|
recreate: true
|
||||||
|
state: started
|
||||||
|
volumes:
|
||||||
|
- /opt/apps/gitea:/data:z
|
||||||
|
- /usr/share/zoneinfo/America/Denver:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
network:
|
||||||
|
- npm_internal
|
||||||
|
ip: '10.10.0.25'
|
||||||
|
ports:
|
||||||
|
- "222:22"
|
||||||
21
roles/jellyfin/tasks/main.yml
Normal file
21
roles/jellyfin/tasks/main.yml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
- name: Deploy Jellyfin
|
||||||
|
containers.podman.podman_container:
|
||||||
|
image: lscr.io/linuxserver/jellyfin:latest
|
||||||
|
name: jellyfin
|
||||||
|
env:
|
||||||
|
USER_UID: 1000
|
||||||
|
USER_GID: 1000
|
||||||
|
JELLYFIN_PublishedServerUrl: http://jellyfin.boxswapper.io
|
||||||
|
restart_policy: always
|
||||||
|
recreate: true
|
||||||
|
state: started
|
||||||
|
volumes:
|
||||||
|
- /opt/apps/jellyfin/config:/config:z
|
||||||
|
- /opt/apps/jellyfin/tvseries:/data/tvshows:z
|
||||||
|
- /opt/apps/jellyfin/movies:/data/movies:z
|
||||||
|
- /usr/share/zoneinfo/America/Denver:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
network:
|
||||||
|
- npm_internal
|
||||||
|
ip: '10.10.0.30'
|
||||||
8
roles/network/tasks/main.yml
Normal file
8
roles/network/tasks/main.yml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
- name: Create internal podman network
|
||||||
|
containers.podman.podman_network:
|
||||||
|
name: npm_internal
|
||||||
|
ip_range: 10.10.0.128/25
|
||||||
|
subnet: 10.10.0.0/24
|
||||||
|
gateway: 10.10.0.1
|
||||||
|
state: present
|
||||||
18
roles/npm/tasks/main.yml
Normal file
18
roles/npm/tasks/main.yml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
- name: Deploy Nginx Proxy Manager
|
||||||
|
containers.podman.podman_container:
|
||||||
|
image: "docker.io/jc21/nginx-proxy-manager:latest"
|
||||||
|
name: npm
|
||||||
|
restart_policy: always
|
||||||
|
recreate: true
|
||||||
|
state: started
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "81:81"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- "/opt/apps/npm:/data:z"
|
||||||
|
- "/opt/apps/letsencrypt:/etc/letsencrypt:z"
|
||||||
|
network:
|
||||||
|
- npm_internal
|
||||||
|
ip: '10.10.0.19'
|
||||||
13
roles/packages/tasks/main.yml
Normal file
13
roles/packages/tasks/main.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
- name: Update Packages
|
||||||
|
ansible.builtin.dnf:
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: Install Packages
|
||||||
|
ansible.builtin.dnf:
|
||||||
|
name:
|
||||||
|
- vim
|
||||||
|
- podman
|
||||||
|
- fail2ban
|
||||||
|
- python3-libdnf5
|
||||||
|
state: present
|
||||||
23
roles/sysctl/tasks/main.yml
Normal file
23
roles/sysctl/tasks/main.yml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
- name: Enable IP forwarding on host
|
||||||
|
ansible.posix.sysctl:
|
||||||
|
name: net.ipv4.ip_forward
|
||||||
|
value: '1'
|
||||||
|
sysctl_set: true
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Enable source valid mark on host
|
||||||
|
ansible.posix.sysctl:
|
||||||
|
name: net.ipv4.conf.all.src_valid_mark
|
||||||
|
value: '1'
|
||||||
|
sysctl_set: true
|
||||||
|
state: present
|
||||||
|
reload: true
|
||||||
|
|
||||||
|
- name: Raise vm.max_map_count for Wazuh indexer
|
||||||
|
ansible.posix.sysctl:
|
||||||
|
name: vm.max_map_count
|
||||||
|
value: '262144'
|
||||||
|
sysctl_set: true
|
||||||
|
state: present
|
||||||
|
reload: true
|
||||||
157
roles/wazuh/tasks/main.yml
Normal file
157
roles/wazuh/tasks/main.yml
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
---
|
||||||
|
# Wazuh SIEM (single-node: indexer + manager + dashboard) on npm_internal
|
||||||
|
# Dashboard is NOT exposed on host ports — NPM proxies wazuh.boxswapper.io to https://10.10.0.40:5601
|
||||||
|
# DNS record must be grey-cloud (Cloudflare 523 lesson from vpn.boxswapper.io), cert via NPM
|
||||||
|
# Config is copied from ./wazuh-docker/config before first deploy
|
||||||
|
|
||||||
|
- name: Copy Wazuh config files to host
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: ./wazuh-docker/config/
|
||||||
|
dest: /opt/apps/wazuh/config/
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: preserve
|
||||||
|
force: true
|
||||||
|
|
||||||
|
- name: Check for stale Wazuh certificate residue
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /opt/apps/wazuh/config/wazuh_indexer_ssl_certs/root-ca.pem
|
||||||
|
register: wazuh_cert_residue
|
||||||
|
|
||||||
|
- name: Remove stale Wazuh certificate directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /opt/apps/wazuh/config/wazuh_indexer_ssl_certs
|
||||||
|
state: absent
|
||||||
|
when: wazuh_cert_residue.stat.exists and wazuh_cert_residue.stat.isdir
|
||||||
|
|
||||||
|
- name: Recreate Wazuh certificates directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /opt/apps/wazuh/config/wazuh_indexer_ssl_certs
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
|
||||||
|
- name: Generate Wazuh certificates
|
||||||
|
ansible.builtin.command: >
|
||||||
|
podman run --rm
|
||||||
|
-e CERT_TOOL_VERSION=4.14
|
||||||
|
-v /opt/apps/wazuh/config/certs.yml:/config/certs.yml:z
|
||||||
|
-v /opt/apps/wazuh/config/wazuh_indexer_ssl_certs/:/certificates:z
|
||||||
|
docker.io/wazuh/wazuh-certs-generator:0.0.3
|
||||||
|
args:
|
||||||
|
creates: /opt/apps/wazuh/config/wazuh_indexer_ssl_certs/root-ca.pem
|
||||||
|
|
||||||
|
- name: Copy root CA as manager root CA
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: /opt/apps/wazuh/config/wazuh_indexer_ssl_certs/root-ca.pem
|
||||||
|
dest: /opt/apps/wazuh/config/wazuh_indexer_ssl_certs/root-ca-manager.pem
|
||||||
|
remote_src: true
|
||||||
|
force: false
|
||||||
|
|
||||||
|
- name: Deploy Wazuh indexer
|
||||||
|
containers.podman.podman_container:
|
||||||
|
name: wazuh.indexer
|
||||||
|
image: "docker.io/wazuh/wazuh-indexer:{{ wazuh_version }}"
|
||||||
|
hostname: wazuh.indexer
|
||||||
|
restart_policy: always
|
||||||
|
recreate: true
|
||||||
|
state: started
|
||||||
|
env:
|
||||||
|
OPENSEARCH_JAVA_OPTS: "-Xms1g -Xmx1g"
|
||||||
|
ulimit:
|
||||||
|
- "memlock=-1:-1"
|
||||||
|
- "nofile=65536:65536"
|
||||||
|
volumes:
|
||||||
|
- "wazuh-indexer-data:/var/lib/wazuh-indexer"
|
||||||
|
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-indexer/config/certs/root-ca.pem:z"
|
||||||
|
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/wazuh.indexer-key.pem:/usr/share/wazuh-indexer/config/certs/wazuh.indexer.key:z"
|
||||||
|
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/wazuh.indexer.pem:/usr/share/wazuh-indexer/config/certs/wazuh.indexer.pem:z"
|
||||||
|
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/admin.pem:/usr/share/wazuh-indexer/config/certs/admin.pem:z"
|
||||||
|
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/admin-key.pem:/usr/share/wazuh-indexer/config/certs/admin-key.pem:z"
|
||||||
|
- "/opt/apps/wazuh/config/wazuh_indexer/wazuh.indexer.yml:/usr/share/wazuh-indexer/config/opensearch.yml:z"
|
||||||
|
- "/opt/apps/wazuh/config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/config/opensearch-security/internal_users.yml:z"
|
||||||
|
network:
|
||||||
|
- npm_internal
|
||||||
|
ip: '{{ wazuh_indexer_ip }}'
|
||||||
|
|
||||||
|
- name: Wait for Wazuh indexer to be ready
|
||||||
|
ansible.builtin.wait_for:
|
||||||
|
host: '{{ wazuh_indexer_ip }}'
|
||||||
|
port: 9200
|
||||||
|
delay: 10
|
||||||
|
timeout: 300
|
||||||
|
|
||||||
|
- name: Deploy Wazuh manager
|
||||||
|
containers.podman.podman_container:
|
||||||
|
name: wazuh.manager
|
||||||
|
image: "docker.io/wazuh/wazuh-manager:{{ wazuh_version }}"
|
||||||
|
hostname: wazuh.manager
|
||||||
|
restart_policy: always
|
||||||
|
recreate: true
|
||||||
|
state: started
|
||||||
|
env:
|
||||||
|
INDEXER_URL: "https://wazuh.indexer:9200"
|
||||||
|
INDEXER_USERNAME: "admin"
|
||||||
|
INDEXER_PASSWORD: "*WD*oW9m6iKf4hDovy7BbMmhLxC9D?Tv"
|
||||||
|
FILEBEAT_SSL_VERIFICATION_MODE: "full"
|
||||||
|
SSL_CERTIFICATE_AUTHORITIES: "/etc/ssl/root-ca.pem"
|
||||||
|
SSL_CERTIFICATE: "/etc/ssl/filebeat.pem"
|
||||||
|
SSL_KEY: "/etc/ssl/filebeat.key"
|
||||||
|
API_USERNAME: "wazuh-wui"
|
||||||
|
API_PASSWORD: "MyS3cr37P450r.*-"
|
||||||
|
ulimit:
|
||||||
|
- "memlock=-1:-1"
|
||||||
|
- "nofile=655360:655360"
|
||||||
|
ports:
|
||||||
|
- "1514:1514"
|
||||||
|
- "1515:1515"
|
||||||
|
- "514:514/udp"
|
||||||
|
- "55000:55000"
|
||||||
|
volumes:
|
||||||
|
- "wazuh_api_configuration:/var/ossec/api/configuration"
|
||||||
|
- "wazuh_etc:/var/ossec/etc"
|
||||||
|
- "wazuh_logs:/var/ossec/logs"
|
||||||
|
- "wazuh_queue:/var/ossec/queue"
|
||||||
|
- "wazuh_var_multigroups:/var/ossec/var/multigroups"
|
||||||
|
- "wazuh_integrations:/var/ossec/integrations"
|
||||||
|
- "wazuh_agentless:/var/ossec/agentless"
|
||||||
|
- "wazuh_active_response:/var/ossec/active-response/bin"
|
||||||
|
- "wazuh_wodles:/var/ossec/wodles"
|
||||||
|
- "filebeat_etc:/etc/filebeat"
|
||||||
|
- "filebeat_var:/var/lib/filebeat"
|
||||||
|
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/root-ca-manager.pem:/etc/ssl/root-ca.pem:z"
|
||||||
|
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/wazuh.manager.pem:/etc/ssl/filebeat.pem:z"
|
||||||
|
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/wazuh.manager-key.pem:/etc/ssl/filebeat.key:z"
|
||||||
|
- "/opt/apps/wazuh/config/wazuh_cluster/wazuh_manager.conf:/wazuh-config-mount/etc/ossec.conf:z"
|
||||||
|
network:
|
||||||
|
- npm_internal
|
||||||
|
ip: '{{ wazuh_manager_ip }}'
|
||||||
|
|
||||||
|
- name: Deploy Wazuh dashboard
|
||||||
|
containers.podman.podman_container:
|
||||||
|
name: wazuh.dashboard
|
||||||
|
image: "docker.io/wazuh/wazuh-dashboard:{{ wazuh_version }}"
|
||||||
|
hostname: wazuh.dashboard
|
||||||
|
restart_policy: always
|
||||||
|
recreate: true
|
||||||
|
state: started
|
||||||
|
env:
|
||||||
|
INDEXER_USERNAME: "admin"
|
||||||
|
INDEXER_PASSWORD: "*WD*oW9m6iKf4hDovy7BbMmhLxC9D?Tv"
|
||||||
|
WAZUH_API_URL: "https://wazuh.manager"
|
||||||
|
DASHBOARD_USERNAME: "kibanaserver"
|
||||||
|
DASHBOARD_PASSWORD: "kibanaserver"
|
||||||
|
API_USERNAME: "wazuh-wui"
|
||||||
|
API_PASSWORD: "MyS3cr37P450r.*-"
|
||||||
|
volumes:
|
||||||
|
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/wazuh.dashboard.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard.pem:z"
|
||||||
|
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/wazuh.dashboard-key.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard-key.pem:z"
|
||||||
|
- "/opt/apps/wazuh/config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-dashboard/certs/root-ca.pem:z"
|
||||||
|
- "/opt/apps/wazuh/config/wazuh_dashboard/opensearch_dashboards.yml:/usr/share/wazuh-dashboard/config/opensearch_dashboards.yml:z"
|
||||||
|
- "/opt/apps/wazuh/config/wazuh_dashboard/wazuh.yml:/usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml:z"
|
||||||
|
- "wazuh-dashboard-config:/usr/share/wazuh-dashboard/data/wazuh/config"
|
||||||
|
- "wazuh-dashboard-custom:/usr/share/wazuh-dashboard/plugins/wazuh/public/assets/custom"
|
||||||
|
network:
|
||||||
|
- npm_internal
|
||||||
|
ip: '{{ wazuh_dashboard_ip }}'
|
||||||
89
roles/wireguard/tasks/main.yml
Normal file
89
roles/wireguard/tasks/main.yml
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure WireGuard kernel module is loaded
|
||||||
|
ansible.builtin.modprobe:
|
||||||
|
name: wireguard
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Persist WireGuard kernel module across reboots
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/modules-load.d/wg-easy.conf
|
||||||
|
content: |
|
||||||
|
wireguard
|
||||||
|
nft_masq
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
# WireGuard Easy VPN (v15) — UI at 10.10.0.36:51821 on npm_internal, fronted by NPM
|
||||||
|
# (vpn.boxswapper.io -> http://10.10.0.36:51821). Login: admin / wireguard_ui_password from vars.yml.
|
||||||
|
# v15 init is ONE-TIME: the INIT_* envs below are consumed only when /etc/wireguard/wg-easy.db is ABSENT.
|
||||||
|
# Force a re-init (wipes clients + server keys): podman rm -f wg-easy && rm -rf /opt/apps/wireguard, then re-run.
|
||||||
|
# NAT from VPN clients to LAN/apps (10.10.1.0/24 -> 10.10.0.0/24) uses NFTABLES hooks —
|
||||||
|
# wg-easy's iptables-legacy hooks cannot init the nat table inside a podman netns
|
||||||
|
# ("Table does not exist"), which makes wg-quick up fail and every client API call
|
||||||
|
# 500 with "Unable to access interface". scripts/patch-wg-hooks.py rewrites the hooks
|
||||||
|
# to nft rules and the tasks below restart wg-easy to apply them. See the official
|
||||||
|
# wg-easy "Podman + nftables" tutorial.
|
||||||
|
# EXTERNAL ACCESS: router MUST forward UDP 51820 -> 192.168.0.98. Test from LTE,
|
||||||
|
# not your LAN — NAT hairpin breaks public-IP handshakes from inside the network.
|
||||||
|
- name: Deploy WireGuard Easy (wg-easy)
|
||||||
|
containers.podman.podman_container:
|
||||||
|
name: wg-easy
|
||||||
|
image: "{{ wireguard_image }}"
|
||||||
|
restart_policy: always
|
||||||
|
recreate: true
|
||||||
|
state: started
|
||||||
|
env:
|
||||||
|
INIT_ENABLED: "true"
|
||||||
|
INIT_USERNAME: "{{ wireguard_ui_username }}"
|
||||||
|
INIT_PASSWORD: "{{ wireguard_ui_password }}"
|
||||||
|
INIT_HOST: "{{ wireguard_host }}"
|
||||||
|
INIT_PORT: "{{ wireguard_port }}"
|
||||||
|
INIT_DNS: "{{ wireguard_default_dns }}"
|
||||||
|
INIT_IPV4_CIDR: "{{ wireguard_cidr }}"
|
||||||
|
INIT_IPV6_CIDR: "{{ wireguard_ipv6_cidr }}"
|
||||||
|
INIT_ALLOWED_IPS: "{{ wireguard_allowed_ips }}"
|
||||||
|
PORT: "{{ wireguard_ui_port }}"
|
||||||
|
INSECURE: "true"
|
||||||
|
DISABLE_VERSION_CHECK: "true"
|
||||||
|
ports:
|
||||||
|
- "{{ wireguard_port }}:{{ wireguard_port }}/udp"
|
||||||
|
- "{{ wireguard_ui_port }}:{{ wireguard_ui_port }}/tcp"
|
||||||
|
volumes:
|
||||||
|
- "/opt/apps/wireguard:/etc/wireguard:z"
|
||||||
|
- "/lib/modules:/lib/modules:ro"
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
- SYS_MODULE
|
||||||
|
- NET_RAW
|
||||||
|
sysctl:
|
||||||
|
net.ipv4.ip_forward: "1"
|
||||||
|
net.ipv4.conf.all.src_valid_mark: "1"
|
||||||
|
net.ipv6.conf.all.disable_ipv6: "0"
|
||||||
|
net.ipv6.conf.all.forwarding: "1"
|
||||||
|
net.ipv6.conf.default.forwarding: "1"
|
||||||
|
network:
|
||||||
|
- npm_internal
|
||||||
|
ip: '{{ wireguard_ip }}'
|
||||||
|
|
||||||
|
- name: Copy wg-easy hook repair script
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: ./scripts/patch-wg-hooks.py
|
||||||
|
dest: /opt/apps/wireguard/patch-wg-hooks.py
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Replace iptables hooks with nftables (iptables-legacy broken in podman)
|
||||||
|
ansible.builtin.command: python3 /opt/apps/wireguard/patch-wg-hooks.py
|
||||||
|
register: wg_hooks_patch
|
||||||
|
changed_when: "'patched hooks' in wg_hooks_patch.stdout"
|
||||||
|
|
||||||
|
- name: Restart wg-easy to apply nft hooks
|
||||||
|
ansible.builtin.command: podman restart wg-easy
|
||||||
|
when: "'patched hooks' in wg_hooks_patch.stdout"
|
||||||
|
|
||||||
|
- name: Wait for WireGuard Easy web UI
|
||||||
|
ansible.builtin.wait_for:
|
||||||
|
host: '{{ wireguard_ip }}'
|
||||||
|
port: '{{ wireguard_ui_port }}'
|
||||||
|
delay: 5
|
||||||
|
timeout: 120
|
||||||
Reference in New Issue
Block a user