From f8dbd625968e3289b477707fc80682e679df0f96 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Wed, 25 Mar 2026 20:07:42 -0300 Subject: [PATCH] add "auto apply" for wireguard peers and dns entries --- .env.example | 5 +++++ dns/views.py | 20 ++++++++++++++---- docker-compose-caddy.yml | 1 + docker-compose-dev.yml | 1 + docker-compose-no-caddy.yml | 1 + entrypoint.sh | 4 ++++ wireguard_peer/views.py | 38 +++++++++++++++++++++++++--------- wireguard_webadmin/settings.py | 4 +++- 8 files changed, 59 insertions(+), 15 deletions(-) diff --git a/.env.example b/.env.example index ef80448..27bb3e8 100644 --- a/.env.example +++ b/.env.example @@ -25,6 +25,11 @@ TIMEZONE=America/Sao_Paulo # Example: EXTRA_ALLOWED_HOSTS=app1.example.com,app2.example.com:8443,app3.example.com #EXTRA_ALLOWED_HOSTS=app1.example.com,app2.example.com:8443,app3.example.com +# Disable automatic apply of WireGuard and DNS configuration changes. +# By default, changes to peers and DNS are applied immediately without requiring manual intervention. +# Set to true if you prefer to apply changes manually. +# DISABLE_AUTO_APPLY=true + # Set a custom MTU for WireGuard interfaces (server and client configs). # Only change this if you know what you are doing. The default WireGuard MTU (1420) works for most setups. # Must be an integer between 1280 and 9000. diff --git a/dns/views.py b/dns/views.py index 192c516..092628a 100644 --- a/dns/views.py +++ b/dns/views.py @@ -18,6 +18,14 @@ from .models import DNSFilterList, DNSSettings from .models import StaticHost +def _auto_apply_dns(request): + if not settings.AUTO_APPLY: + return False + export_dns_configuration() + messages.info(request, _('DNS configuration reloaded automatically.')) + return True + + def detect_list_format(content): for line in content.splitlines(): line = line.strip() @@ -129,9 +137,10 @@ def view_manage_static_host(request): if request.GET.get('action') == 'delete': if request.GET.get('confirmation') == 'delete': static_dns.delete() - dns_settings.pending_changes = True - dns_settings.save() messages.success(request, _('Static DNS deleted successfully')) + if not _auto_apply_dns(request): + dns_settings.pending_changes = True + dns_settings.save() return redirect('/dns/') else: messages.warning(request, _('Static DNS not deleted|Invalid confirmation')) @@ -142,9 +151,10 @@ def view_manage_static_host(request): form = StaticHostForm(request.POST or None, instance=static_dns) if form.is_valid(): form.save() - dns_settings.pending_changes = True - dns_settings.save() messages.success(request, _('Static DNS saved successfully')) + if not _auto_apply_dns(request): + dns_settings.pending_changes = True + dns_settings.save() return redirect('/dns/') context = { @@ -305,6 +315,7 @@ def view_toggle_dns_list(request): dns_list.save() export_dns_configuration() messages.success(request, _('DNS Filter List enabled successfully')) + messages.info(request, _('DNS configuration reloaded automatically.')) else: messages.error(request, _('DNS Filter List not enabled | No valid hosts found')) else: @@ -312,4 +323,5 @@ def view_toggle_dns_list(request): dns_list.save() export_dns_configuration() messages.success(request, _('DNS Filter List disabled successfully')) + messages.info(request, _('DNS configuration reloaded automatically.')) return redirect('/dns/') diff --git a/docker-compose-caddy.yml b/docker-compose-caddy.yml index 3a3af73..3921f0f 100644 --- a/docker-compose-caddy.yml +++ b/docker-compose-caddy.yml @@ -15,6 +15,7 @@ services: - WIREGUARD_STATUS_CACHE_REFRESH_INTERVAL=${WIREGUARD_STATUS_CACHE_REFRESH_INTERVAL} - VPN_CLIENTS_CAN_ACCESS_DJANGO=${VPN_CLIENTS_CAN_ACCESS_DJANGO} - WIREGUARD_MTU=${WIREGUARD_MTU} + - DISABLE_AUTO_APPLY=${DISABLE_AUTO_APPLY} - CADDY_ENABLED=true volumes: - wireguard:/etc/wireguard diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 6e69b83..622d3e6 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -17,6 +17,7 @@ services: - WIREGUARD_STATUS_CACHE_REFRESH_INTERVAL=${WIREGUARD_STATUS_CACHE_REFRESH_INTERVAL} - VPN_CLIENTS_CAN_ACCESS_DJANGO=${VPN_CLIENTS_CAN_ACCESS_DJANGO} - WIREGUARD_MTU=${WIREGUARD_MTU} + - DISABLE_AUTO_APPLY=${DISABLE_AUTO_APPLY} - CADDY_ENABLED=true volumes: - wireguard:/etc/wireguard diff --git a/docker-compose-no-caddy.yml b/docker-compose-no-caddy.yml index fedd10a..f8a654d 100644 --- a/docker-compose-no-caddy.yml +++ b/docker-compose-no-caddy.yml @@ -15,6 +15,7 @@ services: - WIREGUARD_STATUS_CACHE_REFRESH_INTERVAL=${WIREGUARD_STATUS_CACHE_REFRESH_INTERVAL} - VPN_CLIENTS_CAN_ACCESS_DJANGO=${VPN_CLIENTS_CAN_ACCESS_DJANGO} - WIREGUARD_MTU=${WIREGUARD_MTU} + - DISABLE_AUTO_APPLY=${DISABLE_AUTO_APPLY} volumes: - wireguard:/etc/wireguard - static_volume:/app_static_files/ diff --git a/entrypoint.sh b/entrypoint.sh index b553a04..95145e2 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -73,6 +73,10 @@ if [ -n "${WIREGUARD_STATUS_CACHE_REFRESH_INTERVAL:-}" ]; then esac fi +if [[ "${DISABLE_AUTO_APPLY,,}" == "true" ]]; then + echo "AUTO_APPLY = False" >> /app/wireguard_webadmin/production_settings.py +fi + if [ -n "${WIREGUARD_MTU:-}" ]; then if [[ "${WIREGUARD_MTU}" =~ ^[0-9]+$ ]] && [ "${WIREGUARD_MTU}" -ge 1280 ] && [ "${WIREGUARD_MTU}" -le 9000 ]; then echo "WIREGUARD_MTU = ${WIREGUARD_MTU}" >> /app/wireguard_webadmin/production_settings.py diff --git a/wireguard_peer/views.py b/wireguard_peer/views.py index 8c5ccd3..2df1731 100644 --- a/wireguard_peer/views.py +++ b/wireguard_peer/views.py @@ -20,6 +20,18 @@ from wireguard_tools.views import export_wireguard_configuration from .functions import func_create_new_peer +def _auto_apply(request, instance): + if not settings.AUTO_APPLY: + return False + export_wireguard_configuration(instance) + success, message = func_reload_wireguard_interface(instance) + if success: + messages.info(request, _('wg%(id)s reloaded automatically.') % {'id': instance.instance_id}) + else: + messages.warning(request, _('Auto-apply failed for wg%(id)s: ') % {'id': instance.instance_id} + message) + return True + + @login_required def view_wireguard_peer_list(request): user_acl = get_object_or_404(UserAcl, user=request.user) @@ -148,8 +160,9 @@ def view_wireguard_peer_create(request): new_peer, message = func_create_new_peer(current_instance) if new_peer: messages.success(request, _('Peer created|Peer created successfully.')) - new_peer.wireguard_instance.pending_changes = True - new_peer.wireguard_instance.save() + if not _auto_apply(request, new_peer.wireguard_instance): + new_peer.wireguard_instance.pending_changes = True + new_peer.wireguard_instance.save() return redirect('/peer/manage/?peer=' + str(new_peer.uuid)) else: messages.warning(request, message) @@ -173,10 +186,11 @@ def view_wireguard_peer_manage(request): if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=30).exists(): return render(request, 'access_denied.html', {'page_title': 'Access Denied'}) if request.GET.get('confirmation') == 'delete': - current_peer.wireguard_instance.pending_changes = True - current_peer.wireguard_instance.save() current_peer.delete() messages.success(request, _('Peer deleted|Peer deleted successfully.')) + if not _auto_apply(request, current_instance): + current_instance.pending_changes = True + current_instance.save() return redirect('/peer/list/?uuid=' + str(current_instance.uuid)) else: messages.warning(request, _('Error deleting peer|Invalid confirmation message. Type "delete" to confirm.')) @@ -224,8 +238,9 @@ def view_wireguard_peer_edit_field(request): form = FormClass(request.POST or None, instance=current_peer) if form.is_valid(): form.save() - current_peer.wireguard_instance.pending_changes = True - current_peer.wireguard_instance.save() + if group != 'name' and not _auto_apply(request, current_peer.wireguard_instance): + current_peer.wireguard_instance.pending_changes = True + current_peer.wireguard_instance.save() messages.success(request, _('Peer updated|Peer updated successfully.')) return redirect('/peer/manage/?peer=' + str(current_peer.uuid)) @@ -266,10 +281,12 @@ def view_manage_ip_address(request): if request.GET.get('action') == 'delete': if request.GET.get('confirmation') == 'delete': + is_server_side = current_ip.config_file == 'server' current_ip.delete() messages.success(request, _('IP address deleted|IP address deleted successfully.')) - current_peer.wireguard_instance.pending_changes = True - current_peer.wireguard_instance.save() + if is_server_side and not _auto_apply(request, current_peer.wireguard_instance): + current_peer.wireguard_instance.pending_changes = True + current_peer.wireguard_instance.save() return redirect('/peer/manage/?peer=' + str(current_peer.uuid)) else: messages.warning(request, _('Error deleting IP address|Invalid confirmation message. Type "delete" to confirm.')) @@ -289,8 +306,9 @@ def view_manage_ip_address(request): this_form.peer = current_peer this_form.config_file = config_file this_form.save() - current_peer.wireguard_instance.pending_changes = True - current_peer.wireguard_instance.save() + if config_file == 'server' and not _auto_apply(request, current_peer.wireguard_instance): + current_peer.wireguard_instance.pending_changes = True + current_peer.wireguard_instance.save() if current_ip: messages.success(request, _('IP address updated|IP address updated successfully.')) else: diff --git a/wireguard_webadmin/settings.py b/wireguard_webadmin/settings.py index 6a27373..05effa1 100644 --- a/wireguard_webadmin/settings.py +++ b/wireguard_webadmin/settings.py @@ -174,7 +174,7 @@ WIREGUARD_STATUS_CACHE_WEB_LOAD_PREVIOUS_COUNT = 9 DNS_CONFIG_FILE = '/etc/dnsmasq/wireguard_webadmin_dns.conf' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' -WIREGUARD_WEBADMIN_VERSION = 9978 +WIREGUARD_WEBADMIN_VERSION = 9979 CLUSTER_WORKER_CURRENT_VERSION = 11 CLUSTER_WORKER_MINIMUM_VERSION = 11 @@ -183,4 +183,6 @@ CADDY_ENABLED = os.getenv("CADDY_ENABLED", "false").lower() == "true" WIREGUARD_MTU = None +AUTO_APPLY = True + from wireguard_webadmin.production_settings import *