--- # WireGuard server and client configuration - name: Detect primary network interface shell: ip route get 1.1.1.1 | awk '{for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}' register: primary_interface changed_when: false - name: Set computed vars set_fact: _iface: "{{ primary_interface.stdout | trim }}" _subnet_base: "{{ wg_subnet.split('.')[0:3] | join('.') }}" - name: Generate client keys shell: | mkdir -p /etc/wireguard/clients for i in $(seq 1 {{ wg_clients }}); do if [ ! -f /etc/wireguard/clients/client${i}_private.key ]; then wg genkey | tee /etc/wireguard/clients/client${i}_private.key | wg pubkey > /etc/wireguard/clients/client${i}_public.key wg genpsk > /etc/wireguard/clients/client${i}_psk.key chmod 600 /etc/wireguard/clients/client${i}_*.key fi done args: creates: /etc/wireguard/clients/client1_private.key - name: Ensure ip6tables nat module is available modprobe: name: ip6table_nat state: present ignore_errors: true - name: Build WireGuard server config shell: | SERVER_PRIVKEY=$(cat /etc/wireguard/server_private.key) # Header + PrivateKey (needs shell expansion) echo "[Interface]" > /etc/wireguard/wg0.conf echo "Address = {{ _subnet_base }}.1/24" >> /etc/wireguard/wg0.conf echo "ListenPort = {{ wg_port }}" >> /etc/wireguard/wg0.conf echo "PrivateKey = ${SERVER_PRIVKEY}" >> /etc/wireguard/wg0.conf echo "SaveConfig = false" >> /etc/wireguard/wg0.conf # PostUp/PostDown rules (Jinja2 vars, no shell expansion needed) cat >> /etc/wireguard/wg0.conf << 'RULESEOF' PostUp = iptables -A FORWARD -i wg0 -o {{ _iface }} -j ACCEPT PostUp = iptables -A FORWARD -i {{ _iface }} -o wg0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT PostUp = iptables -t nat -A POSTROUTING -o {{ _iface }} -s {{ wg_subnet }} -j MASQUERADE PostUp = ip6tables -A FORWARD -i wg0 -o {{ _iface }} -j ACCEPT || true PostUp = ip6tables -A FORWARD -i {{ _iface }} -o wg0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT || true PostUp = ip6tables -t nat -A POSTROUTING -o {{ _iface }} -j MASQUERADE || true PostUp = iptables -I INPUT -i wg0 -p tcp --dport 22 -j DROP PostUp = iptables -I INPUT -i wg0 -p tcp --dport 80 -j DROP PostUp = iptables -I INPUT -i wg0 -p tcp --dport 443 -j DROP PostDown = iptables -D FORWARD -i wg0 -o {{ _iface }} -j ACCEPT PostDown = iptables -D FORWARD -i {{ _iface }} -o wg0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT PostDown = iptables -t nat -D POSTROUTING -o {{ _iface }} -s {{ wg_subnet }} -j MASQUERADE PostDown = ip6tables -D FORWARD -i wg0 -o {{ _iface }} -j ACCEPT || true PostDown = ip6tables -D FORWARD -i {{ _iface }} -o wg0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT || true PostDown = ip6tables -t nat -D POSTROUTING -o {{ _iface }} -j MASQUERADE || true PostDown = iptables -D INPUT -i wg0 -p tcp --dport 22 -j DROP PostDown = iptables -D INPUT -i wg0 -p tcp --dport 80 -j DROP PostDown = iptables -D INPUT -i wg0 -p tcp --dport 443 -j DROP RULESEOF # Peers for i in $(seq 1 {{ wg_clients }}); do CLIENT_PUBKEY=$(cat /etc/wireguard/clients/client${i}_public.key) CLIENT_PSK=$(cat /etc/wireguard/clients/client${i}_psk.key) echo "" >> /etc/wireguard/wg0.conf echo "[Peer]" >> /etc/wireguard/wg0.conf echo "PublicKey = ${CLIENT_PUBKEY}" >> /etc/wireguard/wg0.conf echo "PresharedKey = ${CLIENT_PSK}" >> /etc/wireguard/wg0.conf echo "AllowedIPs = {{ _subnet_base }}.$(( i + 1 ))/32" >> /etc/wireguard/wg0.conf done chmod 600 /etc/wireguard/wg0.conf args: creates: /etc/wireguard/wg0.conf - name: Verify WireGuard config shell: cat /etc/wireguard/wg0.conf register: wg_config_check changed_when: false - name: Show generated config (debug) debug: var: wg_config_check.stdout_lines - name: Generate client config files shell: | SERVER_PUBKEY=$(echo '{{ server_privkey_content.content | b64decode | trim }}' | wg pubkey) SERVER_ENDPOINT="{{ target_host }}:{{ wg_port }}" for i in $(seq 1 {{ wg_clients }}); do CLIENT_PRIVKEY=$(cat /etc/wireguard/clients/client${i}_private.key) CLIENT_PSK=$(cat /etc/wireguard/clients/client${i}_psk.key) CLIENT_IP="{{ _subnet_base }}.$(( i + 1 ))" cat > /etc/wireguard/clients/client${i}.conf << CLIENTEOF [Interface] PrivateKey = ${CLIENT_PRIVKEY} Address = ${CLIENT_IP}/32 DNS = {{ wg_dns }} [Peer] PublicKey = ${SERVER_PUBKEY} PresharedKey = ${CLIENT_PSK} Endpoint = ${SERVER_ENDPOINT} AllowedIPs = {{ wg_allowed_ips }} PersistentKeepalive = 25 CLIENTEOF qrencode -t ansiutf8 < /etc/wireguard/clients/client${i}.conf > /etc/wireguard/clients/client${i}_qr.txt 2>/dev/null || true done args: creates: /etc/wireguard/clients/client1.conf - name: Create WireGuard systemd override directory file: path: /etc/systemd/system/wg-quick@wg0.service.d state: directory mode: "0755" - name: Deploy WireGuard systemd hardening override copy: dest: /etc/systemd/system/wg-quick@wg0.service.d/hardening.conf content: | [Service] ProtectHome=true ProtectClock=true ProtectHostname=true ProtectKernelLogs=true PrivateTmp=true mode: "0644" - name: Reload systemd daemon systemd: daemon_reload: true - name: Enable and start WireGuard systemd: name: wg-quick@wg0 state: started enabled: true