refactor(deployment): Remove WireGuard VPN dependency and restore public service access
Remove WireGuard integration from production deployment to simplify infrastructure: - Remove docker-compose-direct-access.yml (VPN-bound services) - Remove VPN-only middlewares from Grafana, Prometheus, Portainer - Remove WireGuard middleware definitions from Traefik - Remove WireGuard IPs (10.8.0.0/24) from Traefik forwarded headers All monitoring services now publicly accessible via subdomains: - grafana.michaelschiemer.de (with Grafana native auth) - prometheus.michaelschiemer.de (with Basic Auth) - portainer.michaelschiemer.de (with Portainer native auth) All services use Let's Encrypt SSL certificates via Traefik.
This commit is contained in:
@@ -179,6 +179,141 @@ sudo ufw allow 51820/udp comment 'WireGuard VPN'
|
||||
sudo iptables -A INPUT -p udp --dport 51820 -j ACCEPT
|
||||
```
|
||||
|
||||
## Split-Tunnel Routing & NAT Fix
|
||||
|
||||
### A. Quick Fix Commands (manuell auf dem Server)
|
||||
```bash
|
||||
WAN_IF=${WAN_IF:-eth0}
|
||||
WG_IF=${WG_IF:-wg0}
|
||||
WG_NET=${WG_NET:-10.8.0.0/24}
|
||||
WG_PORT=${WG_PORT:-51820}
|
||||
EXTRA_NETS=${EXTRA_NETS:-"192.168.178.0/24 172.20.0.0/16"}
|
||||
|
||||
sudo sysctl -w net.ipv4.ip_forward=1
|
||||
sudo tee /etc/sysctl.d/99-${WG_IF}-forward.conf >/dev/null <<'EOF'
|
||||
# WireGuard Forwarding
|
||||
net.ipv4.ip_forward=1
|
||||
EOF
|
||||
sudo sysctl --system
|
||||
|
||||
# iptables Variante
|
||||
sudo iptables -t nat -C POSTROUTING -s ${WG_NET} -o ${WAN_IF} -j MASQUERADE 2>/dev/null \
|
||||
|| sudo iptables -t nat -A POSTROUTING -s ${WG_NET} -o ${WAN_IF} -j MASQUERADE
|
||||
sudo iptables -C FORWARD -i ${WG_IF} -s ${WG_NET} -o ${WAN_IF} -j ACCEPT 2>/dev/null \
|
||||
|| sudo iptables -A FORWARD -i ${WG_IF} -s ${WG_NET} -o ${WAN_IF} -j ACCEPT
|
||||
sudo iptables -C FORWARD -o ${WG_IF} -d ${WG_NET} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null \
|
||||
|| sudo iptables -A FORWARD -o ${WG_IF} -d ${WG_NET} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||
for NET in ${EXTRA_NETS}; do
|
||||
sudo iptables -C FORWARD -i ${WG_IF} -d ${NET} -j ACCEPT 2>/dev/null || sudo iptables -A FORWARD -i ${WG_IF} -d ${NET} -j ACCEPT
|
||||
done
|
||||
|
||||
# nftables Variante
|
||||
sudo nft list table inet wireguard_${WG_IF} >/dev/null 2>&1 || sudo nft add table inet wireguard_${WG_IF}
|
||||
sudo nft list chain inet wireguard_${WG_IF} postrouting >/dev/null 2>&1 \
|
||||
|| sudo nft add chain inet wireguard_${WG_IF} postrouting '{ type nat hook postrouting priority srcnat; }'
|
||||
sudo nft list chain inet wireguard_${WG_IF} forward >/dev/null 2>&1 \
|
||||
|| sudo nft add chain inet wireguard_${WG_IF} forward '{ type filter hook forward priority filter; policy accept; }'
|
||||
sudo nft list chain inet wireguard_${WG_IF} postrouting | grep -q "${WAN_IF}" \
|
||||
|| sudo nft add rule inet wireguard_${WG_IF} postrouting oifname "${WAN_IF}" ip saddr ${WG_NET} masquerade
|
||||
sudo nft list chain inet wireguard_${WG_IF} forward | grep -q "iifname \"${WG_IF}\"" \
|
||||
|| sudo nft add rule inet wireguard_${WG_IF} forward iifname "${WG_IF}" ip saddr ${WG_NET} counter accept
|
||||
sudo nft list chain inet wireguard_${WG_IF} forward | grep -q "oifname \"${WG_IF}\"" \
|
||||
|| sudo nft add rule inet wireguard_${WG_IF} forward oifname "${WG_IF}" ip daddr ${WG_NET} ct state established,related counter accept
|
||||
for NET in ${EXTRA_NETS}; do
|
||||
sudo nft list chain inet wireguard_${WG_IF} forward | grep -q "${NET}" \
|
||||
|| sudo nft add rule inet wireguard_${WG_IF} forward iifname "${WG_IF}" ip daddr ${NET} counter accept
|
||||
done
|
||||
|
||||
# Firewall Hooks
|
||||
if command -v ufw >/dev/null && sudo ufw status | grep -iq "Status: active"; then
|
||||
sudo sed -i 's/^DEFAULT_FORWARD_POLICY=.*/DEFAULT_FORWARD_POLICY="ACCEPT"/' /etc/default/ufw
|
||||
sudo ufw allow ${WG_PORT}/udp
|
||||
sudo ufw route allow in on ${WG_IF} out on ${WAN_IF} to any
|
||||
fi
|
||||
if command -v firewall-cmd >/dev/null && sudo firewall-cmd --state >/dev/null 2>&1; then
|
||||
sudo firewall-cmd --permanent --zone=${FIREWALLD_ZONE:-public} --add-port=${WG_PORT}/udp
|
||||
sudo firewall-cmd --permanent --zone=${FIREWALLD_ZONE:-public} --add-masquerade
|
||||
sudo firewall-cmd --reload
|
||||
fi
|
||||
|
||||
sudo systemctl enable --now wg-quick@${WG_IF}
|
||||
sudo wg show
|
||||
```
|
||||
|
||||
### B. Skript: `deployment/ansible/scripts/setup-wireguard-routing.sh`
|
||||
```bash
|
||||
cd deployment/ansible
|
||||
sudo WAN_IF=eth0 WG_IF=wg0 WG_NET=10.8.0.0/24 EXTRA_NETS="192.168.178.0/24 172.20.0.0/16" \
|
||||
./scripts/setup-wireguard-routing.sh
|
||||
```
|
||||
*Erkennt automatisch iptables/nftables und konfiguriert optional UFW/Firewalld.*
|
||||
|
||||
### C. Ansible Playbook: `playbooks/wireguard-routing.yml`
|
||||
```bash
|
||||
cd deployment/ansible
|
||||
ansible-playbook -i inventory/production.yml playbooks/wireguard-routing.yml \
|
||||
-e "wg_interface=wg0 wg_addr=10.8.0.1/24 wg_net=10.8.0.0/24 wan_interface=eth0" \
|
||||
-e '{"extra_nets":["192.168.178.0/24","172.20.0.0/16"],"firewall_backend":"iptables","manage_ufw":true}'
|
||||
```
|
||||
*Variablen:* `wg_interface`, `wg_addr`, `wg_net`, `wan_interface`, `extra_nets`, `firewall_backend` (`iptables|nftables`), `manage_ufw`, `manage_firewalld`, `firewalld_zone`.
|
||||
|
||||
### D. Beispiel `wg0.conf` Ausschnitt
|
||||
```ini
|
||||
[Interface]
|
||||
Address = 10.8.0.1/24
|
||||
ListenPort = 51820
|
||||
PrivateKey = <ServerPrivateKey>
|
||||
|
||||
# iptables
|
||||
PostUp = iptables -t nat -C POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE 2>/dev/null || iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
|
||||
PostUp = iptables -C FORWARD -i wg0 -s 10.8.0.0/24 -j ACCEPT 2>/dev/null || iptables -A FORWARD -i wg0 -s 10.8.0.0/24 -j ACCEPT
|
||||
PostUp = iptables -C FORWARD -o wg0 -d 10.8.0.0/24 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || iptables -A FORWARD -o wg0 -d 10.8.0.0/24 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||
PostDown = iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE 2>/dev/null || true
|
||||
PostDown = iptables -D FORWARD -i wg0 -s 10.8.0.0/24 -j ACCEPT 2>/dev/null || true
|
||||
PostDown = iptables -D FORWARD -o wg0 -d 10.8.0.0/24 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true
|
||||
|
||||
# nftables (stattdessen)
|
||||
# PostUp = nft -f /etc/nftables.d/wireguard-wg0.nft
|
||||
# PostDown = nft delete table inet wireguard_wg0 2>/dev/null || true
|
||||
|
||||
[Peer]
|
||||
PublicKey = <ClientPublicKey>
|
||||
AllowedIPs = 10.8.0.5/32, 192.168.178.0/24, 172.20.0.0/16
|
||||
PersistentKeepalive = 25
|
||||
```
|
||||
|
||||
### E. Windows Client (AllowedIPs & Tests)
|
||||
```ini
|
||||
[Interface]
|
||||
Address = 10.8.0.5/32
|
||||
DNS = 10.8.0.1 # optional
|
||||
|
||||
[Peer]
|
||||
PublicKey = <ServerPublicKey>
|
||||
Endpoint = vpn.example.com:51820
|
||||
AllowedIPs = 10.8.0.0/24, 192.168.178.0/24, 172.20.0.0/16
|
||||
PersistentKeepalive = 25
|
||||
```
|
||||
PowerShell:
|
||||
```powershell
|
||||
wg show
|
||||
Test-Connection -Source 10.8.0.5 -ComputerName 10.8.0.1
|
||||
Test-Connection 192.168.178.1
|
||||
Test-NetConnection -ComputerName 192.168.178.10 -Port 22
|
||||
```
|
||||
Optional: `Set-DnsClientNrptRule -Namespace "internal.lan" -NameServers 10.8.0.1`.
|
||||
|
||||
### F. Troubleshooting & Rollback
|
||||
- Checks: `ip r`, `ip route get <target>`, `iptables -t nat -S`, `nft list ruleset`, `sysctl net.ipv4.ip_forward`, `wg show`, `tcpdump -i wg0`, `tcpdump -i eth0 host 10.8.0.5`.
|
||||
- Häufige Fehler: falsches WAN-Interface, Forwarding/NAT fehlt, doppelte Firewalls (iptables + nftables), Docker-NAT kollidiert, Policy-Routing aktiv.
|
||||
- Rollback:
|
||||
- `sudo rm /etc/sysctl.d/99-wg0-forward.conf && sudo sysctl -w net.ipv4.ip_forward=0`
|
||||
- iptables: Regeln mit `iptables -D` entfernen (siehe oben).
|
||||
- nftables: `sudo nft delete table inet wireguard_wg0`.
|
||||
- UFW: `sudo ufw delete allow 51820/udp`, Route-Regeln entfernen, `DEFAULT_FORWARD_POLICY` zurücksetzen.
|
||||
- Firewalld: `firewall-cmd --permanent --remove-port=51820/udp`, `--remove-masquerade`, `--reload`.
|
||||
- Dienst: `sudo systemctl disable --now wg-quick@wg0`.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### WireGuard startet nicht
|
||||
@@ -281,4 +416,4 @@ Bei Problemen:
|
||||
1. Prüfe Logs: `sudo journalctl -u wg-quick@wg0`
|
||||
2. Prüfe Status: `sudo wg show`
|
||||
3. Prüfe Firewall: `sudo ufw status`
|
||||
4. Teste Connectivity: `ping 10.8.0.1` (vom Client)
|
||||
4. Teste Connectivity: `ping 10.8.0.1` (vom Client)
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
---
|
||||
- name: Add WireGuard Client
|
||||
hosts: production
|
||||
become: yes
|
||||
gather_facts: yes
|
||||
|
||||
vars:
|
||||
wireguard_interface: "wg0"
|
||||
wireguard_config_path: "/etc/wireguard"
|
||||
wireguard_config_file: "{{ wireguard_config_path }}/{{ wireguard_interface }}.conf"
|
||||
wireguard_client_configs_path: "/etc/wireguard/clients"
|
||||
wireguard_local_client_configs_dir: "{{ playbook_dir }}/../wireguard-clients"
|
||||
wireguard_dns_servers: []
|
||||
|
||||
pre_tasks:
|
||||
- name: Set WireGuard network
|
||||
set_fact:
|
||||
wireguard_network: "{{ wireguard_network | default('10.8.0.0/24') }}"
|
||||
|
||||
- name: Set WireGuard other variables with defaults
|
||||
set_fact:
|
||||
wireguard_port: "{{ wireguard_port | default(51820) }}"
|
||||
client_ip: "{{ client_ip | default('') }}"
|
||||
# IMPORTANT: Default to VPN network only (not 0.0.0.0/0)
|
||||
# This ensures SSH access via normal IP remains available
|
||||
allowed_ips: "{{ allowed_ips | default(wireguard_network) }}"
|
||||
|
||||
tasks:
|
||||
- name: Validate client name
|
||||
fail:
|
||||
msg: "client_name is required. Usage: ansible-playbook ... -e 'client_name=myclient'"
|
||||
when: client_name is not defined or client_name == ""
|
||||
|
||||
- name: Get server external IP address
|
||||
uri:
|
||||
url: https://api.ipify.org
|
||||
return_content: yes
|
||||
register: server_external_ip
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Set server external IP
|
||||
set_fact:
|
||||
server_external_ip_content: "{{ ansible_host | default(server_external_ip.content | default('')) }}"
|
||||
|
||||
- name: Check if WireGuard config exists
|
||||
stat:
|
||||
path: "{{ wireguard_config_file }}"
|
||||
register: wireguard_config_exists
|
||||
|
||||
- name: Fail if WireGuard not configured
|
||||
fail:
|
||||
msg: "WireGuard server not configured. Please run setup-wireguard.yml first."
|
||||
when: not wireguard_config_exists.stat.exists
|
||||
|
||||
- name: Read WireGuard server config
|
||||
slurp:
|
||||
src: "{{ wireguard_config_file }}"
|
||||
register: wireguard_server_config_read
|
||||
|
||||
- name: Extract server IP from config
|
||||
set_fact:
|
||||
server_vpn_ip: "{{ (wireguard_server_config_read.content | b64decode | regex_search('Address = ([0-9.]+)', '\\1')) | first | default('10.8.0.1') }}"
|
||||
|
||||
- name: Extract WireGuard server IP octets
|
||||
set_fact:
|
||||
wireguard_server_ip_octets: "{{ server_vpn_ip.split('.') }}"
|
||||
when: client_ip == ""
|
||||
|
||||
- name: Gather existing client addresses
|
||||
set_fact:
|
||||
existing_client_ips: "{{ (wireguard_server_config_read.content | b64decode | regex_findall('AllowedIPs = ([0-9A-Za-z.]+)/32', '\\1')) }}"
|
||||
when: client_ip == ""
|
||||
|
||||
- name: Calculate client IP if not provided
|
||||
vars:
|
||||
existing_last_octets: "{{ (existing_client_ips | default([])) | map('regex_replace', '^(?:\\d+\\.\\d+\\.\\d+\\.)', '') | select('match', '^[0-9]+$') | map('int') | list }}"
|
||||
server_last_octet: "{{ wireguard_server_ip_octets[3] | int }}"
|
||||
next_octet_candidate: "{{ (existing_last_octets + [server_last_octet]) | map('int') | list | max + 1 if (existing_last_octets + [server_last_octet]) else server_last_octet + 1 }}"
|
||||
set_fact:
|
||||
client_ip: "{{ [
|
||||
wireguard_server_ip_octets[0],
|
||||
wireguard_server_ip_octets[1],
|
||||
wireguard_server_ip_octets[2],
|
||||
next_octet_candidate
|
||||
] | join('.') }}"
|
||||
when: client_ip == ""
|
||||
|
||||
- name: Generate client private key
|
||||
command: "wg genkey"
|
||||
register: client_private_key
|
||||
changed_when: true
|
||||
no_log: yes
|
||||
|
||||
- name: Generate client public key
|
||||
command: "wg pubkey"
|
||||
args:
|
||||
stdin: "{{ client_private_key.stdout }}"
|
||||
register: client_public_key
|
||||
changed_when: false
|
||||
no_log: yes
|
||||
|
||||
- name: Add client to WireGuard server config
|
||||
blockinfile:
|
||||
path: "{{ wireguard_config_file }}"
|
||||
block: |
|
||||
# Client: {{ client_name }}
|
||||
[Peer]
|
||||
PublicKey = {{ client_public_key.stdout }}
|
||||
AllowedIPs = {{ client_ip }}/32
|
||||
marker: "# {mark} ANSIBLE MANAGED BLOCK - Client: {{ client_name }}"
|
||||
register: wireguard_client_block
|
||||
|
||||
- name: Ensure client configs directory exists
|
||||
file:
|
||||
path: "{{ wireguard_client_configs_path }}"
|
||||
state: directory
|
||||
mode: '0700'
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: Ensure local client configs directory exists
|
||||
file:
|
||||
path: "{{ wireguard_local_client_configs_dir }}"
|
||||
state: directory
|
||||
mode: '0700'
|
||||
delegate_to: localhost
|
||||
become: no
|
||||
run_once: true
|
||||
|
||||
- name: Get server public key
|
||||
shell: "cat {{ wireguard_config_path }}/{{ wireguard_interface }}_private.key | wg pubkey"
|
||||
register: server_public_key_cmd
|
||||
changed_when: false
|
||||
no_log: yes
|
||||
failed_when: false
|
||||
|
||||
- name: Create client configuration file
|
||||
template:
|
||||
src: "{{ playbook_dir }}/../templates/wireguard-client.conf.j2"
|
||||
dest: "{{ wireguard_client_configs_path }}/{{ client_name }}.conf"
|
||||
mode: '0600'
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: Download client configuration to control machine
|
||||
fetch:
|
||||
src: "{{ wireguard_client_configs_path }}/{{ client_name }}.conf"
|
||||
dest: "{{ wireguard_local_client_configs_dir }}/{{ client_name }}.conf"
|
||||
flat: yes
|
||||
mode: '0600'
|
||||
|
||||
- name: Ensure local client configuration has strict permissions
|
||||
file:
|
||||
path: "{{ wireguard_local_client_configs_dir }}/{{ client_name }}.conf"
|
||||
mode: '0600'
|
||||
delegate_to: localhost
|
||||
become: no
|
||||
|
||||
- name: Read WireGuard server config to find server IP
|
||||
slurp:
|
||||
src: "{{ wireguard_config_file }}"
|
||||
register: wireguard_server_config_read
|
||||
|
||||
- name: Restart WireGuard service
|
||||
systemd:
|
||||
name: "wg-quick@{{ wireguard_interface }}"
|
||||
state: restarted
|
||||
when: wireguard_client_block.changed
|
||||
|
||||
- name: Display client configuration
|
||||
debug:
|
||||
msg: |
|
||||
========================================
|
||||
WireGuard Client Added: {{ client_name }}
|
||||
========================================
|
||||
|
||||
Client Configuration File:
|
||||
{{ wireguard_client_configs_path }}/{{ client_name }}.conf
|
||||
|
||||
Local Copy:
|
||||
{{ wireguard_local_client_configs_dir }}/{{ client_name }}.conf
|
||||
|
||||
Client IP: {{ client_ip }}
|
||||
Server Endpoint: {{ server_external_ip_content }}:{{ wireguard_port }}
|
||||
|
||||
To use this configuration:
|
||||
1. Copy the config file to your client machine
|
||||
2. Install WireGuard client
|
||||
3. Run: sudo wg-quick up {{ client_name }}
|
||||
|
||||
Or scan the QR code (if qrencode installed):
|
||||
qrencode -t ansiutf8 < {{ wireguard_client_configs_path }}/{{ client_name }}.conf
|
||||
========================================
|
||||
|
||||
- name: Generate QR code for client config
|
||||
command: "qrencode -t ansiutf8 -r {{ wireguard_client_configs_path }}/{{ client_name }}.conf"
|
||||
register: qr_code
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Display QR code
|
||||
debug:
|
||||
msg: "{{ qr_code.stdout }}"
|
||||
when: qr_code.rc == 0
|
||||
229
deployment/ansible/playbooks/generate-wireguard-client.yml
Normal file
229
deployment/ansible/playbooks/generate-wireguard-client.yml
Normal file
@@ -0,0 +1,229 @@
|
||||
---
|
||||
# WireGuard Client Configuration Generator
|
||||
# Usage: ansible-playbook playbooks/generate-wireguard-client.yml -e "client_name=michael-laptop"
|
||||
|
||||
- name: Generate WireGuard Client Configuration
|
||||
hosts: server
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
vars:
|
||||
# Default values (can be overridden with -e)
|
||||
wireguard_config_dir: "/etc/wireguard"
|
||||
wireguard_interface: "wg0"
|
||||
wireguard_server_endpoint: "{{ ansible_default_ipv4.address }}"
|
||||
wireguard_server_port: 51820
|
||||
wireguard_vpn_network: "10.8.0.0/24"
|
||||
wireguard_server_ip: "10.8.0.1"
|
||||
|
||||
# Client output directory (local)
|
||||
client_config_dir: "{{ playbook_dir }}/../wireguard/configs"
|
||||
|
||||
# Required variable (must be passed via -e)
|
||||
# client_name: "device-name"
|
||||
|
||||
tasks:
|
||||
- name: Validate client_name is provided
|
||||
assert:
|
||||
that:
|
||||
- client_name is defined
|
||||
- client_name | length > 0
|
||||
fail_msg: "ERROR: client_name must be provided via -e client_name=<name>"
|
||||
success_msg: "Generating config for client: {{ client_name }}"
|
||||
|
||||
- name: Validate client_name format (alphanumeric and hyphens only)
|
||||
assert:
|
||||
that:
|
||||
- client_name is match('^[a-zA-Z0-9-]+$')
|
||||
fail_msg: "ERROR: client_name must contain only letters, numbers, and hyphens"
|
||||
success_msg: "Client name format is valid"
|
||||
|
||||
- name: Check if WireGuard server is configured
|
||||
stat:
|
||||
path: "{{ wireguard_config_dir }}/{{ wireguard_interface }}.conf"
|
||||
register: server_config
|
||||
|
||||
- name: Fail if server config doesn't exist
|
||||
fail:
|
||||
msg: "WireGuard server config not found. Run setup-wireguard-host.yml first."
|
||||
when: not server_config.stat.exists
|
||||
|
||||
- name: Read server public key
|
||||
slurp:
|
||||
src: "{{ wireguard_config_dir }}/server_public.key"
|
||||
register: server_public_key_raw
|
||||
|
||||
- name: Set server public key fact
|
||||
set_fact:
|
||||
server_public_key: "{{ server_public_key_raw.content | b64decode | trim }}"
|
||||
|
||||
- name: Get next available IP address
|
||||
shell: |
|
||||
# Parse existing peer IPs from wg0.conf
|
||||
existing_ips=$(grep -oP 'AllowedIPs\s*=\s*\K[0-9.]+' {{ wireguard_config_dir }}/{{ wireguard_interface }}.conf 2>/dev/null || echo "")
|
||||
|
||||
# Start from .2 (server is .1)
|
||||
i=2
|
||||
while [ $i -le 254 ]; do
|
||||
ip="10.8.0.$i"
|
||||
if ! echo "$existing_ips" | grep -q "^$ip$"; then
|
||||
echo "$ip"
|
||||
exit 0
|
||||
fi
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
echo "ERROR: No free IP addresses" >&2
|
||||
exit 1
|
||||
register: next_ip_result
|
||||
changed_when: false
|
||||
|
||||
- name: Set client IP fact
|
||||
set_fact:
|
||||
client_ip: "{{ next_ip_result.stdout | trim }}"
|
||||
|
||||
- name: Display client IP assignment
|
||||
debug:
|
||||
msg: "Assigned IP for {{ client_name }}: {{ client_ip }}"
|
||||
|
||||
- name: Check if client already exists
|
||||
shell: |
|
||||
grep -q "# Client: {{ client_name }}" {{ wireguard_config_dir }}/{{ wireguard_interface }}.conf
|
||||
register: client_exists
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Warn if client already exists
|
||||
debug:
|
||||
msg: "WARNING: Client '{{ client_name }}' already exists in server config. Creating new keys anyway."
|
||||
when: client_exists.rc == 0
|
||||
|
||||
- name: Generate client private key
|
||||
shell: wg genkey
|
||||
register: client_private_key_result
|
||||
changed_when: true
|
||||
no_log: true
|
||||
|
||||
- name: Generate client public key
|
||||
shell: echo "{{ client_private_key_result.stdout }}" | wg pubkey
|
||||
register: client_public_key_result
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Generate preshared key
|
||||
shell: wg genpsk
|
||||
register: preshared_key_result
|
||||
changed_when: true
|
||||
no_log: true
|
||||
|
||||
- name: Set client key facts
|
||||
set_fact:
|
||||
client_private_key: "{{ client_private_key_result.stdout | trim }}"
|
||||
client_public_key: "{{ client_public_key_result.stdout | trim }}"
|
||||
preshared_key: "{{ preshared_key_result.stdout | trim }}"
|
||||
no_log: true
|
||||
|
||||
- name: Create client config directory on control node
|
||||
delegate_to: localhost
|
||||
file:
|
||||
path: "{{ client_config_dir }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
become: false
|
||||
|
||||
- name: Generate client WireGuard configuration
|
||||
delegate_to: localhost
|
||||
copy:
|
||||
content: |
|
||||
[Interface]
|
||||
# Client: {{ client_name }}
|
||||
# Generated: {{ ansible_date_time.iso8601 }}
|
||||
PrivateKey = {{ client_private_key }}
|
||||
Address = {{ client_ip }}/32
|
||||
DNS = 1.1.1.1, 8.8.8.8
|
||||
|
||||
[Peer]
|
||||
# WireGuard Server
|
||||
PublicKey = {{ server_public_key }}
|
||||
PresharedKey = {{ preshared_key }}
|
||||
Endpoint = {{ wireguard_server_endpoint }}:{{ wireguard_server_port }}
|
||||
AllowedIPs = {{ wireguard_vpn_network }}
|
||||
PersistentKeepalive = 25
|
||||
dest: "{{ client_config_dir }}/{{ client_name }}.conf"
|
||||
mode: '0600'
|
||||
become: false
|
||||
no_log: true
|
||||
|
||||
- name: Add client peer to server configuration
|
||||
blockinfile:
|
||||
path: "{{ wireguard_config_dir }}/{{ wireguard_interface }}.conf"
|
||||
marker: "# {mark} ANSIBLE MANAGED BLOCK - Client: {{ client_name }}"
|
||||
block: |
|
||||
|
||||
[Peer]
|
||||
# Client: {{ client_name }}
|
||||
PublicKey = {{ client_public_key }}
|
||||
PresharedKey = {{ preshared_key }}
|
||||
AllowedIPs = {{ client_ip }}/32
|
||||
no_log: true
|
||||
|
||||
- name: Reload WireGuard configuration
|
||||
shell: wg syncconf {{ wireguard_interface }} <(wg-quick strip {{ wireguard_interface }})
|
||||
args:
|
||||
executable: /bin/bash
|
||||
|
||||
- name: Generate QR code (ASCII)
|
||||
delegate_to: localhost
|
||||
shell: |
|
||||
qrencode -t ansiutf8 < {{ client_config_dir }}/{{ client_name }}.conf > {{ client_config_dir }}/{{ client_name }}.qr.txt
|
||||
become: false
|
||||
changed_when: true
|
||||
|
||||
- name: Generate QR code (PNG)
|
||||
delegate_to: localhost
|
||||
shell: |
|
||||
qrencode -t png -o {{ client_config_dir }}/{{ client_name }}.qr.png < {{ client_config_dir }}/{{ client_name }}.conf
|
||||
become: false
|
||||
changed_when: true
|
||||
|
||||
- name: Display QR code for mobile devices
|
||||
delegate_to: localhost
|
||||
shell: cat {{ client_config_dir }}/{{ client_name }}.qr.txt
|
||||
register: qr_code_output
|
||||
become: false
|
||||
changed_when: false
|
||||
|
||||
- name: Client configuration summary
|
||||
debug:
|
||||
msg:
|
||||
- "========================================="
|
||||
- "WireGuard Client Configuration Created!"
|
||||
- "========================================="
|
||||
- ""
|
||||
- "Client: {{ client_name }}"
|
||||
- "IP Address: {{ client_ip }}/32"
|
||||
- "Public Key: {{ client_public_key }}"
|
||||
- ""
|
||||
- "Configuration Files:"
|
||||
- " Config: {{ client_config_dir }}/{{ client_name }}.conf"
|
||||
- " QR Code (ASCII): {{ client_config_dir }}/{{ client_name }}.qr.txt"
|
||||
- " QR Code (PNG): {{ client_config_dir }}/{{ client_name }}.qr.png"
|
||||
- ""
|
||||
- "Server Configuration:"
|
||||
- " Endpoint: {{ wireguard_server_endpoint }}:{{ wireguard_server_port }}"
|
||||
- " Allowed IPs: {{ wireguard_vpn_network }}"
|
||||
- ""
|
||||
- "Next Steps:"
|
||||
- " Linux/macOS: sudo cp {{ client_config_dir }}/{{ client_name }}.conf /etc/wireguard/ && sudo wg-quick up {{ client_name }}"
|
||||
- " Windows: Import {{ client_name }}.conf in WireGuard GUI"
|
||||
- " iOS/Android: Scan QR code with WireGuard app"
|
||||
- ""
|
||||
- "Test Connection:"
|
||||
- " ping {{ wireguard_server_ip }}"
|
||||
- " curl -k https://{{ wireguard_server_ip }}:8080 # Traefik Dashboard"
|
||||
- ""
|
||||
- "========================================="
|
||||
|
||||
- name: Display QR code
|
||||
debug:
|
||||
msg: "{{ qr_code_output.stdout_lines }}"
|
||||
@@ -1,206 +0,0 @@
|
||||
---
|
||||
- name: Regenerate WireGuard Client - Fresh Config
|
||||
hosts: production
|
||||
become: yes
|
||||
gather_facts: yes
|
||||
|
||||
vars:
|
||||
wireguard_interface: "wg0"
|
||||
wireguard_config_path: "/etc/wireguard"
|
||||
wireguard_config_file: "{{ wireguard_config_path }}/{{ wireguard_interface }}.conf"
|
||||
wireguard_client_configs_path: "/etc/wireguard/clients"
|
||||
wireguard_local_client_configs_dir: "{{ playbook_dir }}/../wireguard-clients"
|
||||
|
||||
tasks:
|
||||
- name: Validate client name
|
||||
fail:
|
||||
msg: "client_name is required. Usage: ansible-playbook ... -e 'client_name=myclient'"
|
||||
when: client_name is not defined or client_name == ""
|
||||
|
||||
- name: Check if old client config exists
|
||||
stat:
|
||||
path: "{{ wireguard_client_configs_path }}/{{ client_name }}.conf"
|
||||
register: old_client_config
|
||||
failed_when: false
|
||||
|
||||
- name: Backup old client config
|
||||
copy:
|
||||
src: "{{ wireguard_client_configs_path }}/{{ client_name }}.conf"
|
||||
dest: "{{ wireguard_client_configs_path }}/{{ client_name }}.conf.backup-{{ ansible_date_time.epoch }}"
|
||||
remote_src: yes
|
||||
when: old_client_config.stat.exists
|
||||
register: backup_result
|
||||
failed_when: false
|
||||
|
||||
- name: Display backup info
|
||||
debug:
|
||||
msg: "Alte Config wurde gesichert als: {{ backup_result.dest | default('N/A') }}"
|
||||
when: old_client_config.stat.exists
|
||||
|
||||
- name: Remove old client from WireGuard server config
|
||||
shell: |
|
||||
# Entferne den [Peer] Block f?r den Client aus wg0.conf
|
||||
sed -i '/# BEGIN ANSIBLE MANAGED BLOCK - Client: {{ client_name }}/,/^# END ANSIBLE MANAGED BLOCK - Client: {{ client_name }}/d' {{ wireguard_config_file }}
|
||||
# Fallback: Entferne auch ohne Marker
|
||||
sed -i '/# Client: {{ client_name }}/,/{/d' {{ wireguard_config_file }}
|
||||
sed -i '/PublicKey = .*/d' {{ wireguard_config_file }} || true
|
||||
sed -i '/AllowedIPs = .*\/32$/d' {{ wireguard_config_file }} || true
|
||||
args:
|
||||
executable: /bin/bash
|
||||
register: remove_result
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Set WireGuard network
|
||||
set_fact:
|
||||
wireguard_network: "{{ wireguard_network | default('10.8.0.0/24') }}"
|
||||
|
||||
- name: Set WireGuard other variables with defaults
|
||||
set_fact:
|
||||
wireguard_port: "{{ wireguard_port | default(51820) }}"
|
||||
client_ip: "{{ client_ip | default('') }}"
|
||||
allowed_ips: "{{ allowed_ips | default(wireguard_network) }}"
|
||||
|
||||
- name: Get server external IP address
|
||||
uri:
|
||||
url: https://api.ipify.org
|
||||
return_content: yes
|
||||
register: server_external_ip
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Set server external IP
|
||||
set_fact:
|
||||
server_external_ip_content: "{{ ansible_host | default(server_external_ip.content | default('')) }}"
|
||||
|
||||
- name: Read WireGuard server config
|
||||
slurp:
|
||||
src: "{{ wireguard_config_file }}"
|
||||
register: wireguard_server_config_read
|
||||
|
||||
- name: Extract server IP from config
|
||||
set_fact:
|
||||
server_vpn_ip: "{{ (wireguard_server_config_read.content | b64decode | regex_findall('Address\\s*=\\s*([0-9.]+)') | first) | default('10.8.0.1') }}"
|
||||
failed_when: false
|
||||
|
||||
- name: Extract WireGuard server IP octets
|
||||
set_fact:
|
||||
wireguard_server_ip_octets: "{{ (server_vpn_ip | default('')).split('.') }}"
|
||||
when: client_ip == ""
|
||||
|
||||
- name: Fail if server VPN IP is invalid
|
||||
fail:
|
||||
msg: "Server VPN IP '{{ server_vpn_ip }}' ist ungültig – bitte wg0.conf prüfen."
|
||||
when: client_ip == "" and (wireguard_server_ip_octets | length) < 4
|
||||
|
||||
- name: Gather existing client addresses
|
||||
set_fact:
|
||||
existing_client_ips: "{{ (wireguard_server_config_read.content | b64decode | regex_findall('AllowedIPs = ([0-9A-Za-z.]+)/32', '\\\\1')) }}"
|
||||
when: client_ip == ""
|
||||
|
||||
- name: Calculate client IP if not provided
|
||||
vars:
|
||||
existing_last_octets: "{{ (existing_client_ips | default([])) | map('regex_replace', '^(?:\\\\d+\\\\.\\\\d+\\\\.\\\\d+\\\\.)', '') | select('match', '^[0-9]+$') | map('int') | list }}"
|
||||
server_last_octet: "{{ wireguard_server_ip_octets[3] | int }}"
|
||||
next_octet_candidate: "{{ (existing_last_octets + [server_last_octet]) | map('int') | list | max + 1 if (existing_client_ips | default([]) | length > 0) else server_last_octet + 1 }}"
|
||||
set_fact:
|
||||
client_ip: "{{ [
|
||||
wireguard_server_ip_octets[0],
|
||||
wireguard_server_ip_octets[1],
|
||||
wireguard_server_ip_octets[2],
|
||||
next_octet_candidate
|
||||
] | join('.') }}"
|
||||
when: client_ip == "" and (wireguard_server_ip_octets | length) >= 4
|
||||
|
||||
- name: Generate NEW client private key
|
||||
command: "wg genkey"
|
||||
register: client_private_key
|
||||
changed_when: true
|
||||
no_log: yes
|
||||
|
||||
- name: Generate NEW client public key
|
||||
command: "wg pubkey"
|
||||
args:
|
||||
stdin: "{{ client_private_key.stdout }}"
|
||||
register: client_public_key
|
||||
changed_when: false
|
||||
no_log: yes
|
||||
|
||||
- name: Add NEW client to WireGuard server config
|
||||
blockinfile:
|
||||
path: "{{ wireguard_config_file }}"
|
||||
block: |
|
||||
# Client: {{ client_name }}
|
||||
[Peer]
|
||||
PublicKey = {{ client_public_key.stdout }}
|
||||
AllowedIPs = {{ client_ip }}/32
|
||||
marker: "# {mark} ANSIBLE MANAGED BLOCK - Client: {{ client_name }}"
|
||||
register: wireguard_client_block
|
||||
|
||||
- name: Ensure client configs directory exists
|
||||
file:
|
||||
path: "{{ wireguard_client_configs_path }}"
|
||||
state: directory
|
||||
mode: '0700'
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: Ensure local client configs directory exists
|
||||
file:
|
||||
path: "{{ wireguard_local_client_configs_dir }}"
|
||||
state: directory
|
||||
mode: '0700'
|
||||
delegate_to: localhost
|
||||
become: no
|
||||
run_once: true
|
||||
|
||||
- name: Get server public key
|
||||
shell: "cat {{ wireguard_config_path }}/{{ wireguard_interface }}_private.key | wg pubkey"
|
||||
register: server_public_key_cmd
|
||||
changed_when: false
|
||||
no_log: yes
|
||||
failed_when: false
|
||||
|
||||
- name: Create NEW client configuration file
|
||||
template:
|
||||
src: "{{ playbook_dir }}/../templates/wireguard-client.conf.j2"
|
||||
dest: "{{ wireguard_client_configs_path }}/{{ client_name }}.conf"
|
||||
mode: '0600'
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: Download NEW client configuration to control machine
|
||||
fetch:
|
||||
src: "{{ wireguard_client_configs_path }}/{{ client_name }}.conf"
|
||||
dest: "{{ wireguard_local_client_configs_dir }}/{{ client_name }}.conf"
|
||||
flat: yes
|
||||
mode: '0600'
|
||||
|
||||
- name: Restart WireGuard service
|
||||
systemd:
|
||||
name: "wg-quick@{{ wireguard_interface }}"
|
||||
state: restarted
|
||||
|
||||
- name: Display NEW client configuration
|
||||
debug:
|
||||
msg: |
|
||||
========================================
|
||||
WireGuard Client REGENERATED: {{ client_name }}
|
||||
========================================
|
||||
|
||||
Neue Client-IP: {{ client_ip }}
|
||||
Server Endpoint: {{ server_external_ip_content }}:{{ wireguard_port }}
|
||||
|
||||
Neue Client-Konfiguration:
|
||||
{{ wireguard_local_client_configs_dir }}/{{ client_name }}.conf
|
||||
|
||||
WICHTIG:
|
||||
1. Lade die neue Config-Datei herunter
|
||||
2. Importiere sie in WireGuard (ersetze die alte!)
|
||||
3. Verbinde mit dem VPN
|
||||
4. Teste: ping 10.8.0.1
|
||||
5. Teste: https://grafana.michaelschiemer.de
|
||||
|
||||
Alte Config gesichert als:
|
||||
{{ backup_result.dest | default('N/A') }}
|
||||
========================================
|
||||
309
deployment/ansible/playbooks/setup-wireguard-host.yml
Normal file
309
deployment/ansible/playbooks/setup-wireguard-host.yml
Normal file
@@ -0,0 +1,309 @@
|
||||
---
|
||||
# Ansible Playbook: WireGuard Host-based VPN Setup
|
||||
# Purpose: Deploy minimalistic WireGuard VPN for admin access
|
||||
# Architecture: Host-based (systemd), no Docker, no DNS
|
||||
|
||||
- name: Setup WireGuard VPN (Host-based)
|
||||
hosts: all
|
||||
become: yes
|
||||
|
||||
vars:
|
||||
# WireGuard Configuration
|
||||
wg_interface: wg0
|
||||
wg_network: 10.8.0.0/24
|
||||
wg_server_ip: 10.8.0.1
|
||||
wg_netmask: 24
|
||||
wg_port: 51820
|
||||
|
||||
# Network Configuration
|
||||
wan_interface: eth0 # Change to your WAN interface (eth0, ens3, etc.)
|
||||
|
||||
# Admin Service Ports (VPN-only access)
|
||||
admin_service_ports:
|
||||
- 8080 # Traefik Dashboard
|
||||
- 9090 # Prometheus
|
||||
- 3001 # Grafana
|
||||
- 9000 # Portainer
|
||||
- 8001 # Redis Insight
|
||||
|
||||
# Public Service Ports
|
||||
public_service_ports:
|
||||
- 80 # HTTP
|
||||
- 443 # HTTPS
|
||||
- 22 # SSH
|
||||
|
||||
# Rate Limiting
|
||||
wg_enable_rate_limit: true
|
||||
|
||||
# Paths
|
||||
wg_config_dir: /etc/wireguard
|
||||
wg_backup_dir: /root/wireguard-backup
|
||||
nft_config_file: /etc/nftables.d/wireguard.nft
|
||||
|
||||
tasks:
|
||||
# ========================================
|
||||
# 1. Pre-flight Checks
|
||||
# ========================================
|
||||
|
||||
- name: Check if running as root
|
||||
assert:
|
||||
that: ansible_user_id == 'root'
|
||||
fail_msg: "This playbook must be run as root"
|
||||
|
||||
- name: Detect WAN interface
|
||||
shell: ip route | grep default | awk '{print $5}' | head -n1
|
||||
register: detected_wan_interface
|
||||
changed_when: false
|
||||
|
||||
- name: Set WAN interface if not specified
|
||||
set_fact:
|
||||
wan_interface: "{{ detected_wan_interface.stdout }}"
|
||||
when: wan_interface == 'eth0' and detected_wan_interface.stdout != ''
|
||||
|
||||
- name: Display detected network configuration
|
||||
debug:
|
||||
msg:
|
||||
- "WAN Interface: {{ wan_interface }}"
|
||||
- "VPN Network: {{ wg_network }}"
|
||||
- "VPN Server IP: {{ wg_server_ip }}"
|
||||
|
||||
# ========================================
|
||||
# 2. Backup Existing Configuration
|
||||
# ========================================
|
||||
|
||||
- name: Create backup directory
|
||||
file:
|
||||
path: "{{ wg_backup_dir }}"
|
||||
state: directory
|
||||
mode: '0700'
|
||||
|
||||
- name: Backup existing WireGuard config (if exists)
|
||||
shell: |
|
||||
if [ -d {{ wg_config_dir }} ]; then
|
||||
tar -czf {{ wg_backup_dir }}/wireguard-backup-$(date +%Y%m%d-%H%M%S).tar.gz {{ wg_config_dir }}
|
||||
echo "Backup created"
|
||||
else
|
||||
echo "No existing config"
|
||||
fi
|
||||
register: backup_result
|
||||
changed_when: "'Backup created' in backup_result.stdout"
|
||||
|
||||
# ========================================
|
||||
# 3. Install WireGuard
|
||||
# ========================================
|
||||
|
||||
- name: Update apt cache
|
||||
apt:
|
||||
update_cache: yes
|
||||
cache_valid_time: 3600
|
||||
when: ansible_os_family == 'Debian'
|
||||
|
||||
- name: Install WireGuard and dependencies
|
||||
apt:
|
||||
name:
|
||||
- wireguard
|
||||
- wireguard-tools
|
||||
- qrencode # For QR code generation
|
||||
- nftables
|
||||
state: present
|
||||
when: ansible_os_family == 'Debian'
|
||||
|
||||
- name: Ensure WireGuard kernel module is loaded
|
||||
modprobe:
|
||||
name: wireguard
|
||||
state: present
|
||||
|
||||
- name: Verify WireGuard module is available
|
||||
shell: lsmod | grep -q wireguard
|
||||
register: wg_module_check
|
||||
failed_when: wg_module_check.rc != 0
|
||||
changed_when: false
|
||||
|
||||
# ========================================
|
||||
# 4. Generate Server Keys (if not exist)
|
||||
# ========================================
|
||||
|
||||
- name: Create WireGuard config directory
|
||||
file:
|
||||
path: "{{ wg_config_dir }}"
|
||||
state: directory
|
||||
mode: '0700'
|
||||
|
||||
- name: Check if server private key exists
|
||||
stat:
|
||||
path: "{{ wg_config_dir }}/server_private.key"
|
||||
register: server_private_key_stat
|
||||
|
||||
- name: Generate server private key
|
||||
shell: wg genkey > {{ wg_config_dir }}/server_private.key
|
||||
when: not server_private_key_stat.stat.exists
|
||||
|
||||
- name: Set server private key permissions
|
||||
file:
|
||||
path: "{{ wg_config_dir }}/server_private.key"
|
||||
mode: '0600'
|
||||
|
||||
- name: Generate server public key
|
||||
shell: cat {{ wg_config_dir }}/server_private.key | wg pubkey > {{ wg_config_dir }}/server_public.key
|
||||
when: not server_private_key_stat.stat.exists
|
||||
|
||||
- name: Read server private key
|
||||
slurp:
|
||||
src: "{{ wg_config_dir }}/server_private.key"
|
||||
register: server_private_key_content
|
||||
|
||||
- name: Read server public key
|
||||
slurp:
|
||||
src: "{{ wg_config_dir }}/server_public.key"
|
||||
register: server_public_key_content
|
||||
|
||||
- name: Set server key facts
|
||||
set_fact:
|
||||
wg_server_private_key: "{{ server_private_key_content.content | b64decode | trim }}"
|
||||
wg_server_public_key: "{{ server_public_key_content.content | b64decode | trim }}"
|
||||
|
||||
- name: Display server public key
|
||||
debug:
|
||||
msg: "Server Public Key: {{ wg_server_public_key }}"
|
||||
|
||||
# ========================================
|
||||
# 5. Configure WireGuard
|
||||
# ========================================
|
||||
|
||||
- name: Deploy WireGuard server configuration
|
||||
template:
|
||||
src: ../templates/wg0.conf.j2
|
||||
dest: "{{ wg_config_dir }}/wg0.conf"
|
||||
mode: '0600'
|
||||
notify: restart wireguard
|
||||
|
||||
- name: Enable IP forwarding
|
||||
sysctl:
|
||||
name: net.ipv4.ip_forward
|
||||
value: '1'
|
||||
sysctl_set: yes
|
||||
state: present
|
||||
reload: yes
|
||||
|
||||
# ========================================
|
||||
# 6. Configure nftables Firewall
|
||||
# ========================================
|
||||
|
||||
- name: Create nftables config directory
|
||||
file:
|
||||
path: /etc/nftables.d
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Deploy WireGuard firewall rules
|
||||
template:
|
||||
src: ../templates/wireguard-host-firewall.nft.j2
|
||||
dest: "{{ nft_config_file }}"
|
||||
mode: '0644'
|
||||
notify: reload nftables
|
||||
|
||||
- name: Include WireGuard rules in main nftables config
|
||||
lineinfile:
|
||||
path: /etc/nftables.conf
|
||||
line: 'include "{{ nft_config_file }}"'
|
||||
create: yes
|
||||
state: present
|
||||
notify: reload nftables
|
||||
|
||||
- name: Enable nftables service
|
||||
systemd:
|
||||
name: nftables
|
||||
enabled: yes
|
||||
state: started
|
||||
|
||||
# ========================================
|
||||
# 7. Enable and Start WireGuard
|
||||
# ========================================
|
||||
|
||||
- name: Enable WireGuard interface
|
||||
systemd:
|
||||
name: wg-quick@wg0
|
||||
enabled: yes
|
||||
state: started
|
||||
|
||||
- name: Verify WireGuard is running
|
||||
command: wg show wg0
|
||||
register: wg_status
|
||||
changed_when: false
|
||||
|
||||
- name: Display WireGuard status
|
||||
debug:
|
||||
msg: "{{ wg_status.stdout_lines }}"
|
||||
|
||||
# ========================================
|
||||
# 8. Health Checks
|
||||
# ========================================
|
||||
|
||||
- name: Check WireGuard interface exists
|
||||
command: ip link show wg0
|
||||
register: wg_interface_check
|
||||
failed_when: wg_interface_check.rc != 0
|
||||
changed_when: false
|
||||
|
||||
- name: Check firewall rules applied
|
||||
command: nft list ruleset
|
||||
register: nft_rules
|
||||
failed_when: "'wireguard_firewall' not in nft_rules.stdout"
|
||||
changed_when: false
|
||||
|
||||
- name: Verify admin ports are blocked from public
|
||||
shell: nft list chain inet wireguard_firewall input | grep -q "admin_service_ports.*drop"
|
||||
register: admin_port_block_check
|
||||
failed_when: admin_port_block_check.rc != 0
|
||||
changed_when: false
|
||||
|
||||
# ========================================
|
||||
# 9. Post-Installation Summary
|
||||
# ========================================
|
||||
|
||||
- name: Create post-installation summary
|
||||
debug:
|
||||
msg:
|
||||
- "========================================="
|
||||
- "WireGuard VPN Setup Complete!"
|
||||
- "========================================="
|
||||
- ""
|
||||
- "Server Configuration:"
|
||||
- " Interface: wg0"
|
||||
- " Server IP: {{ wg_server_ip }}/{{ wg_netmask }}"
|
||||
- " Listen Port: {{ wg_port }}"
|
||||
- " Public Key: {{ wg_server_public_key }}"
|
||||
- ""
|
||||
- "Network Configuration:"
|
||||
- " VPN Network: {{ wg_network }}"
|
||||
- " WAN Interface: {{ wan_interface }}"
|
||||
- ""
|
||||
- "Admin Service Access (VPN-only):"
|
||||
- " Traefik Dashboard: https://{{ wg_server_ip }}:8080"
|
||||
- " Prometheus: http://{{ wg_server_ip }}:9090"
|
||||
- " Grafana: https://{{ wg_server_ip }}:3001"
|
||||
- " Portainer: http://{{ wg_server_ip }}:9000"
|
||||
- " Redis Insight: http://{{ wg_server_ip }}:8001"
|
||||
- ""
|
||||
- "Next Steps:"
|
||||
- " 1. Generate client config: ./scripts/generate-client-config.sh <device-name>"
|
||||
- " 2. Import config on client device"
|
||||
- " 3. Connect and verify access"
|
||||
- ""
|
||||
- "Firewall Status: ACTIVE (nftables)"
|
||||
- " - Public ports: 80, 443, 22"
|
||||
- " - VPN port: {{ wg_port }}"
|
||||
- " - Admin services: VPN-only access"
|
||||
- ""
|
||||
- "========================================="
|
||||
|
||||
handlers:
|
||||
- name: restart wireguard
|
||||
systemd:
|
||||
name: wg-quick@wg0
|
||||
state: restarted
|
||||
|
||||
- name: reload nftables
|
||||
systemd:
|
||||
name: nftables
|
||||
state: reloaded
|
||||
@@ -1,287 +0,0 @@
|
||||
---
|
||||
- name: Setup WireGuard VPN Server
|
||||
hosts: production
|
||||
become: yes
|
||||
gather_facts: yes
|
||||
|
||||
vars:
|
||||
# WireGuard variables are defined in group_vars/production.yml
|
||||
# Can be overridden via -e flag if needed
|
||||
wireguard_port: "{{ wireguard_port_default | default(51820) }}"
|
||||
wireguard_network: "{{ wireguard_network_default | default('10.8.0.0/24') }}"
|
||||
wireguard_server_ip: "{{ wireguard_server_ip_default | default('10.8.0.1') }}"
|
||||
|
||||
pre_tasks:
|
||||
|
||||
- name: Optionally load wireguard secrets from vault
|
||||
include_vars:
|
||||
file: "{{ playbook_dir }}/../secrets/production.vault.yml"
|
||||
no_log: yes
|
||||
ignore_errors: yes
|
||||
delegate_to: localhost
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Check if WireGuard is already installed
|
||||
command: which wg
|
||||
register: wireguard_installed
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Update package cache
|
||||
apt:
|
||||
update_cache: yes
|
||||
cache_valid_time: 3600
|
||||
when: not wireguard_installed.rc == 0
|
||||
|
||||
- name: Install WireGuard
|
||||
apt:
|
||||
name:
|
||||
- wireguard
|
||||
- wireguard-tools
|
||||
- qrencode
|
||||
state: present
|
||||
when: not wireguard_installed.rc == 0
|
||||
notify: restart wireguard
|
||||
|
||||
- name: Ensure WireGuard config directory exists
|
||||
file:
|
||||
path: "{{ wireguard_config_path }}"
|
||||
state: directory
|
||||
mode: '0700'
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: Ensure WireGuard client configs directory exists
|
||||
file:
|
||||
path: "{{ wireguard_client_configs_path }}"
|
||||
state: directory
|
||||
mode: '0700'
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: Check if WireGuard server keys exist
|
||||
stat:
|
||||
path: "{{ wireguard_private_key_file }}"
|
||||
register: server_private_key_exists
|
||||
|
||||
- name: Generate WireGuard server private key
|
||||
command: "wg genkey"
|
||||
register: server_private_key
|
||||
changed_when: true
|
||||
when: not server_private_key_exists.stat.exists
|
||||
no_log: yes
|
||||
|
||||
- name: Save WireGuard server private key
|
||||
copy:
|
||||
content: "{{ server_private_key.stdout }}"
|
||||
dest: "{{ wireguard_private_key_file }}"
|
||||
mode: '0600'
|
||||
owner: root
|
||||
group: root
|
||||
when: not server_private_key_exists.stat.exists
|
||||
no_log: yes
|
||||
|
||||
- name: Read WireGuard server private key
|
||||
slurp:
|
||||
src: "{{ wireguard_private_key_file }}"
|
||||
register: server_private_key_content
|
||||
when: server_private_key_exists.stat.exists
|
||||
|
||||
- name: Generate WireGuard server public key
|
||||
command: "wg pubkey"
|
||||
args:
|
||||
stdin: "{{ server_private_key.stdout if not server_private_key_exists.stat.exists else server_private_key_content.content | b64decode | trim }}"
|
||||
register: server_public_key
|
||||
changed_when: false
|
||||
when: not server_private_key_exists.stat.exists
|
||||
no_log: yes
|
||||
|
||||
- name: Get existing server public key
|
||||
shell: "cat {{ wireguard_private_key_file }} | wg pubkey"
|
||||
register: existing_server_public_key
|
||||
changed_when: false
|
||||
when: server_private_key_exists.stat.exists
|
||||
no_log: yes
|
||||
failed_when: false
|
||||
|
||||
- name: Set server public key fact
|
||||
set_fact:
|
||||
server_public_key_value: "{{ server_public_key.stdout if not server_private_key_exists.stat.exists else existing_server_public_key.stdout }}"
|
||||
|
||||
- name: Save WireGuard server public key
|
||||
copy:
|
||||
content: "{{ server_public_key_value }}"
|
||||
dest: "{{ wireguard_public_key_file }}"
|
||||
mode: '0644'
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: Enable IP forwarding
|
||||
sysctl:
|
||||
name: net.ipv4.ip_forward
|
||||
value: '1'
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
when: wireguard_enable_ip_forwarding
|
||||
|
||||
- name: Make IP forwarding persistent
|
||||
lineinfile:
|
||||
path: /etc/sysctl.conf
|
||||
regexp: '^net\.ipv4\.ip_forward'
|
||||
line: 'net.ipv4.ip_forward=1'
|
||||
state: present
|
||||
when: wireguard_enable_ip_forwarding
|
||||
|
||||
- name: Get server external IP address
|
||||
uri:
|
||||
url: https://api.ipify.org
|
||||
return_content: yes
|
||||
register: server_external_ip
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Set server external IP from inventory if API fails
|
||||
set_fact:
|
||||
server_external_ip_content: "{{ ansible_host | default(server_external_ip.content | default('')) }}"
|
||||
when: server_external_ip.content is defined
|
||||
|
||||
- name: Get server external IP from ansible_host
|
||||
set_fact:
|
||||
server_external_ip_content: "{{ ansible_host }}"
|
||||
when: server_external_ip.content is not defined
|
||||
|
||||
- name: Read server private key for config
|
||||
slurp:
|
||||
src: "{{ wireguard_private_key_file }}"
|
||||
register: server_private_key_file_content
|
||||
when: server_private_key_exists.stat.exists
|
||||
|
||||
- name: Set server private key for template (new key)
|
||||
set_fact:
|
||||
server_private_key_for_config: "{{ server_private_key.stdout }}"
|
||||
when: not server_private_key_exists.stat.exists
|
||||
|
||||
- name: Set server private key for template (existing key)
|
||||
set_fact:
|
||||
server_private_key_for_config: "{{ server_private_key_file_content.content | b64decode | trim }}"
|
||||
when: server_private_key_exists.stat.exists
|
||||
|
||||
- name: Get network interface name
|
||||
shell: "ip route | grep default | awk '{print $5}' | head -1"
|
||||
register: default_interface
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Set default interface
|
||||
set_fact:
|
||||
wireguard_interface_name: "{{ default_interface.stdout | default('eth0') }}"
|
||||
|
||||
- name: Check if WireGuard config exists
|
||||
stat:
|
||||
path: "{{ wireguard_config_file }}"
|
||||
register: wireguard_config_exists
|
||||
|
||||
- name: Create WireGuard server configuration
|
||||
template:
|
||||
src: "{{ playbook_dir }}/../templates/wireguard-server.conf.j2"
|
||||
dest: "{{ wireguard_config_file }}"
|
||||
mode: '0600'
|
||||
owner: root
|
||||
group: root
|
||||
notify: restart wireguard
|
||||
|
||||
- name: Check if WireGuard service is enabled
|
||||
systemd:
|
||||
name: "wg-quick@{{ wireguard_interface }}"
|
||||
register: wireguard_service_status
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Enable WireGuard service
|
||||
systemd:
|
||||
name: "wg-quick@{{ wireguard_interface }}"
|
||||
enabled: yes
|
||||
daemon_reload: yes
|
||||
when: not wireguard_service_status.status.ActiveState is defined or wireguard_service_status.status.ActiveState != 'active'
|
||||
|
||||
- name: Start WireGuard service
|
||||
systemd:
|
||||
name: "wg-quick@{{ wireguard_interface }}"
|
||||
state: started
|
||||
notify: restart wireguard
|
||||
|
||||
- name: Check if UFW firewall is installed
|
||||
command: which ufw
|
||||
register: ufw_installed
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Verify SSH access is allowed in UFW
|
||||
command: "ufw status | grep -q '22/tcp' || echo 'SSH not found'"
|
||||
register: ssh_ufw_check
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
when: ufw_installed.rc == 0
|
||||
|
||||
- name: Warn if SSH is not explicitly allowed
|
||||
debug:
|
||||
msg: |
|
||||
?? WARNING: SSH (port 22) might not be explicitly allowed in UFW!
|
||||
Please ensure SSH access is configured before proceeding.
|
||||
Run: sudo ufw allow 22/tcp
|
||||
when: ufw_installed.rc == 0 and 'SSH not found' in ssh_ufw_check.stdout
|
||||
|
||||
- name: Allow WireGuard port in UFW firewall
|
||||
ufw:
|
||||
rule: allow
|
||||
port: "{{ wireguard_port }}"
|
||||
proto: udp
|
||||
comment: "WireGuard VPN"
|
||||
when: ufw_installed.rc == 0
|
||||
|
||||
- name: Allow WireGuard port in UFW firewall (alternative)
|
||||
shell: "ufw allow {{ wireguard_port }}/udp comment 'WireGuard VPN'"
|
||||
when: ufw_installed.rc == 0
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Check WireGuard status
|
||||
command: "wg show {{ wireguard_interface }}"
|
||||
register: wireguard_status
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Display WireGuard status
|
||||
debug:
|
||||
msg: |
|
||||
WireGuard Status:
|
||||
{{ wireguard_status.stdout if wireguard_status.rc == 0 else 'WireGuard interface not active' }}
|
||||
|
||||
- name: Display server public key
|
||||
debug:
|
||||
msg: |
|
||||
========================================
|
||||
WireGuard Server Setup Complete!
|
||||
========================================
|
||||
|
||||
Server Public Key:
|
||||
{{ server_public_key_value }}
|
||||
|
||||
Server IP: {{ wireguard_server_ip }}
|
||||
Server Endpoint: {{ server_external_ip_content }}:{{ wireguard_port }}
|
||||
Network: {{ wireguard_network }}
|
||||
|
||||
To add a client, run:
|
||||
ansible-playbook -i inventory/production.yml playbooks/add-wireguard-client.yml -e "client_name=myclient"
|
||||
|
||||
Client configs are stored in:
|
||||
{{ wireguard_client_configs_path }}/
|
||||
========================================
|
||||
|
||||
handlers:
|
||||
- name: restart wireguard
|
||||
systemd:
|
||||
name: "wg-quick@{{ wireguard_interface }}"
|
||||
state: restarted
|
||||
@@ -1,168 +0,0 @@
|
||||
---
|
||||
- name: Test WireGuard Connection from Docker Container
|
||||
hosts: production
|
||||
become: yes
|
||||
gather_facts: yes
|
||||
|
||||
vars:
|
||||
test_container_name: "wireguard-test-client"
|
||||
wireguard_config_path: "/tmp/wireguard-test"
|
||||
|
||||
tasks:
|
||||
- name: Validate client name
|
||||
fail:
|
||||
msg: "client_name is required. Usage: ansible-playbook ... -e 'client_name=grafana-test'"
|
||||
when: client_name is not defined or client_name == ""
|
||||
|
||||
- name: Check if WireGuard client config exists
|
||||
stat:
|
||||
path: "{{ playbook_dir }}/../wireguard-clients/{{ client_name }}.conf"
|
||||
register: client_config_exists
|
||||
delegate_to: localhost
|
||||
become: no
|
||||
|
||||
- name: Fail if client config not found
|
||||
fail:
|
||||
msg: "Client config not found: {{ playbook_dir }}/../wireguard-clients/{{ client_name }}.conf"
|
||||
when: not client_config_exists.stat.exists
|
||||
|
||||
- name: Read client config
|
||||
slurp:
|
||||
src: "{{ playbook_dir }}/../wireguard-clients/{{ client_name }}.conf"
|
||||
register: client_config_content
|
||||
delegate_to: localhost
|
||||
become: no
|
||||
|
||||
- name: Extract client IP from config
|
||||
set_fact:
|
||||
client_vpn_ip: "{{ (client_config_content.content | b64decode | regex_findall('Address\\s*=\\s*([0-9.]+)') | first) | default('10.8.0.7') }}"
|
||||
failed_when: false
|
||||
|
||||
- name: Display extracted client IP
|
||||
debug:
|
||||
msg: "Client VPN IP: {{ client_vpn_ip }}"
|
||||
|
||||
- name: Stop and remove existing test container
|
||||
shell: |
|
||||
docker stop {{ test_container_name }} || true
|
||||
docker rm {{ test_container_name }} || true
|
||||
args:
|
||||
executable: /bin/bash
|
||||
ignore_errors: yes
|
||||
failed_when: false
|
||||
|
||||
- name: Create temporary directory for WireGuard config
|
||||
file:
|
||||
path: "{{ wireguard_config_path }}"
|
||||
state: directory
|
||||
mode: '0700'
|
||||
|
||||
- name: Copy client config to server
|
||||
copy:
|
||||
content: "{{ client_config_content.content | b64decode }}"
|
||||
dest: "{{ wireguard_config_path }}/{{ client_name }}.conf"
|
||||
mode: '0600'
|
||||
|
||||
- name: Start WireGuard test container
|
||||
shell: |
|
||||
docker run -d \
|
||||
--name {{ test_container_name }} \
|
||||
--cap-add=NET_ADMIN \
|
||||
--cap-add=SYS_MODULE \
|
||||
--sysctl net.ipv4.conf.all.src_valid_mark=1 \
|
||||
-v {{ wireguard_config_path }}/{{ client_name }}.conf:/etc/wireguard/{{ client_name }}.conf:ro \
|
||||
--device /dev/net/tun \
|
||||
ghcr.io/linuxserver/wireguard:latest
|
||||
args:
|
||||
executable: /bin/bash
|
||||
register: container_result
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Wait for container to start
|
||||
pause:
|
||||
seconds: 5
|
||||
|
||||
- name: Check container status
|
||||
shell: docker ps -a --filter "name={{ test_container_name }}" --format "{{ '{{' }}.Status{{ '}}' }}"
|
||||
register: container_status
|
||||
failed_when: false
|
||||
|
||||
- name: Display container status
|
||||
debug:
|
||||
msg: "Container Status: {{ container_status.stdout }}"
|
||||
|
||||
- name: Get container logs
|
||||
shell: docker logs {{ test_container_name }} --tail 50
|
||||
register: container_logs
|
||||
failed_when: false
|
||||
|
||||
- name: Display container logs
|
||||
debug:
|
||||
msg: "{{ container_logs.stdout_lines }}"
|
||||
|
||||
- name: Test ping to VPN server from container
|
||||
shell: |
|
||||
docker exec {{ test_container_name }} ping -c 4 10.8.0.1 || true
|
||||
register: ping_result
|
||||
failed_when: false
|
||||
|
||||
- name: Display ping result
|
||||
debug:
|
||||
msg: "{{ ping_result.stdout_lines }}"
|
||||
|
||||
- name: Test curl to Grafana from container
|
||||
shell: |
|
||||
docker exec {{ test_container_name }} curl -s -o /dev/null -w "%{http_code}" --max-time 10 https://grafana.michaelschiemer.de/ || echo "FAILED"
|
||||
register: curl_result
|
||||
failed_when: false
|
||||
|
||||
- name: Display curl result
|
||||
debug:
|
||||
msg: "HTTP Status Code: {{ curl_result.stdout }}"
|
||||
|
||||
- name: Get container IP
|
||||
shell: |
|
||||
docker exec {{ test_container_name }} ip addr show wg0 | grep "inet " | awk '{print $2}' | cut -d/ -f1 || echo "No WireGuard IP"
|
||||
register: container_wg_ip
|
||||
failed_when: false
|
||||
|
||||
- name: Display container WireGuard IP
|
||||
debug:
|
||||
msg: "Container WireGuard IP: {{ container_wg_ip.stdout }}"
|
||||
|
||||
- name: Test DNS resolution from container
|
||||
shell: |
|
||||
docker exec {{ test_container_name }} nslookup grafana.michaelschiemer.de || true
|
||||
register: dns_result
|
||||
failed_when: false
|
||||
|
||||
- name: Display DNS result
|
||||
debug: "{{ dns_result.stdout_lines }}"
|
||||
|
||||
- name: Check Traefik logs for container access
|
||||
shell: |
|
||||
cd ~/deployment/stacks/traefik
|
||||
tail -100 logs/access.log | grep -i grafana | tail -10 | grep -oP '"ClientHost":"[^"]*"' | sed 's/"ClientHost":"//;s/"//' | sort -u
|
||||
register: traefik_client_ips
|
||||
failed_when: false
|
||||
|
||||
- name: Display Traefik client IPs
|
||||
debug:
|
||||
msg: "{{ traefik_client_ips.stdout_lines }}"
|
||||
|
||||
- name: Cleanup instructions
|
||||
debug:
|
||||
msg: |
|
||||
========================================
|
||||
TEST ABGESCHLOSSEN
|
||||
========================================
|
||||
|
||||
Container-Name: {{ test_container_name }}
|
||||
|
||||
Um Container zu entfernen:
|
||||
docker stop {{ test_container_name }}
|
||||
docker rm {{ test_container_name }}
|
||||
|
||||
Um Config zu entfernen:
|
||||
rm -rf {{ wireguard_config_path }}
|
||||
========================================
|
||||
212
deployment/ansible/playbooks/wireguard-routing.yml
Normal file
212
deployment/ansible/playbooks/wireguard-routing.yml
Normal file
@@ -0,0 +1,212 @@
|
||||
---
|
||||
- name: Configure WireGuard split tunnel routing
|
||||
hosts: production
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
vars:
|
||||
wg_interface: wg0
|
||||
wg_addr: 10.8.0.1/24
|
||||
wg_net: 10.8.0.0/24
|
||||
wan_interface: eth0
|
||||
listening_port: 51820
|
||||
extra_nets:
|
||||
- 192.168.178.0/24
|
||||
- 172.20.0.0/16
|
||||
firewall_backend: iptables # or nftables
|
||||
manage_ufw: false
|
||||
manage_firewalld: false
|
||||
firewalld_zone: public
|
||||
|
||||
pre_tasks:
|
||||
- name: Ensure required collections are installed (documentation note)
|
||||
debug:
|
||||
msg: >
|
||||
Install collections if missing:
|
||||
ansible-galaxy collection install ansible.posix community.general
|
||||
when: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure WireGuard config directory exists
|
||||
ansible.builtin.file:
|
||||
path: "/etc/wireguard"
|
||||
state: directory
|
||||
mode: "0700"
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: Persist IPv4 forwarding
|
||||
ansible.builtin.copy:
|
||||
dest: "/etc/sysctl.d/99-{{ wg_interface }}-forward.conf"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
content: |
|
||||
# Managed by Ansible - WireGuard {{ wg_interface }}
|
||||
net.ipv4.ip_forward=1
|
||||
|
||||
- name: Enable IPv4 forwarding runtime
|
||||
ansible.posix.sysctl:
|
||||
name: net.ipv4.ip_forward
|
||||
value: "1"
|
||||
state: present
|
||||
reload: true
|
||||
|
||||
- name: Configure MASQUERADE (iptables)
|
||||
community.general.iptables:
|
||||
table: nat
|
||||
chain: POSTROUTING
|
||||
out_interface: "{{ wan_interface }}"
|
||||
source: "{{ wg_net }}"
|
||||
jump: MASQUERADE
|
||||
state: present
|
||||
when: firewall_backend == "iptables"
|
||||
|
||||
- name: Allow forwarding wg -> wan (iptables)
|
||||
community.general.iptables:
|
||||
table: filter
|
||||
chain: FORWARD
|
||||
in_interface: "{{ wg_interface }}"
|
||||
out_interface: "{{ wan_interface }}"
|
||||
source: "{{ wg_net }}"
|
||||
jump: ACCEPT
|
||||
state: present
|
||||
when: firewall_backend == "iptables"
|
||||
|
||||
- name: Allow forwarding wan -> wg (iptables)
|
||||
community.general.iptables:
|
||||
table: filter
|
||||
chain: FORWARD
|
||||
out_interface: "{{ wg_interface }}"
|
||||
destination: "{{ wg_net }}"
|
||||
ctstate: RELATED,ESTABLISHED
|
||||
jump: ACCEPT
|
||||
state: present
|
||||
when: firewall_backend == "iptables"
|
||||
|
||||
- name: Allow forwarding to extra nets (iptables)
|
||||
community.general.iptables:
|
||||
table: filter
|
||||
chain: FORWARD
|
||||
in_interface: "{{ wg_interface }}"
|
||||
destination: "{{ item }}"
|
||||
jump: ACCEPT
|
||||
state: present
|
||||
loop: "{{ extra_nets }}"
|
||||
when: firewall_backend == "iptables"
|
||||
|
||||
- name: Allow return from extra nets (iptables)
|
||||
community.general.iptables:
|
||||
table: filter
|
||||
chain: FORWARD
|
||||
source: "{{ item }}"
|
||||
out_interface: "{{ wg_interface }}"
|
||||
ctstate: RELATED,ESTABLISHED
|
||||
jump: ACCEPT
|
||||
state: present
|
||||
loop: "{{ extra_nets }}"
|
||||
when: firewall_backend == "iptables"
|
||||
|
||||
- name: Deploy nftables WireGuard rules
|
||||
ansible.builtin.template:
|
||||
src: "{{ playbook_dir }}/../templates/wireguard-nftables.nft.j2"
|
||||
dest: "/etc/nftables.d/wireguard-{{ wg_interface }}.nft"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
when: firewall_backend == "nftables"
|
||||
notify: Reload nftables
|
||||
|
||||
- name: Ensure nftables main config includes WireGuard rules
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/nftables.conf
|
||||
regexp: '^include "/etc/nftables.d/wireguard-{{ wg_interface }}.nft";$'
|
||||
line: 'include "/etc/nftables.d/wireguard-{{ wg_interface }}.nft";'
|
||||
create: true
|
||||
when: firewall_backend == "nftables"
|
||||
notify: Reload nftables
|
||||
|
||||
- name: Manage UFW forward policy
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/default/ufw
|
||||
regexp: '^DEFAULT_FORWARD_POLICY='
|
||||
line: 'DEFAULT_FORWARD_POLICY="ACCEPT"'
|
||||
when: manage_ufw
|
||||
|
||||
- name: Allow WireGuard port in UFW
|
||||
community.general.ufw:
|
||||
rule: allow
|
||||
port: "{{ listening_port }}"
|
||||
proto: udp
|
||||
comment: "WireGuard VPN"
|
||||
when: manage_ufw
|
||||
|
||||
- name: Allow routed traffic via UFW (wg -> wan)
|
||||
ansible.builtin.command:
|
||||
cmd: "ufw route allow in on {{ wg_interface }} out on {{ wan_interface }} to any"
|
||||
register: ufw_route_result
|
||||
changed_when: "'Skipping' not in ufw_route_result.stdout"
|
||||
when: manage_ufw
|
||||
|
||||
- name: Allow extra nets via UFW
|
||||
ansible.builtin.command:
|
||||
cmd: "ufw route allow in on {{ wg_interface }} to {{ item }}"
|
||||
loop: "{{ extra_nets }}"
|
||||
register: ufw_extra_result
|
||||
changed_when: "'Skipping' not in ufw_extra_result.stdout"
|
||||
when: manage_ufw
|
||||
|
||||
- name: Allow WireGuard port in firewalld
|
||||
ansible.posix.firewalld:
|
||||
zone: "{{ firewalld_zone }}"
|
||||
port: "{{ listening_port }}/udp"
|
||||
permanent: true
|
||||
state: enabled
|
||||
when: manage_firewalld
|
||||
|
||||
- name: Enable firewalld masquerade
|
||||
ansible.posix.firewalld:
|
||||
zone: "{{ firewalld_zone }}"
|
||||
masquerade: true
|
||||
permanent: true
|
||||
state: enabled
|
||||
when: manage_firewalld
|
||||
|
||||
- name: Allow forwarding from WireGuard via firewalld
|
||||
ansible.posix.firewalld:
|
||||
permanent: true
|
||||
state: enabled
|
||||
immediate: false
|
||||
rich_rule: 'rule family="ipv4" source address="{{ wg_net }}" accept'
|
||||
when: manage_firewalld
|
||||
|
||||
- name: Allow extra nets via firewalld
|
||||
ansible.posix.firewalld:
|
||||
permanent: true
|
||||
state: enabled
|
||||
immediate: false
|
||||
rich_rule: 'rule family="ipv4" source address="{{ item }}" accept'
|
||||
loop: "{{ extra_nets }}"
|
||||
when: manage_firewalld
|
||||
|
||||
- name: Ensure wg-quick service enabled and restarted
|
||||
ansible.builtin.systemd:
|
||||
name: "wg-quick@{{ wg_interface }}"
|
||||
enabled: true
|
||||
state: restarted
|
||||
|
||||
- name: Show WireGuard status
|
||||
ansible.builtin.command: "wg show {{ wg_interface }}"
|
||||
register: wg_status
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Render routing summary
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
WireGuard routing updated for {{ wg_interface }}
|
||||
{{ wg_status.stdout }}
|
||||
|
||||
handlers:
|
||||
- name: Reload nftables
|
||||
ansible.builtin.command: nft -f /etc/nftables.conf
|
||||
156
deployment/ansible/scripts/setup-wireguard-routing.sh
Executable file
156
deployment/ansible/scripts/setup-wireguard-routing.sh
Executable file
@@ -0,0 +1,156 @@
|
||||
#!/usr/bin/env bash
|
||||
# setup-wireguard-routing.sh
|
||||
# Idempotent WireGuard split-tunnel routing helper.
|
||||
# Detects iptables/nftables and optional UFW/Firewalld to configure forwarding + NAT.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
WAN_IF=${WAN_IF:-eth0}
|
||||
WG_IF=${WG_IF:-wg0}
|
||||
WG_NET=${WG_NET:-10.8.0.0/24}
|
||||
WG_ADDR=${WG_ADDR:-10.8.0.1/24}
|
||||
WG_PORT=${WG_PORT:-51820}
|
||||
EXTRA_NETS_DEFAULT="192.168.178.0/24 172.20.0.0/16"
|
||||
EXTRA_NETS="${EXTRA_NETS:-$EXTRA_NETS_DEFAULT}"
|
||||
FIREWALL_BACKEND=${FIREWALL_BACKEND:-auto}
|
||||
FIREWALLD_ZONE=${FIREWALLD_ZONE:-public}
|
||||
|
||||
read -r -a EXTRA_NETS_ARRAY <<< "${EXTRA_NETS}"
|
||||
|
||||
abort() {
|
||||
echo "Error: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
require_root() {
|
||||
if [[ "${EUID}" -ne 0 ]]; then
|
||||
abort "please run as root (sudo ./setup-wireguard-routing.sh)"
|
||||
fi
|
||||
}
|
||||
|
||||
detect_backend() {
|
||||
case "${FIREWALL_BACKEND}" in
|
||||
iptables|nftables) echo "${FIREWALL_BACKEND}"; return 0 ;;
|
||||
auto)
|
||||
if command -v nft >/dev/null 2>&1; then
|
||||
echo "nftables"; return 0
|
||||
fi
|
||||
if command -v iptables >/dev/null 2>&1; then
|
||||
echo "iptables"; return 0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
abort "no supported firewall backend found (install iptables or nftables)"
|
||||
}
|
||||
|
||||
ensure_sysctl() {
|
||||
local sysctl_file="/etc/sysctl.d/99-${WG_IF}-forward.conf"
|
||||
cat <<EOF > "${sysctl_file}"
|
||||
# Managed by setup-wireguard-routing.sh
|
||||
net.ipv4.ip_forward=1
|
||||
EOF
|
||||
sysctl -w net.ipv4.ip_forward=1 >/dev/null
|
||||
sysctl --system >/dev/null
|
||||
}
|
||||
|
||||
apply_iptables() {
|
||||
iptables -t nat -C POSTROUTING -s "${WG_NET}" -o "${WAN_IF}" -j MASQUERADE 2>/dev/null || \
|
||||
iptables -t nat -A POSTROUTING -s "${WG_NET}" -o "${WAN_IF}" -j MASQUERADE
|
||||
|
||||
iptables -C FORWARD -i "${WG_IF}" -s "${WG_NET}" -o "${WAN_IF}" -j ACCEPT 2>/dev/null || \
|
||||
iptables -A FORWARD -i "${WG_IF}" -s "${WG_NET}" -o "${WAN_IF}" -j ACCEPT
|
||||
|
||||
iptables -C FORWARD -o "${WG_IF}" -d "${WG_NET}" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \
|
||||
iptables -A FORWARD -o "${WG_IF}" -d "${WG_NET}" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||
|
||||
for net in "${EXTRA_NETS_ARRAY[@]}"; do
|
||||
[[ -z "${net}" ]] && continue
|
||||
iptables -C FORWARD -i "${WG_IF}" -d "${net}" -j ACCEPT 2>/dev/null || \
|
||||
iptables -A FORWARD -i "${WG_IF}" -d "${net}" -j ACCEPT
|
||||
iptables -C FORWARD -s "${net}" -o "${WG_IF}" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \
|
||||
iptables -A FORWARD -s "${net}" -o "${WG_IF}" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||
done
|
||||
}
|
||||
|
||||
apply_nftables() {
|
||||
local table="inet wireguard_${WG_IF}"
|
||||
nft list table ${table} >/dev/null 2>&1 || nft add table ${table}
|
||||
|
||||
nft list chain ${table} postrouting >/dev/null 2>&1 || \
|
||||
nft add chain ${table} postrouting '{ type nat hook postrouting priority srcnat; }'
|
||||
|
||||
nft list chain ${table} forward >/dev/null 2>&1 || \
|
||||
nft add chain ${table} forward '{ type filter hook forward priority filter; policy accept; }'
|
||||
|
||||
nft list chain ${table} postrouting | grep -q "oifname \"${WAN_IF}\" ip saddr ${WG_NET}" || \
|
||||
nft add rule ${table} postrouting oifname "${WAN_IF}" ip saddr ${WG_NET} masquerade
|
||||
|
||||
nft list chain ${table} forward | grep -q "iifname \"${WG_IF}\" ip saddr ${WG_NET}" || \
|
||||
nft add rule ${table} forward iifname "${WG_IF}" ip saddr ${WG_NET} counter accept
|
||||
|
||||
nft list chain ${table} forward | grep -q "oifname \"${WG_IF}\" ip daddr ${WG_NET}" || \
|
||||
nft add rule ${table} forward oifname "${WG_IF}" ip daddr ${WG_NET} ct state established,related counter accept
|
||||
|
||||
for net in "${EXTRA_NETS_ARRAY[@]}"; do
|
||||
[[ -z "${net}" ]] && continue
|
||||
nft list chain ${table} forward | grep -q "iifname \"${WG_IF}\" ip daddr ${net}" || \
|
||||
nft add rule ${table} forward iifname "${WG_IF}" ip daddr ${net} counter accept
|
||||
done
|
||||
}
|
||||
|
||||
configure_ufw() {
|
||||
if command -v ufw >/dev/null 2>&1 && ufw status | grep -iq "Status: active"; then
|
||||
sed -i 's/^DEFAULT_FORWARD_POLICY=.*/DEFAULT_FORWARD_POLICY="ACCEPT"/' /etc/default/ufw
|
||||
ufw allow "${WG_PORT}"/udp >/dev/null
|
||||
ufw route allow in on "${WG_IF}" out on "${WAN_IF}" to any >/dev/null 2>&1 || true
|
||||
for net in "${EXTRA_NETS_ARRAY[@]}"; do
|
||||
[[ -z "${net}" ]] && continue
|
||||
ufw route allow in on "${WG_IF}" to "${net}" >/dev/null 2>&1 || true
|
||||
done
|
||||
ufw reload >/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
configure_firewalld() {
|
||||
if command -v firewall-cmd >/dev/null 2>&1 && firewall-cmd --state >/dev/null 2>&1; then
|
||||
firewall-cmd --permanent --zone="${FIREWALLD_ZONE}" --add-port=${WG_PORT}/udp >/dev/null
|
||||
firewall-cmd --permanent --zone="${FIREWALLD_ZONE}" --add-masquerade >/dev/null
|
||||
firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 \
|
||||
"iif ${WG_IF} oif ${WAN_IF} -s ${WG_NET} -j ACCEPT" >/dev/null 2>&1 || true
|
||||
firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 \
|
||||
"oif ${WG_IF} -d ${WG_NET} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT" >/dev/null 2>&1 || true
|
||||
for net in "${EXTRA_NETS_ARRAY[@]}"; do
|
||||
[[ -z "${net}" ]] && continue
|
||||
firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 \
|
||||
"iif ${WG_IF} -d ${net} -j ACCEPT" >/dev/null 2>&1 || true
|
||||
done
|
||||
firewall-cmd --reload >/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_service() {
|
||||
systemctl enable "wg-quick@${WG_IF}" >/dev/null
|
||||
systemctl restart "wg-quick@${WG_IF}"
|
||||
}
|
||||
|
||||
show_status() {
|
||||
echo "WireGuard routing configured with ${WG_IF} (${WG_ADDR}) via ${WAN_IF}"
|
||||
wg show "${WG_IF}" || true
|
||||
ip route show table main | grep "${WG_NET}" || true
|
||||
}
|
||||
|
||||
main() {
|
||||
require_root
|
||||
ensure_sysctl
|
||||
backend=$(detect_backend)
|
||||
case "${backend}" in
|
||||
iptables) apply_iptables ;;
|
||||
nftables) apply_nftables ;;
|
||||
esac
|
||||
configure_ufw
|
||||
configure_firewalld
|
||||
ensure_service
|
||||
show_status
|
||||
}
|
||||
|
||||
main "$@"
|
||||
50
deployment/ansible/templates/wg0.conf.j2
Normal file
50
deployment/ansible/templates/wg0.conf.j2
Normal file
@@ -0,0 +1,50 @@
|
||||
# WireGuard Server Configuration
|
||||
# Interface: wg0
|
||||
# Network: {{ wg_network }}
|
||||
# Server IP: {{ wg_server_ip }}
|
||||
|
||||
[Interface]
|
||||
PrivateKey = {{ wg_server_private_key }}
|
||||
Address = {{ wg_server_ip }}/{{ wg_netmask }}
|
||||
ListenPort = {{ wg_port | default(51820) }}
|
||||
|
||||
# Enable IP forwarding for VPN routing
|
||||
PostUp = sysctl -w net.ipv4.ip_forward=1
|
||||
|
||||
# nftables: Setup VPN routing and firewall
|
||||
PostUp = nft add table inet wireguard
|
||||
PostUp = nft add chain inet wireguard postrouting { type nat hook postrouting priority srcnat\; }
|
||||
PostUp = nft add chain inet wireguard forward { type filter hook forward priority filter\; }
|
||||
|
||||
# NAT for VPN traffic (masquerade to WAN)
|
||||
PostUp = nft add rule inet wireguard postrouting oifname "{{ wan_interface }}" ip saddr {{ wg_network }} masquerade
|
||||
|
||||
# Allow VPN traffic forwarding
|
||||
PostUp = nft add rule inet wireguard forward iifname "wg0" ip saddr {{ wg_network }} accept
|
||||
PostUp = nft add rule inet wireguard forward oifname "wg0" ip daddr {{ wg_network }} ct state established,related accept
|
||||
|
||||
# Cleanup on shutdown
|
||||
PostDown = nft delete table inet wireguard
|
||||
|
||||
# Peers (automatically managed)
|
||||
# Format:
|
||||
# [Peer]
|
||||
# # Description: device-name
|
||||
# PublicKey = peer_public_key
|
||||
# PresharedKey = peer_preshared_key
|
||||
# AllowedIPs = 10.8.0.X/32
|
||||
# PersistentKeepalive = 25 # Optional: for clients behind NAT
|
||||
|
||||
{% for peer in wg_peers | default([]) %}
|
||||
[Peer]
|
||||
# {{ peer.name }}
|
||||
PublicKey = {{ peer.public_key }}
|
||||
{% if peer.preshared_key is defined %}
|
||||
PresharedKey = {{ peer.preshared_key }}
|
||||
{% endif %}
|
||||
AllowedIPs = {{ peer.allowed_ips }}
|
||||
{% if peer.persistent_keepalive | default(true) %}
|
||||
PersistentKeepalive = 25
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
@@ -1,29 +0,0 @@
|
||||
# WireGuard Client Configuration for {{ client_name }}
|
||||
# Generated by Ansible - DO NOT EDIT MANUALLY
|
||||
|
||||
[Interface]
|
||||
# Client private key
|
||||
PrivateKey = {{ client_private_key.stdout }}
|
||||
|
||||
# Client IP address in VPN network
|
||||
Address = {{ client_ip }}/24
|
||||
|
||||
{% if wireguard_dns_servers | length > 0 %}
|
||||
# DNS servers provided via Ansible (optional)
|
||||
DNS = {{ wireguard_dns_servers | join(', ') }}
|
||||
{% endif %}
|
||||
|
||||
[Peer]
|
||||
# Server public key
|
||||
PublicKey = {{ server_public_key_cmd.stdout }}
|
||||
|
||||
# Server endpoint
|
||||
Endpoint = {{ server_external_ip_content }}:{{ wireguard_port }}
|
||||
|
||||
# Allowed IPs (routes through VPN)
|
||||
# IMPORTANT: Only VPN network is routed through VPN by default
|
||||
# SSH access via normal IP ({{ server_external_ip_content }}) remains available
|
||||
AllowedIPs = {{ allowed_ips }}
|
||||
|
||||
# Keep connection alive
|
||||
PersistentKeepalive = 25
|
||||
116
deployment/ansible/templates/wireguard-host-firewall.nft.j2
Normal file
116
deployment/ansible/templates/wireguard-host-firewall.nft.j2
Normal file
@@ -0,0 +1,116 @@
|
||||
#!/usr/sbin/nft -f
|
||||
# WireGuard VPN Firewall Rules
|
||||
# Purpose: Isolate admin services behind VPN, allow public access only to ports 80, 443, 22
|
||||
# Generated by Ansible - DO NOT EDIT MANUALLY
|
||||
|
||||
table inet wireguard_firewall {
|
||||
# Define sets for easy management
|
||||
set vpn_network {
|
||||
type ipv4_addr
|
||||
flags interval
|
||||
elements = { {{ wg_network }} }
|
||||
}
|
||||
|
||||
set admin_service_ports {
|
||||
type inet_service
|
||||
elements = {
|
||||
8080, # Traefik Dashboard
|
||||
9090, # Prometheus
|
||||
3001, # Grafana
|
||||
9000, # Portainer
|
||||
8001, # Redis Insight
|
||||
{% for port in additional_admin_ports | default([]) %}
|
||||
{{ port }}, # {{ port }}
|
||||
{% endfor %}
|
||||
}
|
||||
}
|
||||
|
||||
set public_service_ports {
|
||||
type inet_service
|
||||
elements = {
|
||||
80, # HTTP
|
||||
443, # HTTPS
|
||||
22, # SSH
|
||||
{% for port in additional_public_ports | default([]) %}
|
||||
{{ port }}, # {{ port }}
|
||||
{% endfor %}
|
||||
}
|
||||
}
|
||||
|
||||
# Input chain - Handle incoming traffic
|
||||
chain input {
|
||||
type filter hook input priority filter; policy drop;
|
||||
|
||||
# Allow established/related connections
|
||||
ct state established,related accept
|
||||
|
||||
# Allow loopback
|
||||
iifname "lo" accept
|
||||
|
||||
# Allow ICMP (ping)
|
||||
ip protocol icmp accept
|
||||
ip6 nexthdr icmpv6 accept
|
||||
|
||||
# Allow SSH (public)
|
||||
tcp dport 22 accept
|
||||
|
||||
# Allow WireGuard port (public)
|
||||
udp dport {{ wg_port | default(51820) }} accept comment "WireGuard VPN"
|
||||
|
||||
# Allow public web services (HTTP/HTTPS)
|
||||
tcp dport @public_service_ports accept comment "Public services"
|
||||
|
||||
# Allow VPN network to access admin services
|
||||
ip saddr @vpn_network tcp dport @admin_service_ports accept comment "VPN admin access"
|
||||
|
||||
# Block public access to admin services
|
||||
tcp dport @admin_service_ports counter log prefix "BLOCKED_ADMIN_SERVICE: " drop
|
||||
|
||||
# Log and drop all other traffic
|
||||
counter log prefix "BLOCKED_INPUT: " drop
|
||||
}
|
||||
|
||||
# Forward chain - Handle routed traffic (VPN to services)
|
||||
chain forward {
|
||||
type filter hook forward priority filter; policy drop;
|
||||
|
||||
# Allow established/related connections
|
||||
ct state established,related accept
|
||||
|
||||
# Allow VPN clients to access local services
|
||||
iifname "wg0" ip saddr @vpn_network accept comment "VPN to services"
|
||||
|
||||
# Allow return traffic to VPN clients
|
||||
oifname "wg0" ip daddr @vpn_network ct state established,related accept
|
||||
|
||||
# Log and drop all other forwarded traffic
|
||||
counter log prefix "BLOCKED_FORWARD: " drop
|
||||
}
|
||||
|
||||
# Output chain - Allow all outgoing traffic
|
||||
chain output {
|
||||
type filter hook output priority filter; policy accept;
|
||||
}
|
||||
|
||||
# NAT chain - Masquerade VPN traffic to WAN
|
||||
chain postrouting {
|
||||
type nat hook postrouting priority srcnat;
|
||||
|
||||
# Masquerade VPN traffic going to WAN
|
||||
oifname "{{ wan_interface }}" ip saddr @vpn_network masquerade comment "VPN NAT"
|
||||
}
|
||||
}
|
||||
|
||||
# Optional: Rate limiting for VPN port (DDoS protection)
|
||||
{% if wg_enable_rate_limit | default(true) %}
|
||||
table inet wireguard_ratelimit {
|
||||
chain input {
|
||||
type filter hook input priority -10;
|
||||
|
||||
# Rate limit WireGuard port: 10 connections per second per IP
|
||||
udp dport {{ wg_port | default(51820) }} \
|
||||
meter vpn_ratelimit { ip saddr limit rate over 10/second } \
|
||||
counter log prefix "VPN_RATELIMIT: " drop
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
15
deployment/ansible/templates/wireguard-nftables.nft.j2
Normal file
15
deployment/ansible/templates/wireguard-nftables.nft.j2
Normal file
@@ -0,0 +1,15 @@
|
||||
table inet wireguard_{{ wg_interface }} {
|
||||
chain postrouting {
|
||||
type nat hook postrouting priority srcnat;
|
||||
oifname "{{ wan_interface }}" ip saddr {{ wg_net }} masquerade
|
||||
}
|
||||
|
||||
chain forward {
|
||||
type filter hook forward priority filter;
|
||||
iifname "{{ wg_interface }}" ip saddr {{ wg_net }} counter accept
|
||||
oifname "{{ wg_interface }}" ip daddr {{ wg_net }} ct state established,related counter accept
|
||||
{% for net in extra_nets %}
|
||||
iifname "{{ wg_interface }}" ip daddr {{ net }} counter accept
|
||||
{% endfor %}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
# WireGuard Server Configuration
|
||||
# Generated by Ansible - DO NOT EDIT MANUALLY
|
||||
|
||||
[Interface]
|
||||
# Server private key
|
||||
PrivateKey = {{ server_private_key_for_config }}
|
||||
|
||||
# Server IP address in VPN network
|
||||
Address = {{ wireguard_server_ip }}/24
|
||||
|
||||
# Port to listen on
|
||||
ListenPort = {{ wireguard_port }}
|
||||
|
||||
# Enable NAT for VPN clients to access internet
|
||||
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o {{ wireguard_interface_name }} -j MASQUERADE
|
||||
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o {{ wireguard_interface_name }} -j MASQUERADE
|
||||
|
||||
# Clients will be added here by the add-wireguard-client playbook
|
||||
# Example:
|
||||
# [Peer]
|
||||
# PublicKey = <client_public_key>
|
||||
# AllowedIPs = 10.8.0.2/32
|
||||
14
deployment/ansible/wireguard/configs/michael-pc.conf
Normal file
14
deployment/ansible/wireguard/configs/michael-pc.conf
Normal file
@@ -0,0 +1,14 @@
|
||||
[Interface]
|
||||
# Client: michael-pc
|
||||
# Generated: 2025-11-05T01:02:14Z
|
||||
PrivateKey = MHgxUzmEHQ15EB3v4TaXEcJAZNRaBd54/ZDcN6nN8lI=
|
||||
Address = 10.8.0.2/32
|
||||
DNS = 1.1.1.1, 8.8.8.8
|
||||
|
||||
[Peer]
|
||||
# WireGuard Server
|
||||
PublicKey = SFxxHe4bunfQ1Xid5AMXbBgY+AjlxNtRHQ5uYjSib3E=
|
||||
PresharedKey = WsnvFp6WrF/y9fQwn3RgOTmwMS2UHoqIBRKrTPZ5lW8=
|
||||
Endpoint = 94.16.110.151:51820
|
||||
AllowedIPs = 10.8.0.0/24
|
||||
PersistentKeepalive = 25
|
||||
Reference in New Issue
Block a user