--- # 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: 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: Build WireGuard server config shell: | SERVER_PRIVKEY=$(cat /etc/wireguard/server_private.key) IFACE={{ primary_interface.stdout | trim }} cat > /etc/wireguard/wg0.conf << 'WGEOF' [Interface] WGEOF # Write dynamic values separately to avoid heredoc variable issues cat >> /etc/wireguard/wg0.conf << EOF Address = {{ wg_subnet | regex_replace('/\\d+$', '') | regex_replace('\\.[0-9]+$', '.1/24') }} ListenPort = {{ wg_port }} PrivateKey = ${SERVER_PRIVKEY} SaveConfig = false # IPv4: forward VPN traffic to internet, masquerade source PostUp = iptables -A FORWARD -i wg0 -o ${IFACE} -j ACCEPT PostUp = iptables -A FORWARD -i ${IFACE} -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT PostUp = iptables -t nat -A POSTROUTING -o ${IFACE} -s {{ wg_subnet }} -j MASQUERADE # IPv6: same rules to prevent leaks PostUp = ip6tables -A FORWARD -i wg0 -o ${IFACE} -j ACCEPT PostUp = ip6tables -A FORWARD -i ${IFACE} -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT PostUp = ip6tables -t nat -A POSTROUTING -o ${IFACE} -j MASQUERADE # Block VPN clients from accessing server-local services (except DNS if local) 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 state --state 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 PostDown = ip6tables -D FORWARD -i ${IFACE} -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT PostDown = ip6tables -t nat -D POSTROUTING -o ${IFACE} -j MASQUERADE 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 EOF 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) cat >> /etc/wireguard/wg0.conf << EOF [Peer] # Client ${i} PublicKey = ${CLIENT_PUBKEY} PresharedKey = ${CLIENT_PSK} AllowedIPs = {{ wg_subnet | regex_replace('/\\d+$', '') | regex_replace('\\.[0-9]+$', '') }}.$(( i + 1 ))/32 EOF done chmod 600 /etc/wireguard/wg0.conf args: creates: /etc/wireguard/wg0.conf - 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="{{ wg_subnet | regex_replace('/\\d+$', '') | regex_replace('\\.[0-9]+$', '') }}.$(( i + 1 ))" cat > /etc/wireguard/clients/client${i}.conf << EOF [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 EOF # Generate QR code 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: Enable and start WireGuard systemd: name: wg-quick@wg0 state: started enabled: true