#!/bin/bash # # vpn-stack # A set of bash scripts for installing and managing a WireGuard VPN server. # https://git.stack-source.com/msb/vpn-stack # Copyright (c) 2022 Matthew Saunders Brown # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # # wireguard installer for Debian 12 # # this installer expects a clean Debian 12 install with # wireguard, stubby & dnsmasq *not* previously installed # require root if [ "${EUID}" -ne 0 ]; then echo "This script must be run as root" exit 1 fi # do some basic pre-install checks - these are *not* exhaustive os_id=`lsb_release -is 2>/dev/null` os_release=`lsb_release -rs 2>/dev/null` if [ $os_id != Debian ] || [ $os_release != 12 ]; then echo "this installer only runs on Debian 12, bailing out" exit 1 fi if [ -d /etc/wiregaurd ]; then echo "looks like wireguard is already installed, bailing out" exit 1 fi if [ -d /etc/stubby/ ]; then echo "looks like stubby is already installed, bailing out" exit 1 fi if [ -d /etc/dnsmasq.d ]; then echo "looks like dnsmasq is already installed, bailing out" exit 1 fi # check for / set hostname # autodetection that should work on Debian 12 # you can change this to fit your network, or just set to a specific IP # used by wireguard for vpn connections & stubby for DNS queries IPv4=`ip route get 1.1.1.1| head -n 1 | cut -d ' ' -f 7` # make sure systemd-resolved is installed, and resolvconf is not installed DEBIAN_FRONTEND=noninteractive apt-get -y purge resolvconf DEBIAN_FRONTEND=noninteractive apt-get -y install systemd-resolved # 1.1.1.1 (Cloudflare) DNS w/ DNS over TLS (DoT) for OS sed -i 's|#DNS=|DNS=1.1.1.1|g' /etc/systemd/resolved.conf sed -i 's|#FallbackDNS=|FallbackDNS=1.0.0.1|g' /etc/systemd/resolved.conf sed -i "s|#Domains=|Domains=`hostname -d`|g" /etc/systemd/resolved.conf sed -i 's|#DNSOverTLS=no|DNSOverTLS=yes|g' /etc/systemd/resolved.conf sed -i 's|#Cache=.*|Cache=no|g' /etc/systemd/resolved.conf systemctl restart systemd-resolved # configure a minimal smtp server so automated emails (cron etc) can be sent DEBIAN_FRONTEND=noninteractive apt-get -y install exim4-daemon-light mailutils sed -i "s|dc_eximconfig_configtype='local'|dc_eximconfig_configtype='internet'|g" /etc/exim4/update-exim4.conf.conf /usr/sbin/update-exim4.conf systemctl restart exim4 # stubby DNS Privacy stub resolver for wireguard clients DEBIAN_FRONTEND=noninteractive apt-get -y install stubby cp /etc/stubby/stubby.yml /etc/stubby/stubby.yml.default echo 'resolution_type: GETDNS_RESOLUTION_STUB' > /etc/stubby/stubby.yml echo 'dns_transport_list:' >> /etc/stubby/stubby.yml echo ' - GETDNS_TRANSPORT_TLS' >> /etc/stubby/stubby.yml echo 'tls_authentication: GETDNS_AUTHENTICATION_REQUIRED' >> /etc/stubby/stubby.yml echo 'tls_query_padding_blocksize: 128' >> /etc/stubby/stubby.yml echo 'edns_client_subnet_private : 1' >> /etc/stubby/stubby.yml echo 'round_robin_upstreams: 1' >> /etc/stubby/stubby.yml echo 'idle_timeout: 10000' >> /etc/stubby/stubby.yml echo 'listen_addresses:' >> /etc/stubby/stubby.yml echo ' - 127.0.0.1' >> /etc/stubby/stubby.yml echo ' - 0::1' >> /etc/stubby/stubby.yml echo " - $IPv4" >> /etc/stubby/stubby.yml echo 'upstream_recursive_servers:' >> /etc/stubby/stubby.yml echo ' - address_data: 1.1.1.1' >> /etc/stubby/stubby.yml echo ' tls_auth_name: "one.one.one.one"' >> /etc/stubby/stubby.yml echo ' - address_data: 1.0.0.1' >> /etc/stubby/stubby.yml echo ' tls_auth_name: "one.one.one.one"' >> /etc/stubby/stubby.yml echo ' - address_data: 2606:4700:4700::1111' >> /etc/stubby/stubby.yml echo ' tls_auth_name: "one.one.one.one"' >> /etc/stubby/stubby.yml echo ' - address_data: 2606:4700:4700::1001' >> /etc/stubby/stubby.yml echo ' tls_auth_name: "one.one.one.one"' >> /etc/stubby/stubby.yml systemctl restart stubby.service # download adware + malware hosts file, used by dnsmasq wget --output-document=/usr/local/etc/hosts https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts # remove ipv6 records sed -i '/::/d' /usr/local/etc/hosts # dnsmasq will use adware + malware hosts file # and listen on wireguard server private lan IP # can be used by clients for adblocking # create temporary policy-rc.d to stop dnsmasq from starting during install # otherwise dnsmasq will fail to start due to ports in use and will show # errors. not really a problem as later config resoves this, but the errors # may cause concern for users running the install install -m 755 /dev/null /usr/sbin/policy-rc.d echo '#!/bin/sh' > /usr/sbin/policy-rc.d echo 'exit 101' >> /usr/sbin/policy-rc.d DEBIAN_FRONTEND=noninteractive apt-get -y install dnsmasq echo "domain-needed" > /etc/dnsmasq.d/local.conf echo "bogus-priv" >> /etc/dnsmasq.d/local.conf echo "no-resolv" >> /etc/dnsmasq.d/local.conf echo "no-poll" >> /etc/dnsmasq.d/local.conf echo "server=127.0.0.1" >> /etc/dnsmasq.d/local.conf echo "addn-hosts=/usr/local/etc/hosts" >> /etc/dnsmasq.d/local.conf # cache is disabled for extra privacy, but this impacts performance # enable cache for increased performance, at the expense of privacy echo "cache-size=0" >> /etc/dnsmasq.d/local.conf echo "no-negcache" >> /etc/dnsmasq.d/local.conf echo "listen-address=10.96.0.1" >> /etc/dnsmasq.d/local.conf echo "no-dhcp-interface=10.96.0.1" >> /etc/dnsmasq.d/local.conf echo "bind-interfaces" >> /etc/dnsmasq.d/local.conf # remove temporary policy-rc.d rm -f /usr/sbin/policy-rc.d sed -i 's|After=network.target|After=wg-quick@wg0.service|g' /lib/systemd/system/dnsmasq.service systemctl daemon-reload # install & configure wireguard DEBIAN_FRONTEND=noninteractive apt-get -y install net-tools wireguard wireguard-tools qrencode zip # this will be the private network used by wireguard server & clients # Network: 10.96.0.0/16 # Address: 10.96.0.1 # Netmask: 255.255.0.0 # Wildcard: 0.0.255.255 # Broadcast: 10.96.255.255 # HostMin: 10.96.0.1 # HostMax: 10.96.255.254 # Hosts/Net: 65025 (Private Internet) # Network: 10.96.0.0/12 # Address: 10.96.0.1 # Netmask: 255.240.0.0 = 12 # Wildcard: 0.15.255.255 # Broadcast: 10.111.255.255 # HostMin: 10.96.0.1 # HostMax: 10.111.255.254 # Hosts/Net: 1048574 (Private Internet) # set temp umask for creating wiregaurd configs UMASK=`umask` umask 0077 # create keys wg genkey > /etc/wireguard/.privatekey cat /etc/wireguard/.privatekey | wg pubkey > /etc/wireguard/.publickey # Generate wg0.conf echo "[Interface]" >> /etc/wireguard/wg0.conf echo "Address = 10.96.0.1/16" >> /etc/wireguard/wg0.conf echo "ListenPort = 51820" >> /etc/wireguard/wg0.conf echo "PrivateKey = "$(cat /etc/wireguard/.privatekey) >> /etc/wireguard/wg0.conf echo "SaveConfig = true" >> /etc/wireguard/wg0.conf echo >> /etc/wireguard/wg0.conf # make backup copy of initial wg0.conf. can be used to reset server config # and optionally re-enable peers if anything gets fubared cp /etc/wireguard/wg0.conf /etc/wireguard/.wg0.conf # make sure perms are correct. redundant, umask should have taken care of this chmod 600 /etc/wireguard/* chmod 600 /etc/wireguard/.wg0.conf # create dirs for client & peer configs install --owner=root --group=root --mode=700 --directory /etc/wireguard/clients install --owner=root --group=root --mode=700 --directory /etc/wireguard/peers # revert umask setting umask $UMASK systemctl enable wg-quick@wg0.service systemctl start wg-quick@wg0.service systemctl restart dnsmasq.service # install wg*.sh scripts in to /usr/local/sbin/ cp sbin/wg*.sh /usr/local/sbin/ chmod 755 /usr/local/sbin/wg*.sh # set up wireguard timer for wg-cron.sh # removes inactive peers (clients) endpoint (last connected IP) data from wireguard mkdir -p /usr/local/lib/systemd/system cp systemd/wg-cron.* /usr/local/lib/systemd/system/ chmod 644 /usr/local/lib/systemd/system/wg-cron.* systemctl daemon-reload systemctl enable wg-cron.timer systemctl start wg-cron.timer # get public interface (e.g. eth0, enp0s10, etc.) for adding to firewall config INTERFACE=$(ip route get 1.1.1.1 | sed -n 's/.*dev \([^\ ]*\).*/\1/p') # configure firewalld if [[ -f /etc/firewalld/zones/public.xml ]]; then rm /etc/firewalld/zones/public.xml firewall-cmd --reload fi firewall-cmd --permanent --zone=external --add-interface=$INTERFACE firewall-cmd --permanent --zone=external --add-service=wireguard firewall-cmd --permanent --zone=internal --add-interface=wg0 firewall-cmd --permanent --zone=internal --add-service=dns firewall-cmd --permanent --zone=internal --remove-service=mdns firewall-cmd --permanent --zone=internal --remove-service=samba-client firewall-cmd --permanent --zone=internal --remove-service=dhcpv6-client # configure cross-zone forwarding firewall-cmd --permanent --new-policy=internal2external firewall-cmd --permanent --policy=internal2external --set-target=ACCEPT firewall-cmd --permanent --policy=internal2external --add-ingress-zone=internal firewall-cmd --permanent --policy=internal2external --add-egress-zone=external firewall-cmd --reload # configure draconian ssh failure blocking sed -i "s|maxretry.*|maxretry = 1|g" /etc/fail2ban/jail.d/defaults-debian.conf systemctl restart fail2ban # display installation confirmation message echo "WireGuard is now installed and configured and running." echo "You can begin adding clients with the wg-client-add.sh script." echo "" echo "Reasonable defaults have been set. There are a couple of adjustable" echo "settings in /usr/local/sbin/wg.sh if you need to customize your installation." echo "" echo "To route system emails and to enable unattended upgrade notifications" echo "run these two commands, replacing user@example.com with your email address." echo "" echo "echo \"root: user@example.com\" >> /etc/aliases" echo "sed -i 's|//Unattended-Upgrade::Mail \"\";|Unattended-Upgrade::Mail \"user@example.com\";|g' /etc/apt/apt.conf.d/50unattended-upgrades"