added scripts for vpn
This commit is contained in:
@@ -49,6 +49,7 @@
|
|||||||
dest: /etc/modules-load.d/wg-easy.conf
|
dest: /etc/modules-load.d/wg-easy.conf
|
||||||
content: |
|
content: |
|
||||||
wireguard
|
wireguard
|
||||||
|
nft_masq
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
|
|
||||||
- name: Enable IP forwarding on host
|
- name: Enable IP forwarding on host
|
||||||
@@ -146,17 +147,18 @@
|
|||||||
# - 7359:7359/udp #optional
|
# - 7359:7359/udp #optional
|
||||||
# - 1900:1900/udp #optional
|
# - 1900:1900/udp #optional
|
||||||
|
|
||||||
# WireGuard Easy VPN — deployed on npm_internal behind NPM
|
# WireGuard Easy VPN (v15) — UI at 10.10.0.36:51821 on npm_internal, fronted by NPM
|
||||||
# After first deploy, you MUST add NAT hooks in the wg-easy UI:
|
# (vpn.boxswapper.io -> http://10.10.0.36:51821). Login: admin / wireguard_ui_password from vars.yml.
|
||||||
# 1. Open http://10.10.0.36:51821 in a browser
|
# v15 init is ONE-TIME: the INIT_* envs below are consumed only when /etc/wireguard/wg-easy.db is ABSENT.
|
||||||
# 2. Log in with the username/password from vars.yml
|
# Force a re-init (wipes clients + server keys): podman rm -f wg-easy && rm -rf /opt/apps/wireguard, then re-run.
|
||||||
# 3. Go to the "Hooks" tab
|
# NAT from VPN clients to LAN/apps (10.10.1.0/24 -> 10.10.0.0/24) uses NFTABLES hooks —
|
||||||
# 4. PostUp — paste this EXACTLY:
|
# wg-easy's iptables-legacy hooks cannot init the nat table inside a podman netns
|
||||||
# nft add table inet wg_table; nft add chain inet wg_table prerouting { type nat hook prerouting priority 100 \; }; nft add chain inet wg_table postrouting { type nat hook postrouting priority 100 \; }; nft add rule inet wg_table postrouting ip saddr {{ipv4Cidr}} oifname {{device}} masquerade; nft add rule inet wg_table postrouting ip6 saddr {{ipv6Cidr}} oifname {{device}} masquerade; nft add chain inet wg_table input { type filter hook input priority 0 \; policy accept \; }; nft add rule inet wg_table input udp dport {{port}} accept; nft add rule inet wg_table input tcp dport {{uiPort}} accept; nft add chain inet wg_table forward { type filter hook forward priority 0 \; policy accept \; }; nft add rule inet wg_table forward iifname "wg0" accept; nft add rule inet wg_table forward oifname "wg0" accept;
|
# ("Table does not exist"), which makes wg-quick up fail and every client API call
|
||||||
# 5. PostDown — paste this EXACTLY:
|
# 500 with "Unable to access interface". scripts/patch-wg-hooks.py rewrites the hooks
|
||||||
# nft delete table inet wg_table
|
# to nft rules and the tasks below restart wg-easy to apply them. See the official
|
||||||
# 6. Click Save and restart the container
|
# wg-easy "Podman + nftables" tutorial.
|
||||||
# These hooks enable VPN clients to reach your app containers (10.10.0.0/24)
|
# EXTERNAL ACCESS: router MUST forward UDP 51820 -> 192.168.0.98. Test from LTE,
|
||||||
|
# not your LAN — NAT hairpin breaks public-IP handshakes from inside the network.
|
||||||
- name: Deploy WireGuard Easy (wg-easy)
|
- name: Deploy WireGuard Easy (wg-easy)
|
||||||
containers.podman.podman_container:
|
containers.podman.podman_container:
|
||||||
name: wg-easy
|
name: wg-easy
|
||||||
@@ -190,10 +192,37 @@
|
|||||||
sysctl:
|
sysctl:
|
||||||
net.ipv4.ip_forward: "1"
|
net.ipv4.ip_forward: "1"
|
||||||
net.ipv4.conf.all.src_valid_mark: "1"
|
net.ipv4.conf.all.src_valid_mark: "1"
|
||||||
|
net.ipv6.conf.all.disable_ipv6: "0"
|
||||||
|
net.ipv6.conf.all.forwarding: "1"
|
||||||
|
net.ipv6.conf.default.forwarding: "1"
|
||||||
network:
|
network:
|
||||||
- npm_internal
|
- npm_internal
|
||||||
ip: '{{ wireguard_ip }}'
|
ip: '{{ wireguard_ip }}'
|
||||||
|
|
||||||
|
- name: Copy wg-easy hook repair script
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: ./scripts/patch-wg-hooks.py
|
||||||
|
dest: /opt/apps/wireguard/patch-wg-hooks.py
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Replace iptables hooks with nftables (iptables-legacy broken in podman)
|
||||||
|
ansible.builtin.command: python3 /opt/apps/wireguard/patch-wg-hooks.py
|
||||||
|
register: wg_hooks_patch
|
||||||
|
changed_when: "'patched hooks' in wg_hooks_patch.stdout"
|
||||||
|
|
||||||
|
- name: Restart wg-easy to apply nft hooks
|
||||||
|
ansible.builtin.command: podman restart wg-easy
|
||||||
|
when: "'patched hooks' in wg_hooks_patch.stdout"
|
||||||
|
|
||||||
|
- name: Wait for WireGuard Easy web UI
|
||||||
|
ansible.builtin.wait_for:
|
||||||
|
host: '{{ wireguard_ip }}'
|
||||||
|
port: '{{ wireguard_ui_port }}'
|
||||||
|
delay: 5
|
||||||
|
timeout: 120
|
||||||
|
|
||||||
# Wazuh SIEM (single-node: indexer + manager + dashboard) on npm_internal
|
# Wazuh SIEM (single-node: indexer + manager + dashboard) on npm_internal
|
||||||
# Dashboard is NOT exposed on host ports — NPM proxies wazuh.boxswapper.io to https://10.10.0.40:5601
|
# Dashboard is NOT exposed on host ports — NPM proxies wazuh.boxswapper.io to https://10.10.0.40:5601
|
||||||
# DNS record must be grey-cloud (Cloudflare 523 lesson from vpn.boxswapper.io), cert via NPM
|
# DNS record must be grey-cloud (Cloudflare 523 lesson from vpn.boxswapper.io), cert via NPM
|
||||||
|
|||||||
60
scripts/patch-wg-hooks.py
Normal file
60
scripts/patch-wg-hooks.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Replace wg-easy iptables hooks with nftables equivalents.
|
||||||
|
|
||||||
|
wg-easy images ship iptables-legacy, which cannot initialize the `nat`/`filter`
|
||||||
|
tables inside a podman container netns on nftables-only kernels (fc42). Every
|
||||||
|
`wg-quick up wg0` then fails at the PostUp hook, so the wg0 interface is rolled
|
||||||
|
back and ALL client API calls 500 with "Unable to access interface: No such device".
|
||||||
|
|
||||||
|
The official wg-easy podman+nftables tutorial replaces the hooks with nft rules.
|
||||||
|
This script rewrites hooks_table in /opt/apps/wireguard/wg-easy.db when the hooks
|
||||||
|
still reference iptables. Run it with the wg-easy container stopped, then restart
|
||||||
|
the container so wg0.conf is regenerated. Idempotent.
|
||||||
|
"""
|
||||||
|
import sqlite3
|
||||||
|
import sys
|
||||||
|
|
||||||
|
DB = "/opt/apps/wireguard/wg-easy.db"
|
||||||
|
|
||||||
|
POSTUP = (
|
||||||
|
"nft add table inet wg_table;"
|
||||||
|
" nft add chain inet wg_table prerouting { type nat hook prerouting priority 100 \\; };"
|
||||||
|
" nft add chain inet wg_table postrouting { type nat hook postrouting priority 100 \\; };"
|
||||||
|
" nft add rule inet wg_table postrouting ip saddr {{ipv4Cidr}} oifname {{device}} masquerade;"
|
||||||
|
" nft add rule inet wg_table postrouting ip6 saddr {{ipv6Cidr}} oifname {{device}} masquerade;"
|
||||||
|
" nft add chain inet wg_table input { type filter hook input priority 0 \\; policy accept \\; };"
|
||||||
|
" nft add rule inet wg_table input udp dport {{port}} accept;"
|
||||||
|
" nft add rule inet wg_table input tcp dport {{uiPort}} accept;"
|
||||||
|
" nft add chain inet wg_table forward { type filter hook forward priority 0 \\; policy accept \\; };"
|
||||||
|
' nft add rule inet wg_table forward iifname "wg0" accept;'
|
||||||
|
' nft add rule inet wg_table forward oifname "wg0" accept;'
|
||||||
|
)
|
||||||
|
POSTDOWN = "nft delete table inet wg_table"
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
con = sqlite3.connect(DB)
|
||||||
|
try:
|
||||||
|
rows = con.execute("SELECT id, post_up, post_down FROM hooks_table").fetchall()
|
||||||
|
changed = 0
|
||||||
|
for name, post_up, post_down in rows:
|
||||||
|
post_up = post_up or ""
|
||||||
|
post_down = post_down or ""
|
||||||
|
if "iptables" in post_up or "iptables" in post_down:
|
||||||
|
con.execute(
|
||||||
|
"UPDATE hooks_table SET post_up=?, post_down=?, updated_at=CURRENT_TIMESTAMP WHERE id=?",
|
||||||
|
(POSTUP, POSTDOWN, name),
|
||||||
|
)
|
||||||
|
print(f"patched hooks for {name!r}")
|
||||||
|
changed += 1
|
||||||
|
else:
|
||||||
|
print(f"hooks ok for {name!r}")
|
||||||
|
con.commit()
|
||||||
|
finally:
|
||||||
|
con.close()
|
||||||
|
print(f"changed={changed}")
|
||||||
|
return 0 if changed >= 0 else 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
4
vars.yml
4
vars.yml
@@ -46,9 +46,9 @@ POSTGRES_DB: thatoneit
|
|||||||
## IMPORTANT: After first run, change wireguard_ui_password to a strong password
|
## IMPORTANT: After first run, change wireguard_ui_password to a strong password
|
||||||
## Public IP or DDNS hostname clients connect to — CHANGE THIS before deploying
|
## Public IP or DDNS hostname clients connect to — CHANGE THIS before deploying
|
||||||
wireguard_image: ghcr.io/wg-easy/wg-easy:15
|
wireguard_image: ghcr.io/wg-easy/wg-easy:15
|
||||||
wireguard_host: CHANGE_ME
|
wireguard_host: vpn.boxswapper.io
|
||||||
wireguard_ui_username: admin
|
wireguard_ui_username: admin
|
||||||
wireguard_ui_password: CHANGE_ME
|
wireguard_ui_password: T3l0penF@5tback
|
||||||
wireguard_port: 51820
|
wireguard_port: 51820
|
||||||
wireguard_ui_port: 51821
|
wireguard_ui_port: 51821
|
||||||
wireguard_cidr: 10.10.1.0/24
|
wireguard_cidr: 10.10.1.0/24
|
||||||
|
|||||||
Reference in New Issue
Block a user