mirror of
https://github.com/eduardogsilva/wireguard_webadmin.git
synced 2025-04-19 00:45:16 +00:00
DNS Container and docker compose
This commit is contained in:
parent
da1513e560
commit
aefd3f698b
@ -4,6 +4,7 @@ IMAGES=(
|
||||
"eduardosilva/wireguard_webadmin:latest"
|
||||
"eduardosilva/wireguard_webadmin_cron:latest"
|
||||
"eduardosilva/wireguard_webadmin_nginx:latest"
|
||||
"eduardosilva/wireguard_webadmin_dns:latest"
|
||||
)
|
||||
|
||||
build_images() {
|
||||
|
13
containers/dnsmasq/Dockerfile-dnsmasq
Normal file
13
containers/dnsmasq/Dockerfile-dnsmasq
Normal file
@ -0,0 +1,13 @@
|
||||
FROM ubuntu:latest
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y dnsmasq nano inotify-tools psmisc && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
40
containers/dnsmasq/entrypoint.sh
Normal file
40
containers/dnsmasq/entrypoint.sh
Normal file
@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
CONFIG_FILE="/etc/dnsmasq/wireguard_webadmin_dns.conf"
|
||||
DEFAULT_CONFIG_CONTENT="
|
||||
no-dhcp-interface=
|
||||
server=1.1.1.1
|
||||
server=1.0.0.1
|
||||
|
||||
listen-address=0.0.0.0
|
||||
bind-interfaces
|
||||
"
|
||||
|
||||
create_default_config() {
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
echo "Config file not found, creating a new one..."
|
||||
echo "$DEFAULT_CONFIG_CONTENT" > "$CONFIG_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
start_dnsmasq() {
|
||||
dnsmasq -C "$CONFIG_FILE" &
|
||||
while inotifywait -e modify "$CONFIG_FILE"; do
|
||||
echo "Configuration changed, reloading dnsmasq..."
|
||||
pkill dnsmasq
|
||||
sleep 5
|
||||
dnsmasq -C "$CONFIG_FILE" &
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
handle_sigint() {
|
||||
echo "SIGINT received. Stopping inotifywait and dnsmasq..."
|
||||
pkill inotifywait
|
||||
pkill dnsmasq
|
||||
exit 0
|
||||
}
|
||||
|
||||
trap handle_sigint SIGINT
|
||||
|
||||
create_default_config
|
||||
start_dnsmasq
|
@ -21,6 +21,7 @@ class DNSSettingsForm(forms.ModelForm):
|
||||
self.helper = FormHelper()
|
||||
self.fields['dns_primary'].label = 'Primary Resolver'
|
||||
self.fields['dns_secondary'].label = 'Secondary Resolver'
|
||||
self.fields['dns_primary'].required = True
|
||||
self.helper.form_method = 'post'
|
||||
self.helper.layout = Layout(
|
||||
Fieldset(
|
||||
|
@ -25,9 +25,51 @@ server:
|
||||
local-zone: "local." static
|
||||
do-not-query-localhost: {do_not_query_localhost}
|
||||
verbosity: 1
|
||||
recursion: yes
|
||||
'''
|
||||
unbound_config += forward_zone
|
||||
|
||||
if static_hosts:
|
||||
unbound_config += '\nlocal-zone: "." transparent\n'
|
||||
for static_host in static_hosts:
|
||||
unbound_config += f' local-data: "{static_host.hostname}. IN A {static_host.ip_address}"\n'
|
||||
return unbound_config
|
||||
|
||||
|
||||
def generate_dnsdist_config():
|
||||
dns_settings = DNSSettings.objects.get(name='dns_settings')
|
||||
static_hosts = StaticHost.objects.all()
|
||||
dnsdist_config = "setLocal('0.0.0.0:53')\n"
|
||||
dnsdist_config += "setACL('0.0.0.0/0')\n"
|
||||
|
||||
if dns_settings.dns_primary:
|
||||
dnsdist_config += f"newServer({{address='{dns_settings.dns_primary}', pool='upstreams'}})\n"
|
||||
if dns_settings.dns_secondary:
|
||||
dnsdist_config += f"newServer({{address='{dns_settings.dns_secondary}', pool='upstreams'}})\n"
|
||||
|
||||
if static_hosts:
|
||||
dnsdist_config += "addAction(makeRule(''), PoolAction('staticHosts'))\n"
|
||||
for static_host in static_hosts:
|
||||
dnsdist_config += f"addLocal('{static_host.hostname}', '{static_host.ip_address}')\n"
|
||||
|
||||
return dnsdist_config
|
||||
|
||||
|
||||
def generate_dnsmasq_config():
|
||||
dns_settings = DNSSettings.objects.get(name='dns_settings')
|
||||
static_hosts = StaticHost.objects.all()
|
||||
dnsmasq_config = f'''
|
||||
no-dhcp-interface=
|
||||
listen-address=0.0.0.0
|
||||
bind-interfaces
|
||||
|
||||
'''
|
||||
if dns_settings.dns_primary:
|
||||
dnsmasq_config += f'server={dns_settings.dns_primary}\n'
|
||||
if dns_settings.dns_secondary:
|
||||
dnsmasq_config += f'server={dns_settings.dns_secondary}\n'
|
||||
|
||||
if static_hosts:
|
||||
dnsmasq_config += '\n'
|
||||
for static_host in static_hosts:
|
||||
dnsmasq_config += f'address=/{static_host.hostname}/{static_host.ip_address}\n'
|
||||
return dnsmasq_config
|
||||
|
15
dns/views.py
15
dns/views.py
@ -4,7 +4,7 @@ from django.contrib import messages
|
||||
from user_manager.models import UserAcl
|
||||
from .models import DNSSettings, StaticHost
|
||||
from .forms import StaticHostForm, DNSSettingsForm
|
||||
from .functions import generate_unbound_config
|
||||
from .functions import generate_dnsmasq_config
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
@ -13,9 +13,9 @@ def view_apply_dns_config(request):
|
||||
dns_settings, _ = DNSSettings.objects.get_or_create(name='dns_settings')
|
||||
dns_settings.pending_changes = False
|
||||
dns_settings.save()
|
||||
unbound_config = generate_unbound_config()
|
||||
with open(settings.UNBOUND_CONFIG, 'w') as f:
|
||||
f.write(unbound_config)
|
||||
dnsmasq_config = generate_dnsmasq_config()
|
||||
with open(settings.DNS_CONFIG_FILE, 'w') as f:
|
||||
f.write(dnsmasq_config)
|
||||
messages.success(request, 'DNS settings applied successfully')
|
||||
return redirect('/dns/')
|
||||
|
||||
@ -48,12 +48,7 @@ def view_manage_dns_settings(request):
|
||||
<p>
|
||||
All DNS queries will be forwarded to the primary resolver. If the primary resolver is not available, the secondary resolver will be used.
|
||||
</p>
|
||||
<strong>
|
||||
Local DNS Resolution
|
||||
</strong>
|
||||
<p>
|
||||
If no forwarders are specified, the system will locally resolve DNS queries. This can lead to slower DNS resolution times, but can be useful in certain scenarios.
|
||||
</p>
|
||||
|
||||
'''
|
||||
|
||||
context = {
|
||||
|
@ -11,6 +11,12 @@ services:
|
||||
context: ./cron
|
||||
dockerfile: Dockerfile-cron
|
||||
|
||||
wireguard-webadmin-dns:
|
||||
image: eduardosilva/wireguard_webadmin_dns:latest
|
||||
build:
|
||||
context: ./containers/dnsmasq
|
||||
dockerfile: Dockerfile-dnsmasq
|
||||
|
||||
wireguard-webadmin-nginx:
|
||||
image: eduardosilva/wireguard_webadmin_nginx:latest
|
||||
build:
|
||||
|
@ -8,10 +8,12 @@ services:
|
||||
environment:
|
||||
- SERVER_ADDRESS=127.0.0.1
|
||||
- DEBUG_MODE=True
|
||||
- COMPOSE_VERSION=02b
|
||||
volumes:
|
||||
- wireguard:/etc/wireguard
|
||||
- static_volume:/app_static_files/
|
||||
- .:/app
|
||||
- dnsmasq_conf:/etc/dnsmasq
|
||||
ports:
|
||||
# Do not directly expose the Django port to the internet, use some kind of reverse proxy with SSL.
|
||||
- "127.0.0.1:8000:8000"
|
||||
@ -38,6 +40,16 @@ services:
|
||||
depends_on:
|
||||
- wireguard-webadmin
|
||||
|
||||
wireguard-webadmin-dns:
|
||||
container_name: wireguard-webadmin-dns
|
||||
restart: unless-stopped
|
||||
build:
|
||||
context: ./containers/dnsmasq
|
||||
dockerfile: Dockerfile-dnsmasq
|
||||
volumes:
|
||||
- dnsmasq_conf:/etc/dnsmasq/
|
||||
|
||||
volumes:
|
||||
static_volume:
|
||||
wireguard:
|
||||
dnsmasq_conf:
|
@ -7,9 +7,11 @@ services:
|
||||
environment:
|
||||
- SERVER_ADDRESS=127.0.0.1
|
||||
- DEBUG_MODE=True
|
||||
- COMPOSE_VERSION=02b
|
||||
volumes:
|
||||
- wireguard:/etc/wireguard
|
||||
- static_volume:/app_static_files/
|
||||
- dnsmasq_conf:/etc/dnsmasq
|
||||
ports:
|
||||
# Do not directly expose the Django port to the internet, use some kind of reverse proxy with SSL.
|
||||
- "127.0.0.1:8000:8000"
|
||||
@ -33,6 +35,14 @@ services:
|
||||
depends_on:
|
||||
- wireguard-webadmin
|
||||
|
||||
wireguard-webadmin-dns:
|
||||
container_name: wireguard-webadmin-dns
|
||||
restart: unless-stopped
|
||||
image: eduardosilva/wireguard_webadmin_dns:latest
|
||||
volumes:
|
||||
- dnsmasq_conf:/etc/dnsmasq/
|
||||
|
||||
volumes:
|
||||
static_volume:
|
||||
wireguard:
|
||||
dnsmasq_conf:
|
||||
|
@ -7,9 +7,11 @@ services:
|
||||
environment:
|
||||
- SERVER_ADDRESS=${SERVER_ADDRESS}
|
||||
- DEBUG_MODE=${DEBUG_MODE}
|
||||
- COMPOSE_VERSION=02b
|
||||
volumes:
|
||||
- wireguard:/etc/wireguard
|
||||
- static_volume:/app_static_files/
|
||||
- dnsmasq_conf:/etc/dnsmasq
|
||||
ports:
|
||||
# Do not directly expose the Django port to the internet, use the reverse proxy below instead
|
||||
# - "127.0.0.1:8000:8000"
|
||||
@ -33,6 +35,13 @@ services:
|
||||
depends_on:
|
||||
- wireguard-webadmin
|
||||
|
||||
wireguard-webadmin-dns:
|
||||
container_name: wireguard-webadmin-dns
|
||||
restart: unless-stopped
|
||||
image: eduardosilva/wireguard_webadmin_dns:latest
|
||||
volumes:
|
||||
- dnsmasq_conf:/etc/dnsmasq/
|
||||
|
||||
wireguard-webadmin-nginx:
|
||||
container_name: wireguard-webadmin-nginx
|
||||
restart: unless-stopped
|
||||
@ -48,3 +57,4 @@ volumes:
|
||||
static_volume:
|
||||
https_cert:
|
||||
wireguard:
|
||||
dnsmasq_conf:
|
||||
|
@ -2,6 +2,11 @@
|
||||
|
||||
set -e
|
||||
|
||||
if [[ "$COMPOSE_VERSION" != "02b" ]]; then
|
||||
echo "ERROR: Please upgrade your docker compose file. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$SERVER_ADDRESS" ]; then
|
||||
echo "SERVER_ADDRESS environment variable is not set. Exiting."
|
||||
exit 1
|
||||
|
@ -143,6 +143,19 @@ def export_user_firewall():
|
||||
return "".join(iptables_rules)
|
||||
|
||||
|
||||
def generate_redirect_dns_rules():
|
||||
wireguard_instance_list = WireGuardInstance.objects.all()
|
||||
firewall_settings, firewall_settings_created = FirewallSettings.objects.get_or_create(name='global')
|
||||
dns_redirect_rules = ''
|
||||
for wireguard_instance in wireguard_instance_list:
|
||||
dns_redirect_rules += f"# DNS Redirect for instance wg{wireguard_instance.instance_id}\n"
|
||||
dns_redirect_rules += f"iptables -t nat -A WGWADM_PREROUTING -i wg{wireguard_instance.instance_id} -d {wireguard_instance.address} -p udp --dport 53 -j DNAT --to $DNS_IP:53\n"
|
||||
dns_redirect_rules += f"iptables -t nat -A WGWADM_PREROUTING -i wg{wireguard_instance.instance_id} -d {wireguard_instance.address} -p tcp --dport 53 -j DNAT --to $DNS_IP:53\n"
|
||||
dns_redirect_rules += f"iptables -t nat -A WGWADM_POSTROUTING -i wg{wireguard_instance.instance_id} -o {firewall_settings.wan_interface} -d $DNS_IP -j MASQUERADE\n"
|
||||
dns_redirect_rules += f"iptables -t filter -A WGWADM_FORWARD -i wg{wireguard_instance.instance_id} -o {firewall_settings.wan_interface} -d $DNS_IP -j ACCEPT\n"
|
||||
return dns_redirect_rules
|
||||
|
||||
|
||||
def generate_firewall_header():
|
||||
firewall_settings, firewall_settings_created = FirewallSettings.objects.get_or_create(name='global')
|
||||
header = f'''#!/bin/bash
|
||||
@ -151,6 +164,10 @@ def generate_firewall_header():
|
||||
#
|
||||
# This script was generated by WireGuard_WebAdmin on {timezone.now().strftime('%Y-%m-%d %H:%M:%S %Z')}
|
||||
#
|
||||
DNS_IP=$(host wireguard-webadmin-dns | grep -oP 'has address \K[\d\.]+')
|
||||
if [ -z "$DNS_IP" ]; then
|
||||
DNS_IP="127.0.0.250"
|
||||
fi
|
||||
|
||||
iptables -t nat -N WGWADM_POSTROUTING >> /dev/null 2>&1
|
||||
iptables -t nat -N WGWADM_PREROUTING >> /dev/null 2>&1
|
||||
|
@ -98,11 +98,11 @@
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="{{ form.dns_primary.id_for_label }}">{{ form.dns_primary.label }}</label>
|
||||
<input type="text" class="form-control" id="{{ form.dns_primary.id_for_label }}" name="{{ form.dns_primary.html_name }}" placeholder="1.1.1.1" value="{{ form.dns_primary.value|default_if_none:'' }}">
|
||||
<input type="text" class="form-control" id="{{ form.dns_primary.id_for_label }}" name="{{ form.dns_primary.html_name }}" value="{{ form.dns_primary.value|default_if_none:'' }}">
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="{{ form.dns_secondary.id_for_label }}">{{ form.dns_secondary.label }}</label>
|
||||
<input type="text" class="form-control" id="{{ form.dns_secondary.id_for_label }}" name="{{ form.dns_secondary.html_name }}" placeholder="1.0.0.1" value="{{ form.dns_secondary.value|default_if_none:'' }}">
|
||||
<input type="text" class="form-control" id="{{ form.dns_secondary.id_for_label }}" name="{{ form.dns_secondary.html_name }}" value="{{ form.dns_secondary.value|default_if_none:'' }}">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -16,7 +16,7 @@ class WireGuardInstanceForm(forms.ModelForm):
|
||||
post_down = forms.CharField(label='Post Down', required=False)
|
||||
peer_list_refresh_interval = forms.IntegerField(label='Web Refresh Interval', initial=20)
|
||||
dns_primary = forms.GenericIPAddressField(label='Primary DNS', initial='1.1.1.1', required=False)
|
||||
dns_secondary = forms.GenericIPAddressField(label='Secondary DNS', initial='1.0.0.1', required=False)
|
||||
dns_secondary = forms.GenericIPAddressField(label='Secondary DNS', initial='', required=False)
|
||||
|
||||
class Meta:
|
||||
model = WireGuardInstance
|
||||
|
@ -60,6 +60,7 @@ def generate_instance_defaults():
|
||||
'private_key': new_private_key,
|
||||
'public_key': new_public_key,
|
||||
'address': new_address,
|
||||
'dns_primary': new_address,
|
||||
'netmask': 24,
|
||||
'persistent_keepalive': 25,
|
||||
'hostname': 'myserver.example.com',
|
||||
|
@ -4,7 +4,8 @@ import qrcode
|
||||
import subprocess
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import redirect, get_object_or_404, render
|
||||
from firewall.tools import generate_firewall_header, generate_firewall_footer, generate_port_forward_firewall, export_user_firewall
|
||||
from firewall.tools import generate_firewall_header, generate_firewall_footer, generate_port_forward_firewall, \
|
||||
export_user_firewall, generate_redirect_dns_rules
|
||||
from user_manager.models import UserAcl
|
||||
from wireguard.models import WireGuardInstance, Peer, PeerAllowedIP
|
||||
from firewall.models import RedirectRule
|
||||
@ -55,6 +56,7 @@ def generate_peer_config(peer_uuid):
|
||||
|
||||
def export_firewall_configuration():
|
||||
firewall_content = generate_firewall_header()
|
||||
firewall_content += generate_redirect_dns_rules()
|
||||
firewall_content += generate_port_forward_firewall()
|
||||
firewall_content += export_user_firewall()
|
||||
firewall_content += generate_firewall_footer()
|
||||
|
@ -131,9 +131,9 @@ STATICFILES_DIRS = [
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
|
||||
UNBOUND_CONFIG = '/config/unbound.conf'
|
||||
DNS_CONFIG_FILE = '/etc/dnsmasq/wireguard_webadmin_dns.conf'
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
WIREGUARD_WEBADMIN_VERSION = 9607
|
||||
WIREGUARD_WEBADMIN_VERSION = 9609
|
||||
|
||||
from wireguard_webadmin.production_settings import *
|
||||
|
@ -28,7 +28,7 @@ from dns.views import view_static_host_list, view_manage_static_host, view_manag
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
# path('admin/', admin.site.urls),
|
||||
path('', view_welcome, name='welcome'),
|
||||
path('status/', view_wireguard_status, name='wireguard_status'),
|
||||
path('dns/', view_static_host_list, name='static_host_list'),
|
||||
|
Loading…
x
Reference in New Issue
Block a user