d4b7c356dc
- wg-quick runs under set -e; any non-zero exit kills the service - 2>/dev/null only hides stderr, doesn't change exit code — need || true - Split PostUp back to multiple lines (one command per line, cleaner) - Use Jinja2 vars instead of shell heredoc for interface/subnet values (quoted heredoc 'CONFEOF' prevents shell expansion issues, PrivateKey written separately via echo since it needs shell expansion) - Use -m conntrack --ctstate instead of deprecated -m state --state - Add config dump debug task to capture generated config on failure - Separate heredoc markers (CONFEOF/CLIENTEOF) to avoid conflicts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
119 lines
4.8 KiB
YAML
119 lines
4.8 KiB
YAML
---
|
|
# 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: Ensure ip6tables nat module is available
|
|
modprobe:
|
|
name: ip6table_nat
|
|
state: present
|
|
ignore_errors: true
|
|
|
|
- name: Build WireGuard server config
|
|
vars:
|
|
_iface: "{{ primary_interface.stdout | trim }}"
|
|
_addr: "{{ wg_subnet | regex_replace('/\\d+$', '') | regex_replace('\\.[0-9]+$', '.1/24') }}"
|
|
shell: |
|
|
SERVER_PRIVKEY=$(cat /etc/wireguard/server_private.key)
|
|
cat > /etc/wireguard/wg0.conf << 'CONFEOF'
|
|
[Interface]
|
|
Address = {{ _addr }}
|
|
ListenPort = {{ wg_port }}
|
|
SaveConfig = false
|
|
CONFEOF
|
|
echo "PrivateKey = ${SERVER_PRIVKEY}" >> /etc/wireguard/wg0.conf
|
|
cat >> /etc/wireguard/wg0.conf << 'CONFEOF'
|
|
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
|
|
CONFEOF
|
|
|
|
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 = {{ wg_subnet | regex_replace('/\\d+$', '') | regex_replace('\\.[0-9]+$', '') }}.$(( 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="{{ wg_subnet | regex_replace('/\\d+$', '') | regex_replace('\\.[0-9]+$', '') }}.$(( 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: Enable and start WireGuard
|
|
systemd:
|
|
name: wg-quick@wg0
|
|
state: started
|
|
enabled: true
|