diff --git a/not-supported/firewall.sh b/not-supported/firewall.sh index a6f476a492..4d11f642bd 100644 --- a/not-supported/firewall.sh +++ b/not-supported/firewall.sh @@ -87,7 +87,7 @@ then fi # Pi-hole -if pihole &>/dev/null +if is_docker_running && docker ps -a --format "{{.Names}}" | grep -q "^pihole$" then print_text_in_color "$ICyan" "Allow Pi-hole" ufw allow 53/tcp comment 'Pi-hole TCP' @@ -95,11 +95,12 @@ then ufw allow 8094/tcp comment 'Pi-hole Web' fi -# PiVPN -if pivpn &>/dev/null +# WireGuard +if is_docker_running && docker ps -a --format "{{.Names}}" | grep -q "^wg-easy$" then - print_text_in_color "$ICyan" "Allow PiVPN" - ufw allow 51820/udp comment 'PiVPN' + print_text_in_color "$ICyan" "Allow WireGuard" + ufw allow 51820/udp comment 'WireGuard VPN' + ufw allow 51822/tcp comment 'WireGuard Web' fi # Plex diff --git a/not-supported/not-supported_menu.sh b/not-supported/not-supported_menu.sh index 96778f4fa7..196bf60761 100644 --- a/not-supported/not-supported_menu.sh +++ b/not-supported/not-supported_menu.sh @@ -39,11 +39,11 @@ $CHECKLIST_GUIDE" "$WT_HEIGHT" "$WT_WIDTH" 4 \ "Monitor Link Shares" "(Monitors the creation of link shares)" OFF \ "Off-Shore Backup Wizard" "(Create an Off-Shore Backup script)" OFF \ "Pi-hole" "(Network wide ads- and tracker blocking)" OFF \ -"PiVPN" "(Install a Wireguard VPN server with PiVPN)" OFF \ "PLEX Media Server" "(Multimedia server application)" OFF \ "Remotedesktop" "(Install a remotedesktop based on xrdp)" OFF \ "SMB-server" "(Create and manage a SMB-server on OS level)" OFF \ -"System Restore" "(Restore the system partition from a backup)" OFF 3>&1 1>&2 2>&3) +"System Restore" "(Restore the system partition from a backup)" OFF \ +"WireGuard" "(Install a WireGuard VPN server)" OFF 3>&1 1>&2 2>&3) case "$choice" in *"BTRFS Format"*) @@ -102,10 +102,6 @@ case "$choice" in print_text_in_color "$ICyan" "Downloading the Pi-hole script..." run_script NOT_SUPPORTED_FOLDER pi-hole ;;& - *"PiVPN"*) - print_text_in_color "$ICyan" "Downloading the PiVPN script..." - run_script NOT_SUPPORTED_FOLDER pivpn - ;;& *"PLEX Media Server"*) print_text_in_color "$ICyan" "Downloading the PLEX Media Server script..." run_script NOT_SUPPORTED_FOLDER plexmediaserver @@ -122,6 +118,10 @@ case "$choice" in print_text_in_color "$ICyan" "Downloading the System Restore script..." run_script NOT_SUPPORTED_FOLDER system-restore ;;& + *"WireGuard"*) + print_text_in_color "$ICyan" "Downloading the WireGuard script..." + run_script NOT_SUPPORTED_FOLDER wireguard + ;;& *) ;; esac diff --git a/not-supported/pi-hole.sh b/not-supported/pi-hole.sh index 443c4c324f..aff668a20b 100644 --- a/not-supported/pi-hole.sh +++ b/not-supported/pi-hole.sh @@ -3,12 +3,13 @@ # T&M Hansson IT AB © - 2026, https://www.hanssonit.se/ # Copyright © 2021 Simon Lindner (https://github.com/szaimen) -# shellcheck disable=2016,2034,2059,2178,2317 true SCRIPT_NAME="Pi-hole" SCRIPT_EXPLAINER="The Pi-hole® is a DNS sinkhole that protects your devices from unwanted content, \ without installing any client-side software. -This is their official website: https://pi-hole.net" +This is their official website: https://pi-hole.net + +This script installs Pi-hole in a Docker container." # shellcheck source=lib.sh source /var/scripts/fetch_lib.sh @@ -21,304 +22,210 @@ debug_mode # Check if root root_check -msg_box "The pi-hole script is unfortunately deprecated as it needs a rewrite since many parts in the upstream pi-hole project changed. -Feel free to subscribe to https://github.com/szaimen/Nextcloud-NAS-Guide/issues/133 in the meantime." -exit 1 +# The port that the Pi-hole web interface listens on inside the container. +# We don't use 80 here since that port is already occupied by Apache2 on the host. +PIHOLE_WEB_PORT=8573 +# The port that Apache2 listens on to proxy the web interface via https +PIHOLE_PROXY_PORT=8094 +# Where the Pi-hole configuration and databases are stored on the host +PIHOLE_DIR=/opt/pihole # Check if already installed -if ! pihole &>/dev/null +if ! is_docker_running || ! docker ps -a --format "{{.Names}}" | grep -q "^pihole$" then # Ask for installing install_popup "$SCRIPT_NAME" else - # Choose to uninstall - if ! yesno_box_no "It seems like Pi-hole is already installed. -Do you want to uninstall Pi-hole and reset all its settings?" - then - exit 1 - fi - - # Check if PiVPN is installed - if pivpn &>/dev/null - then - msg_box "It seems like PiVPN is installed. -We recommend urgently to uninstall PiVPN before uninstalling Pi-hole \ -because it could happen, that PiVPN doesn't work anymore after uninstalling Pi-hole." - exit 1 - fi - - # Warning - msg_box "Warning! -Uninstalling Pi-hole will reset all its config and will reboot your NcVM afterwards automatically." - - # Last choice - if ! yesno_box_no "Do you want to continue nonetheless?" - then - exit 1 - fi - - # Get initially installed programs from pihole-update.sh - INSTALLED=$(grep "Pi-hole installed programs=" "$SCRIPTS/pihole-update.sh") - INSTALLED="${INSTALLED##*programs=}" - - # Inform the user - if ! yesno_box_yes "These are all packets that where installed during your initial Pi-hole installation: -$INSTALLED - -Do they look correct to you? If not, you can press 'no' and we will not remove anything. -If you press 'yes', we will remove Pi-hole, its settings and all those listed programs." - then - exit 1 - fi - - # Make an array from installed applications - read -r -a INSTALLED <<< "$INSTALLED" - - # /opt/pihole/uninstall.sh edit file and put setupVars variable setupVars="/etc/pihole/setupVars.conf" at 5th line or something - - UNINSTALL="/etc/.pihole/automated install/uninstall.sh" - # Uninstall pihole; we need to modify it, else it is not unattended - if ! [ -f "$UNINSTALL" ] || ! grep -q "######### SCRIPT ###########" "$UNINSTALL" || ! grep -q "removeNoPurge()" "$UNINSTALL" + # Ask for removal or reinstallation + reinstall_remove_menu "$SCRIPT_NAME" + # Removal + docker rm -f pihole &>/dev/null + # Remove the Apache2 configuration + if [ -f "$SITES_AVAILABLE/pihole.conf" ] then - msg_box "It seems like some uninstall functions changed. -Please report this to $ISSUES" - exit 1 - fi - - # Continue with preparation - check_command cp "/etc/.pihole/automated install/uninstall.sh" "$SCRIPTS"/pihole-uninstall.sh - check_command sed -i '/######### SCRIPT ###########/q' "$SCRIPTS"/pihole-uninstall.sh - check_command echo "removeNoPurge" >> "$SCRIPTS"/pihole-uninstall.sh - - # Uninstall Pi-hole - check_command yes | bash "$SCRIPTS"/pihole-uninstall.sh - - # Remove the file and crontab - crontab -u root -l | grep -v "pihole-update.sh" | crontab -u root - - check_command rm "$SCRIPTS"/pihole-uninstall.sh - - # Delete the pihole user - if id pihole &>/dev/null - then - check_command killall -u pihole - check_command deluser pihole &>/dev/null - check_command groupdel pihole + a2dissite pihole.conf &>/dev/null + rm -f "$SITES_AVAILABLE/pihole.conf" + restart_webserver fi - - # Delete all its config data - rm -rf /etc/.pihole - rm -rf /etc/pihole - rm -rf /opt/pihole - rm -rf /usr/bin/pihole-FTL - rm -rf /usr/local/bin/pihole - rm -rf /var/www/html/admin - rm -f /var/www/html/pihole - - # Delete unbound config - crontab -u root -l | grep -v "systemctl restart unbound" | crontab -u root - - rm /etc/unbound/unbound.conf.d/pi-hole.conf - - # Remove update script - rm -f "$SCRIPTS/pihole-update.sh" - - # Remove all initially installed applications - for program in "${INSTALLED[@]}" + # Delete firewall entries + for port in 53/tcp 53/udp "$PIHOLE_PROXY_PORT/tcp" do - apt-get purge "$program" -y + ufw delete allow "$port" &>/dev/null done - - # Remove unbound - if is_this_installed unbound + # Re-enable the systemd-resolved stub listener since port 53 is free again + if [ -f /etc/systemd/resolved.conf.d/ncvm-pihole.conf ] then - apt-get purge unbound -y + rm -f /etc/systemd/resolved.conf.d/ncvm-pihole.conf + systemctl restart systemd-resolved &>/dev/null + # Restore the resolv.conf symlink to the stub resolver + if [ -f /run/systemd/resolve/stub-resolv.conf ] + then + ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf + fi fi - - # Remove not needed dependencies - apt-get autoremove -y - - # Delete other files - rm -f /var/www/html/index.lighttpd.orig - rm -rf /etc/lighttpd - - # Remove apache conf - a2dissite pihole.conf &>/dev/null - rm -f "$SITES_AVAILABLE/pihole.conf" - restart_webserver - - # Delete firewall entry - ufw delete allow 53/tcp &>/dev/null - ufw delete allow 53/udp &>/dev/null - ufw delete allow 8094/tcp &>/dev/null - - # Inform the user - msg_box "Pi-hole was successfully uninstalled! -Please reset the DNS on your router/clients to restore internet connectivity" - msg_box "After you hit OK, your NcVM will get restarted." - rm -f "$SCRIPTS/pi-hole.sh" - # Reboot the NcVM because it would cause problems if not - reboot -fi - -# Inform the user -msg_box "Before installing the Pi-hole, please make sure that you have a backup of your NcVM. -The reason is, that to install the Pi-hole we will need to run a 3rd party script on your NcVM. -Something could go wrong. So please keep backups!" - -# Ask if backups are ready -if ! yesno_box_no "Have you made a backup of your NcVM? -This is the last possibility to quit! -If you choose 'yes' we will continue with the installtion." -then - exit 1 + # The user-data is kept on purpose so that a reinstallation doesn't lose the settings + if [ "$REINSTALL_REMOVE" = "Uninstall" ] + then + msg_box "The Pi-hole user-data was NOT removed and is still stored here: +'$PIHOLE_DIR' + +If you want to delete it as well, e.g. to be able to start from scratch \ +if you install Pi-hole again later on, please run the following command: +'sudo rm -r $PIHOLE_DIR' + +Attention! Please don't forget to reset the DNS server on your router and/or \ +your clients to restore their internet connectivity, if you had configured them \ +to use this server as their DNS server." + else + msg_box "Please note that the Pi-hole user-data in '$PIHOLE_DIR' \ +will be kept, which means that your current settings, blocklists and \ +statistics will still be there after the reinstallation. + +If you want to start from scratch instead, please abort this script now with 'CTRL+C' \ +and run the following command before running it again: +'sudo rm -r $PIHOLE_DIR'" + fi + # Show successful uninstall if applicable + removal_popup "$SCRIPT_NAME" fi -# Inform the user -print_text_in_color "$ICyan" "Installing Pi-hole..." +# Warn about running this on a public server +msg_box "Please note that Pi-hole is only intended to be run on a server \ +in a trusted home network. -# Download the script -mkdir -p "$SCRIPTS" -check_command curl -sfL https://install.pi-hole.net -o "$SCRIPTS"/pihole-install.sh +You should NOT run this on a public VPS or any other server whose ip address \ +is directly reachable from the internet, since an open DNS resolver can be \ +abused for DNS amplification attacks." -# Check that all patterns match -if ! grep -q 'displayFinalMessage "${pw}"' "$SCRIPTS"/pihole-install.sh || ! grep -q "setAdminFlag$" "$SCRIPTS"/pihole-install.sh \ -|| ! grep -q "chooseInterface$" "$SCRIPTS"/pihole-install.sh || ! grep -q "getStaticIPv4Settings$" "$SCRIPTS"/pihole-install.sh +if ! yesno_box_yes "Is this server running in a trusted home network?" then - msg_box "It seems like some functions in pihole-install.sh have changed. -Please report this to $ISSUES" exit 1 fi -# Continue with the process -sed -i 's|displayFinalMessage "${pw}"|echo displayFinalMessage|' "$SCRIPTS"/pihole-install.sh # We don't want to display the final message -sed -i "s|setAdminFlag$|echo setAdminFlag|" "$SCRIPTS"/pihole-install.sh # We want to install the web-interface and lighttpd -sed -i "s|chooseInterface$|echo chooseInterface|" "$SCRIPTS"/pihole-install.sh # We don't want the user choose the interface -sed -i "s|getStaticIPv4Settings$|echo getStaticIPv4Settings|" "$SCRIPTS"/pihole-install.sh # We don't want to set a static ip4 - -# Export default values -PIHOLE_INTERFACE="$IFACE" -export PIHOLE_INTERFACE - -# Fix php versions getting hold for pi-hole install script -apt-mark unhold php"$PHPVER"* - -# Run the script -bash "$SCRIPTS"/pihole-install.sh | tee "$SCRIPTS"/pihole-install.report - -# Get all installed and remove pihole-install.sh -unset INSTALLED -INSTALLED=$(grep "Checking for" "$SCRIPTS"/pihole-install.report | grep "will be installed" | awk '{print $8}') -check_command rm "$SCRIPTS"/pihole-install.sh -check_command rm "$SCRIPTS"/pihole-install.report - -# Check if at least one app got installed -if [ -z "${INSTALLED[*]}" ] +# Pi-hole needs port 53. On the NcVM this port is by default occupied by the +# systemd-resolved stub listener on 127.0.0.53, which prevents the container +# from binding to 53 on all interfaces. We disable the stub listener further +# down below, but any other DNS server needs to be handled by the user. +print_text_in_color "$ICyan" "Checking if port 53 is already in use..." +install_if_not net-tools +DNS_IN_USE="$(netstat -tulpn 2>/dev/null | grep ":53 " | grep -v "127.0.0.53:53" | grep -v "docker-proxy")" +if [ -n "$DNS_IN_USE" ] then - msg_bos "Something is wrong. Didn't expect that no requirement get installed. -Please report this to $ISSUES" -fi + msg_box "It seems like another DNS server is already listening on port 53: -# Make an array from installed applications -mapfile -t INSTALLED <<< "${INSTALLED[@]}" +$DNS_IN_USE -# Create update script -mkdir -p "$SCRIPTS" +Pi-hole cannot be installed while another DNS server occupies this port. \ +Please stop and disable that DNS server first and run this script again. -# Insert the new lines into pihole-update.sh -cat << PIHOLE_UPDATE > "$SCRIPTS/pihole-update.sh" -#!/bin/bash -if [ -f /var/scripts/fetch_lib.sh ] -then - source /var/scripts/fetch_lib.sh -elif ! source <(curl -sL https://raw.githubusercontent.com/nextcloud/vm/main/static/fetch_lib.sh) -then - source <(curl -sL https://cdn.statically.io/gh/nextcloud/vm/main/static/fetch_lib.sh) -fi -PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin -notify_admin_gui "Starting the Pi-hole update." "You will be notified when it is done." -# Create backup first -if [ -f "\$SCRIPTS/daily-borg-backup.sh" ] -then - rm -f /tmp/DAILY_BACKUP_CREATION_SUCCESSFUL - export SKIP_DAILY_BACKUP_CHECK=1 - bash "\$SCRIPTS/daily-borg-backup.sh" - if ! [ -f "/tmp/DAILY_BACKUP_CREATION_SUCCESSFUL" ] - then - notify_admin_gui "Pi-hole update failed because backup could not be created!" \ - "Could not create a backup! \$(date +%T)" - exit 1 - fi -fi -check_command pihole -up -systemctl stop lighttpd -check_command sed -i 's|^server\.port.*|server\.port = 8093|' /etc/lighttpd/lighttpd.conf -sleep 10 # Wait for lighttpd -check_command systemctl start lighttpd -# Please don't remove or change this line! Pi-hole installed programs=${INSTALLED[@]} -notify_admin_gui "Pi-hole update successful!" "" -PIHOLE_UPDATE - -# Secure the file -chown root:root "$SCRIPTS/pihole-update.sh" -chmod 700 "$SCRIPTS/pihole-update.sh" - -# Check if Pi-hole was successfully installed -if ! pihole &>/dev/null -then - msg_box "Something got wrong during pihole-install.sh -Please report this to $ISSUES" +Please report this to $ISSUES if you think that this is a mistake." exit 1 fi -# Set up REV_SERVER for local DNS entries because Pi-hole isn't the DHCP server and some other settings -if [ -f /etc/pihole/setupVars.conf ] && ! grep -q "REV_SERVER" /etc/pihole/setupVars.conf +# Ask if the user wants to use unbound as recursive DNS server +if yesno_box_yes "Do you want to enable your Pi-hole to be a recursive DNS server? + +If you choose 'yes', we will additionally install unbound and configure your \ +Pi-hole to use it as its upstream DNS server. This means that your Pi-hole will \ +resolve all DNS queries itself instead of forwarding them to a public DNS \ +provider like Google or Cloudflare, which improves your privacy." then - cat << PIHOLE_CONF >> /etc/pihole/setupVars.conf -REV_SERVER=true -REV_SERVER_CIDR=$(ip route | grep -v "default via" | grep "$IFACE" | awk '{print $1}' | grep "/") -REV_SERVER_TARGET=$GATEWAY -REV_SERVER_DOMAIN= -PIHOLE_CONF + UNBOUND=yes fi -# Make sure that local DNS entries work -if [ -f /etc/pihole/setupVars.conf ] && ! grep -q "DNS_FQDN_REQUIRED" /etc/pihole/setupVars.conf && ! grep -q "DNS_BOGUS_PRIV" /etc/pihole/setupVars.conf +# Install Docker +install_docker + +# Free port 53 by disabling the systemd-resolved stub listener. +# systemd-resolved itself keeps running as the local resolver for the host, +# but stops listening on 127.0.0.53:53 so that Pi-hole can bind to port 53. +print_text_in_color "$ICyan" "Disabling the systemd-resolved DNS stub listener..." +mkdir -p /etc/systemd/resolved.conf.d +cat << RESOLVED_CONF > /etc/systemd/resolved.conf.d/ncvm-pihole.conf +# This file was created by the NcVM Pi-hole script. +# Pi-hole needs to bind to port 53 on all interfaces, which is not possible +# while the systemd-resolved stub listener occupies 127.0.0.53:53. +[Resolve] +DNSStubListener=no +RESOLVED_CONF + +# With the stub listener disabled, /etc/resolv.conf must not point to the +# stub resolver anymore, since nothing is listening on 127.0.0.53 any longer. +if [ -f /run/systemd/resolve/resolv.conf ] then - cat << PIHOLE_CONF >> /etc/pihole/setupVars.conf -DNS_FQDN_REQUIRED=false -DNS_BOGUS_PRIV=false -PIHOLE_CONF + ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf fi -# Wait for pihole to restart -print_text_in_color "$ICyan" "Restarting pihole..." -sleep 5 +check_command systemctl restart systemd-resolved -# Try to restart Pi-hole to apply the new settings -if ! pihole restartdns +# Make sure that name resolution still works before we continue, +# since we just changed the DNS setup of the host +print_text_in_color "$ICyan" "Checking if DNS resolution still works..." +if ! nslookup github.com >/dev/null 2>&1 then - msg_box "Something got wrong during the Pi-hole restart. + msg_box "DNS resolution stopped working after disabling the systemd-resolved \ +stub listener. We will revert this change now and exit. + Please report this to $ISSUES" + rm -f /etc/systemd/resolved.conf.d/ncvm-pihole.conf + if [ -f /run/systemd/resolve/stub-resolv.conf ] + then + ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf + fi + systemctl restart systemd-resolved exit 1 fi -# Change the port to 8093 -check_command sudo sed -i '/^server.port/s/80/8093/' /etc/lighttpd/lighttpd.conf +# Create the directories for the persistent data +mkdir -p "$PIHOLE_DIR/etc-pihole" +mkdir -p "$PIHOLE_DIR/etc-dnsmasq.d" -# Wait for lighttpd to startup -print_text_in_color "$ICyan" "Restarting lighttpd..." -sleep 5 +# Generate a new Pi-hole password +PASSWORD=$(gen_passwd 12 "a-zA-Z0-9") -# Restart lighttpd -if ! systemctl restart lighttpd +# Get the docker container +print_text_in_color "$ICyan" "Getting Pi-hole..." +docker pull pihole/pihole:latest + +# Create Pi-hole +# The web interface listens on $PIHOLE_WEB_PORT inside the container since port 80 +# is already used by Apache2 on the host. Apache2 proxies https://$ADDRESS:8094 +# to 127.0.0.1:$PIHOLE_WEB_PORT further down below. +# 'FTLCONF_dns_listeningMode=all' is needed because the container runs in the +# docker bridge network and would otherwise only answer queries that originate +# from the same subnet as the container itself. +# The DHCP functionality is not enabled on purpose, which is why the container +# doesn't need the NET_ADMIN capability and port 67/udp. +print_text_in_color "$ICyan" "Installing Pi-hole..." +if ! docker run -d \ +--name pihole \ +--restart always \ +-p 53:53/tcp \ +-p 53:53/udp \ +-p 127.0.0.1:"$PIHOLE_WEB_PORT":"$PIHOLE_WEB_PORT"/tcp \ +-e TZ="$(cat /etc/timezone)" \ +-e FTLCONF_webserver_api_password="$PASSWORD" \ +-e FTLCONF_dns_listeningMode=all \ +-e FTLCONF_webserver_port="$PIHOLE_WEB_PORT" \ +-v "$PIHOLE_DIR/etc-pihole:/etc/pihole" \ +-v "$PIHOLE_DIR/etc-dnsmasq.d:/etc/dnsmasq.d" \ +pihole/pihole:latest then - msg_box "Couldn't restart lighttpd. -Please report this to $ISSUES" + msg_box "Failed to create the Pi-hole container. + +Please report this issue here $ISSUES if you can't solve it yourself." + # Remove the container leftovers so that this script can be run again + docker rm -f pihole &>/dev/null exit 1 fi -# Install Apache2 -print_text_in_color "$ICyan" "Configuring Apache..." +# Add prune command +add_dockerprune + +# Install apache2 install_if_not apache2 + +# Enable Apache2 module's a2enmod headers a2enmod rewrite a2enmod ssl @@ -331,40 +238,44 @@ then TLS13="+TLSv1.3" fi +# Create the vhost that proxies the Pi-hole web interface via https. +# We use a self-signed certificate here since the Pi-hole admin interface is +# only meant to be reachable inside the local network via the ip address. cat << PIHOLE_CONF > "$SITES_AVAILABLE/pihole.conf" -Listen 8094 - +Listen $PIHOLE_PROXY_PORT + Header add Strict-Transport-Security: "max-age=15768000;includeSubdomains" - + # Intermediate configuration SSLEngine on SSLCompression off SSLProtocol -all +TLSv1.2 $TLS13 - SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 + SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 SSLHonorCipherOrder off SSLSessionTickets off ServerSignature off - + # Logs LogLevel warn CustomLog \${APACHE_LOG_DIR}/access.log combined ErrorLog \${APACHE_LOG_DIR}/error.log - + # Just in case - see below SSLProxyEngine On SSLProxyVerify None SSLProxyCheckPeerCN Off SSLProxyCheckPeerName Off - - # This is needed to redirect access on http://$ADDRESS:8094/ to https://$ADDRESS:8094/ - ErrorDocument 400 https://$ADDRESS:8094/admin/ - + + # This is needed to redirect access on http://$ADDRESS:$PIHOLE_PROXY_PORT/ + # to https://$ADDRESS:$PIHOLE_PROXY_PORT/ + ErrorDocument 400 https://$ADDRESS:$PIHOLE_PROXY_PORT/admin/ + # basic proxy settings ProxyRequests off - ProxyPass / "http://127.0.0.1:8093/" - ProxyPassReverse / "http://127.0.0.1:8093/" + ProxyPass / "http://127.0.0.1:$PIHOLE_WEB_PORT/" + ProxyPassReverse / "http://127.0.0.1:$PIHOLE_WEB_PORT/" ProxyPreserveHost On - + ### LOCATION OF CERT FILES ### SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key @@ -382,69 +293,32 @@ The script will exit." exit 1 fi -# Generate new Pi-hole password -PASSWORD=$(gen_passwd 12 "a-zA-Z0-9") - -# Set a new admin password -check_command pihole -a -p "$PASSWORD" - -# Get the ipv6-address from the config file -IPV6_ADDRESS=$(grep "IPV6_ADDRESS=" /etc/pihole/setupVars.conf) -IPV6_ADDRESS="${IPV6_ADDRESS##*IPV6_ADDRESS=}" - -# Create contab entry -crontab -u root -l | grep -v "pihole-update.sh" | crontab -u root - -crontab -u root -l | { cat; echo "30 19 * * 6 $SCRIPTS/pihole-update.sh >/dev/null" ; } | crontab -u root - - -# Add firewall entry +# Add firewall rules ufw allow 53/tcp comment 'Pi-hole TCP' &>/dev/null ufw allow 53/udp comment 'Pi-hole UDP' &>/dev/null -ufw allow 8094/tcp comment 'Pi-hole Web' &>/dev/null - -# Show that everything was set up correctly -msg_box "Congratulations, your Pi-hole was set up correctly! -It is now reachable on: -https://$ADDRESS:8094/admin - -Your password is: $PASSWORD" - -# Show the address -msg_box "You can now configure your devices to use the Pi-hole as their DNS server using: -IPv4: $ADDRESS -IPv6: ${IPV6_ADDRESS:-Not Configured}" - -# Show how to use pihole in the command line -msg_box "How to use Pi-hole on the command line: - -You can reset the Pi-hole admin password by running: -'pihole -a -p' - -A list of available options is shown by running: -'pihole -h'" - -# Inform about updates -msg_box "Concerning updates: -We have created an update script that you can use to update your Pi-hole by running: -'bash $SCRIPTS/pihole-update.sh' +ufw allow "$PIHOLE_PROXY_PORT"/tcp comment 'Pi-hole Web' &>/dev/null -Updates will automatically be executed every saturday at 19:30" - -# Ask if the user wants to install unbound -if ! yesno_box_yes "Do you want to enables your Pi-hole to be a recursive DNS server? -If you press 'yes', we will install unbound and configure your Pi-hole to use that." +# Set up unbound if chosen +if [ "$UNBOUND" = "yes" ] then - exit -fi - -# Install needed tools -install_if_not unbound + # Install needed tools + install_if_not unbound + + # unbound listens on port 5335 on the docker bridge gateway so that the + # Pi-hole container can reach it. 127.0.0.1 would not be reachable from + # inside the container. + DOCKER_GATEWAY="$(docker network inspect bridge --format '{{range .IPAM.Config}}{{.Gateway}}{{end}}')" + if [ -z "$DOCKER_GATEWAY" ] + then + DOCKER_GATEWAY=172.17.0.1 + fi -cat << UNBOUND_CONF > /etc/unbound/unbound.conf.d/pi-hole.conf + cat << UNBOUND_CONF > /etc/unbound/unbound.conf.d/pi-hole.conf server: # To see what those variables do, look here: # https://docs.pi-hole.net/guides/unbound/ verbosity: 0 - interface: 127.0.0.1 + interface: $DOCKER_GATEWAY port: 5335 do-ip4: yes do-udp: yes @@ -454,7 +328,7 @@ server: harden-glue: yes harden-dnssec-stripped: yes use-caps-for-id: no - edns-buffer-size: 1472 + edns-buffer-size: 1232 prefetch: yes num-threads: 1 so-rcvbuf: 1m @@ -464,48 +338,88 @@ server: private-address: 10.0.0.0/8 private-address: fd00::/8 private-address: fe80::/10 + # Only allow the Pi-hole container to use this resolver + access-control: 0.0.0.0/0 refuse + access-control: 127.0.0.0/8 allow + access-control: 172.16.0.0/12 allow UNBOUND_CONF -# Wait for unbound to restart -print_text_in_color "$ICyan" "Restarting unbound..." -sleep 10 & spinner_loading - -# Restart unbound -check_command service unbound restart + # Restart unbound + print_text_in_color "$ICyan" "Restarting unbound..." + check_command systemctl restart unbound + countdown "Waiting for unbound to start... " 10 -# Testing DNSSEC -if ! dig sigfail.verteiltesysteme.net @127.0.0.1 -p 5335 | grep -q "SERVFAIL" -then - msg_box "Something got wrong while testing SERVFAIL. + # Testing DNSSEC + install_if_not dnsutils + if ! dig sigfail.verteiltesysteme.net @"$DOCKER_GATEWAY" -p 5335 | grep -q "SERVFAIL" + then + msg_box "Something went wrong while testing SERVFAIL. Please report this to $ISSUES" -elif ! dig sigok.verteiltesysteme.net @127.0.0.1 -p 5335 | grep -q "NOERROR" -then - msg_box "Something got wrong while testing NOERROR. + elif ! dig sigok.verteiltesysteme.net @"$DOCKER_GATEWAY" -p 5335 | grep -q "NOERROR" + then + msg_box "Something went wrong while testing NOERROR. Please report this to $ISSUES" + fi + + # Allow the container to reach unbound on the docker bridge + ufw allow in on docker0 to "$DOCKER_GATEWAY" port 5335 comment 'Pi-hole unbound' &>/dev/null + + # Configure Pi-hole to use unbound as its upstream DNS server + print_text_in_color "$ICyan" "Configuring Pi-hole to use unbound..." + countdown "Waiting for Pi-hole to start... " 15 + if ! docker exec pihole pihole-FTL --config "dns.upstreams=$DOCKER_GATEWAY#5335" &>/dev/null + then + msg_box "Could not configure Pi-hole to use unbound automatically. + +You can do this yourself by visiting https://$ADDRESS:$PIHOLE_PROXY_PORT/admin \ +and entering '$DOCKER_GATEWAY#5335' as custom upstream DNS server under \ +'Settings' --> 'DNS'." + else + docker restart pihole &>/dev/null + msg_box "unbound was successfully installed and Pi-hole was successfully \ +configured to use it as recursive DNS server." + fi fi -# Set up Pi-hole -sed -i 's|^PIHOLE_DNS_1=.*|PIHOLE_DNS_1=127.0.0.1#5335|' /etc/pihole/setupVars.conf -sed -i '/^PIHOLE_DNS_2=.*/d' /etc/pihole/setupVars.conf +# Show that everything was set up correctly +msg_box "Congratulations, your Pi-hole was set up correctly! +It is now reachable on: +https://$ADDRESS:$PIHOLE_PROXY_PORT/admin -# Wait for pihole to restart -print_text_in_color "$ICyan" "Restarting pihole..." -sleep 5 +Your password is: $PASSWORD -# Try to restart Pi-hole to apply the new settings -if ! pihole restartdns -then - msg_box "Something got wrong during the Pi-hole unbound restart. -Please report this to $ISSUES" - exit 1 -fi +Please note that the certificate is self-signed, which means that your browser \ +will show a warning that you need to accept." -# Fix dns disconnections -crontab -u root -l | grep -v "systemctl restart unbound" | crontab -u root - -crontab -u root -l | { cat; echo "@hourly systemctl restart unbound" ; } | crontab -u root - +# Show the address +msg_box "You can now configure your devices to use the Pi-hole as their DNS server \ +by entering the following ip address as DNS server in your router: +$ADDRESS + +Additionally, you can configure the docker daemon to use it by editing \ +'/etc/docker/daemon.json' and adding '\"dns\" : [ \"$ADDRESS\", \"9.9.9.9\" ]'." + +# Show how to use pihole in the command line +msg_box "How to use Pi-hole on the command line: + +You can run any Pi-hole command inside the container like this: +'sudo docker exec -it pihole pihole -h' + +Please note that the admin password is set via an environment variable of the \ +container, which makes it read-only for the web interface and the command line. \ +If you want to change it, you can run this script again and choose 'Reinstall', \ +which will generate and show you a new password while keeping all your settings. + +Please also note that the DHCP functionality of Pi-hole is not enabled since the \ +container doesn't run in the host network." + +# Inform about updates +msg_box "Concerning updates: +Pi-hole runs in a Docker container, which means that you can update it \ +by running the following commands: +'sudo docker pull pihole/pihole:latest' +and afterwards running this script again and choosing 'Reinstall'. -# Inform the user -msg_box "Congratulations! -Unbound was successfully installed and Pi-hole was successfully configured as recursive DNS server." +Your settings and statistics in '$PIHOLE_DIR' will be kept in that process." exit diff --git a/not-supported/pivpn.sh b/not-supported/pivpn.sh deleted file mode 100644 index e0c74d417d..0000000000 --- a/not-supported/pivpn.sh +++ /dev/null @@ -1,280 +0,0 @@ -#!/bin/bash - -# T&M Hansson IT AB © - 2026, https://www.hanssonit.se/ -# Copyright © 2021 Simon Lindner (https://github.com/szaimen) - -true -SCRIPT_NAME="PiVPN" -SCRIPT_EXPLAINER="PiVPN is one of the fastest and most user friendly ways to get a running Wireguard VPN server. -This script will set up a Wireguard VPN server to connect devices to your home net from everywhere. -Wireguard is a relatively new VPN protocol, that is much faster and better then e.g. OpenVPN." -# shellcheck source=lib.sh -source /var/scripts/fetch_lib.sh - -# Check for errors + debug code and abort if something isn't right -# 1 = ON -# 0 = OFF -DEBUG=0 -debug_mode - -# Check if root -root_check - -# Check if already installed -if ! pivpn &>/dev/null -then - # Ask for installing - install_popup "$SCRIPT_NAME" -else - # Choose to uninstall - if ! yesno_box_no "It seems like PiVPN is already installed. -Do you want to uninstall PiVPN and reset all its settings? -This will also remove all clients that have currently home network access via Wireguard." - then - exit 1 - fi - - # Get installed applications - INSTALLED=$(grep "INSTALLED_PACKAGES=" /etc/pivpn/wireguard/setupVars.conf) - INSTALLED="${INSTALLED##*INSTALLED_PACKAGES=}" - INSTALLED=$(echo "$INSTALLED" | sed 's|(||;s|)||') - - # Warning - msg_box "Warning! Continuing in the next step will reboot your server after completion automatically!" - - # Inform about possible problems - msg_box "Attention! - -It could happen that the automatic reboot after uninstalling PiVPN fails (it doesn't finish with shutdown). -In this case, you will need to power off your device by hand. -Also it might happen that it will not remove pivpn successfully in this case. -If this is the case, just run the uninstallation again." - if ! yesno_box_yes "Do you want to continue?" - then - exit 1 - fi - - # Last chance to cancel - if ! yesno_box_yes "The following packets will get uninstalled, too: -$INSTALLED - -Do they look correct to you? If not, you can press 'no' and we will not remove anything. -If you press 'yes', we will remove PiVPN, its settings and all those listed programs \ -and automatically reboot your server afterwards." - then - exit 1 - fi - - # Last msg_box - msg_box "After you hit okay, we will remove PiVPN, all its settings and all listed programs \ -and reboot your server automatically." - - # Remove firewall rule - ufw delete allow 51820/udp &>/dev/null - - # Remove PiVPN and reboot - yes | pivpn uninstall - - # Remove some leftovers - rm -r /etc/wireguard* - ip link set down wg0 - ip link del dev wg0 - rm -f "$SCRIPTS/pivpn.sh" - - # Just to make sure - reboot -fi - -# Check if Pi-hole is already installed -if ! pihole &>/dev/null -then - # Inform the user - msg_box "It seems like Pi-hole is not installed. -It is recommended to install it first if you want to use it, \ -because you will have the chance to use it as the DNS-server for Wireguard \ -if it is installed before installing Wireguard." - - # Ask if the user wants to continue - if ! yesno_box_no "Do you want to continue nonetheless?" - then - exit 1 - fi -fi - -# Test if the user is okay -if [ -z "$UNIXUSER" ] || ! find /home -maxdepth 1 -mindepth 1 | grep -q "$UNIXUSER" -then - msg_box "It seems like you run this script as pure root \ -or your user doesn't have a home directory. This is not supported." - exit 1 -fi - -# Inform the user -msg_box "Before installing PiVPN please make sure that you have a backup of your NcVM. -The reason is, that to install the the PiVPN we will need to run a 3rd party script on your NcVM. -Something could go wrong. So please keep backups!" - -# Automatically get the domain -if [ -f "$NCPATH/occ" ] -then - # Get the NCDOMAIN - NCDOMAIN=$(nextcloud_occ_no_check config:system:get overwrite.cli.url | sed 's|https://||;s|/||') - - # Check if Nextcloud is installed - if ! curl -s https://"$NCDOMAIN"/status.php | grep -q 'installed":true' || [ "$NCDOMAIN" = "nextcloud" ] - then - msg_box "It seems like Nextcloud is not installed or that you don't use https on: -$NCDOMAIN. - -Please install Nextcloud and make sure your domain is reachable, or activate TLS -on your domain to be able to run this script. - -We need this to make sure that the domain works for connections over Wireguard." - exit 1 - fi -fi - -# Ask if backups are ready -if ! yesno_box_no "Have you made a backup of your NcVM? -This is the last possibility to quit! -If you choose 'yes' we will continue with the installation." -then - exit 1 -fi - -# Ask for the domain -if ! [ -f "$NCPATH/occ" ] -then - # Enter the NCDOMAIN yourself - NCDOMAIN=$(input_box_flow "Please enter the domain that you want to use for Wireguard. -It should most likely point to your home ip address via DDNS.") -fi - -# Inform user to open Port -msg_box "To make Wireguard work, you will need to open port 51820 UDP. - -You will have the option to automatically open this port by using UPNP in the next step." -if yesno_box_no "Do you want to use UPNP to open port 51820 UDP?" -then - unset FAIL - open_port 51820 UDP - cleanup_open_port -fi - -# Check the port -if ! yesno_box_yes "Unfortunately we are not able to check automatically if port 51820 UDP is open. So please make sure to open it correctly!\nDo you still want to continue?" -then - exit 1 -fi - -# Inform the user about PIVPN -msg_box "Just so that you don't wonder: -We will use the scripts from the PiVPN project. -They are made for the Raspberry Pi but work on Ubuntu without any problem. -This is why we decided to use this project as foundation for Wireguard. -The next popups are from the PiVPN script. -This is their official website: https://pivpn.io/" - -# Inform the user -print_text_in_color "$ICyan" "Installing PiVPN..." - -# Download the script -check_command curl -sfL https://install.pivpn.io -o "$SCRIPTS"/pivpn-install.sh - -# Check that all patterns match -if ! grep -q "maybeOSSupport$" "$SCRIPTS"/pivpn-install.sh || ! grep -q "askWhichVPN$" "$SCRIPTS"/pivpn-install.sh \ -|| ! grep -q "askPublicIPOrDNS$" "$SCRIPTS"/pivpn-install.sh || ! grep -q "askCustomPort$" "$SCRIPTS"/pivpn-install.sh \ -|| ! grep -q "askUnattendedUpgrades$" "$SCRIPTS"/pivpn-install.sh || ! grep -q "displayFinalMessage$" "$SCRIPTS"/pivpn-install.sh \ -|| ! grep -q "chooseUser$" "$SCRIPTS"/pivpn-install.sh || ! grep -q "welcomeDialogs$" "$SCRIPTS"/pivpn-install.sh -then - msg_box "It seems like some functions in pivpn-install.sh have changed. -Please report this to $ISSUES" - exit 1 -fi - -# Continue with the process -sed -i 's|maybeOSSupport$|# maybeOSSupport|' "$SCRIPTS"/pivpn-install.sh # We don't need to check the OS since Ubuntu is supported -sed -i 's|askWhichVPN$|# askWhichVPN|' "$SCRIPTS"/pivpn-install.sh # We always want to use Wireguard -sed -i 's|askPublicIPOrDNS$|# askPublicIPOrDNS|' "$SCRIPTS"/pivpn-install.sh # We will set the hostname automatically -sed -i 's|askCustomPort$|# askCustomPort|' "$SCRIPTS"/pivpn-install.sh # We always use port 51820 -sed -i 's|askUnattendedUpgrades$|# askUnattendedUpgrades|' "$SCRIPTS"/pivpn-install.sh # We don't want to enable unattended upgrades -sed -i 's|displayFinalMessage$|# displayFinalMessage|' "$SCRIPTS"/pivpn-install.sh # We don't want to show the final message -sed -i 's|chooseUser$|# chooseUser|' "$SCRIPTS"/pivpn-install.sh # We want to use the UNIXUSER -sed -i 's|welcomeDialogs$|# welcomeDialogs|' "$SCRIPTS"/pivpn-install.sh # We don't want to display the welcoem dialog - -# Set and export defaults -pivpnPORT=51820 && export pivpnPORT -VPN="wireguard" && export VPN -UNATTUPG=0 && export UNATTUPG - -# Run the script -bash "$SCRIPTS"/pivpn-install.sh - -# Remove the script since it is no longer needed -check_command rm "$SCRIPTS"/pivpn-install.sh - -# Check if PiVPN was successfully installed -if ! pivpn &>/dev/null -then - msg_box "Something got wrong during pivpn-install.sh -Please report this to $ISSUES" - exit 1 -fi - -PIVPN_CONF="/etc/pivpn/wireguard/setupVars.conf" -if [ -f "$PIVPN_CONF" ] && ! grep -q "pivpnHOST" "$PIVPN_CONF" \ -&& ! grep -q "UNATTUPG" "$PIVPN_CONF" && ! grep -q "pivpnPORT" "$PIVPN_CONF" \ -&& ! grep -q "install_user" "$PIVPN_CONF" && ! grep -q "install_home" "$PIVPN_CONF" -then - # Write values to setupVars.conf - cat << PIVPN_CONF >> /etc/pivpn/wireguard/setupVars.conf -pivpnHOST=$NCDOMAIN -UNATTUPG=0 -pivpnPORT=51820 -install_user=$UNIXUSER -install_home=/home/$UNIXUSER -PIVPN_CONF -else - msg_box "Couldn't write configuration to setupVars.conf. -Please report this to $ISSUES" - exit 1 -fi - -# Add firewall rule -ufw allow 51820/udp comment 'PiVPN' &>/dev/null - -# Inform the user about successfully installing PiVPN -msg_box "Congratulations, your PiVPN was set up correctly! - -You can now generate new client profiles for your devices by running: -'pivpn -a' - -Adding the new profile to a mobile phone (using the Wireguard app) can get afterwards done by running: -'pivpn -qr' - -Attention! Every device needs its own profile! - -A list of available options is shown by running: -'pivpn -h'" - -msg_box "Have you secure boot enabled? -If you had to configure a secure boot key during the PiVPN scripts, \ -it is recommended to reboot your server now and follow those instructions: - -1. select to reboot -2. On the next startup you will see now the MOK-management-console. -3. select 'Enroll MOK' -4. select 'Yes' when asked 'Enroll the Key(s)?' -5. Enter the password -6. reboot - -Afterwards the startup should work automatically again." - -if yesno_box_yes "Do you want to reboot now? -This is only needed, if you have secure boot enabled and \ -needed to enter a secure boot key during the PiVPN script." -then - reboot -fi - -exit diff --git a/not-supported/restore-backup.sh b/not-supported/restore-backup.sh index 633aa5084b..05c8fe9dd4 100644 --- a/not-supported/restore-backup.sh +++ b/not-supported/restore-backup.sh @@ -718,7 +718,7 @@ msg_box "Restore completed!\n You can now simply reinstall all apps and addons that were installed on your server before!\n Those need to get installed (if they were installed on the old server before): Geoblocking, Disk Monitoring, Fail2Ban, ClamAV, SMTP Mail, DDclient, Activate TLS, EuroOffice, Push Notifications for Nextcloud, \ -High-Performance backend for Nextcloud Talk, Whiteboard for Nextcloud, Vaultwarden, Pi-hole, PiVPN, \ +High-Performance backend for Nextcloud Talk, Whiteboard for Nextcloud, Vaultwarden, Pi-hole, WireGuard, \ Plex Media Server, Jellyfin, Previewgenerator, Remotedesktop and Midnight Commander.\n Note: Vaultwarden, Plex Media Server and Jellyfin files were restored (if they were installed before) but the containers need to get \ diff --git a/not-supported/wireguard.sh b/not-supported/wireguard.sh new file mode 100644 index 0000000000..87b2f501d0 --- /dev/null +++ b/not-supported/wireguard.sh @@ -0,0 +1,427 @@ +#!/bin/bash + +# T&M Hansson IT AB © - 2026, https://www.hanssonit.se/ +# Copyright © 2021 Simon Lindner (https://github.com/szaimen) + +true +SCRIPT_NAME="WireGuard" +SCRIPT_EXPLAINER="WireGuard is a modern VPN protocol that is much faster and simpler than e.g. OpenVPN. +This script will set up a WireGuard VPN server to connect devices to your home network from everywhere. + +It uses wg-easy, which provides a web interface to manage your clients. +This is their official website: https://github.com/wg-easy/wg-easy + +This script installs WireGuard in a Docker container." +# shellcheck source=lib.sh +source /var/scripts/fetch_lib.sh + +# Check for errors + debug code and abort if something isn't right +# 1 = ON +# 0 = OFF +DEBUG=0 +debug_mode + +# Check if root +root_check + +# The port that the WireGuard VPN listens on. This one needs to be forwarded. +WIREGUARD_PORT=51820 +# The port that the wg-easy web interface listens on inside the container. +# It is only bound to 127.0.0.1 on the host, since Apache2 proxies it via https. +WIREGUARD_WEB_PORT=51821 +# The port that Apache2 listens on to proxy the web interface via https +WIREGUARD_PROXY_PORT=51822 +# The name of the docker network that the container runs in. +# wg-easy needs an own network with IPv6 enabled. +WIREGUARD_NETWORK=wg-easy + +# Check if already installed +if ! is_docker_running || ! docker ps -a --format "{{.Names}}" | grep -q "^wg-easy$" +then + # Ask for installing + install_popup "$SCRIPT_NAME" +else + # Ask for removal or reinstallation + reinstall_remove_menu "$SCRIPT_NAME" + # Removal + docker rm -f wg-easy &>/dev/null + docker network rm "$WIREGUARD_NETWORK" &>/dev/null + # Remove the Apache2 configuration + if [ -f "$SITES_AVAILABLE/wg-easy.conf" ] + then + a2dissite wg-easy.conf &>/dev/null + rm -f "$SITES_AVAILABLE/wg-easy.conf" + restart_webserver + fi + # Delete firewall entries + for port in "$WIREGUARD_PORT/udp" "$WIREGUARD_PROXY_PORT/tcp" + do + ufw delete allow "$port" &>/dev/null + done + # The user-data is kept on purpose so that a reinstallation doesn't lose the clients + if [ "$REINSTALL_REMOVE" = "Uninstall" ] + then + msg_box "The WireGuard configuration and all your clients were NOT removed \ +and are still stored in the 'wg_easy' docker volume. + +If you want to delete them as well, e.g. to be able to start from scratch \ +if you install WireGuard again later on, please run the following command: +'sudo docker volume rm wg_easy' + +Please don't forget to close port $WIREGUARD_PORT/udp in your router again \ +if you don't need it anymore." + else + msg_box "Please note that the WireGuard configuration in the 'wg_easy' \ +docker volume will be kept, which means that all your current clients will \ +still work after the reinstallation. + +This also means that the admin password will stay the same as before, since \ +wg-easy only applies the initial password on a fresh installation. + +If you want to start from scratch instead, please abort this script now with 'CTRL+C' \ +and run the following command before running it again: +'sudo docker volume rm wg_easy'" + fi + # Show successful uninstall if applicable + removal_popup "$SCRIPT_NAME" +fi + +# Warn about running this on a public server +msg_box "Attention! + +This script opens a VPN entry point into your servers network. \ +Only continue if you understand the implications and keep it updated! + +It is only intended to be used on a server in a trusted home network. \ +Do NOT run this on a public VPS or any other server whose ip address is \ +directly reachable from the internet." + +if ! yesno_box_yes "Is this server running in a trusted home network?" +then + exit 1 +fi + +# wg-easy needs the wireguard kernel module on the host. +# It ships as a loadable module on all kernels since 5.6, but might not be loaded yet. +print_text_in_color "$ICyan" "Checking if the WireGuard kernel module is available..." +if ! lsmod | grep -q "^wireguard" +then + if ! modprobe wireguard &>/dev/null + then + msg_box "The WireGuard kernel module is not available on this server, \ +which means that the container would not be able to start. + +It ships as a loadable module on all common distributions with kernel 5.6 or \ +later. Your current kernel is: $(uname -r) + +Please install the WireGuard kernel module on this server first and \ +run this script again." + exit 1 + fi +fi + +# Make sure that the module gets loaded again after a reboot +if ! [ -f /etc/modules-load.d/wireguard.conf ] +then + echo "wireguard" > /etc/modules-load.d/wireguard.conf +fi + +# Automatically get the domain +if [ -f "$NCPATH/occ" ] +then + # Get the NCDOMAIN + NCDOMAIN=$(nextcloud_occ_no_check config:system:get overwrite.cli.url | sed 's|https://||;s|/||') + + # Check if Nextcloud is installed + if ! curl -s https://"$NCDOMAIN"/status.php | grep -q 'installed":true' || [ "$NCDOMAIN" = "nextcloud" ] + then + msg_box "It seems like Nextcloud is not installed or that you don't use https on: +$NCDOMAIN. + +Please install Nextcloud and make sure your domain is reachable, or activate TLS +on your domain to be able to run this script. + +We need this to make sure that the domain works for connections over WireGuard." + exit 1 + fi +fi + +# Ask for the domain +if ! [ -f "$NCPATH/occ" ] +then + # Enter the domain yourself + NCDOMAIN=$(input_box_flow "Please enter the domain that you want to use for WireGuard. +It should most likely point to your home ip address via DDNS.") +fi + +# Inform user to open the port +msg_box "To make WireGuard work, you will need to open port $WIREGUARD_PORT UDP \ +in your router and forward it to this server. + +Attention! The web interface on port $WIREGUARD_PROXY_PORT TCP must NOT be \ +forwarded, since it is only meant to be reachable inside your local network! + +You will have the option to automatically open port $WIREGUARD_PORT UDP by \ +using UPNP in the next step." + +if yesno_box_no "Do you want to use UPNP to open port $WIREGUARD_PORT UDP?" +then + unset FAIL + open_port "$WIREGUARD_PORT" UDP + cleanup_open_port +fi + +# Check the port +if ! yesno_box_yes "Unfortunately we are not able to check automatically if port \ +$WIREGUARD_PORT UDP is open. So please make sure to open it correctly! +Do you still want to continue?" +then + exit 1 +fi + +# Install Docker +install_docker + +# Generate a new admin password. +# wg-easy doesn't check the password for complexity but refuses to let the user +# log in if it is too short, which is why we use 16 characters here. +PASSWORD=$(gen_passwd 16 "a-zA-Z0-9") + +# The INIT_* variables below are only applied by wg-easy if it doesn't find an +# existing configuration in its volume. So if the volume was kept from a previous +# installation, the old admin password stays in place and the newly generated one +# above would be wrong. We check this here to be able to inform the user correctly. +if docker volume ls --format "{{.Name}}" | grep -q "^wg_easy$" +then + EXISTING_CONFIG=yes +fi + +# Get the docker container +print_text_in_color "$ICyan" "Getting WireGuard..." +docker pull ghcr.io/wg-easy/wg-easy:15 + +# wg-easy needs an own docker network with IPv6 enabled since it hands out +# IPv6 addresses to its clients. The default bridge network doesn't support this. +if ! docker network ls --format "{{.Name}}" | grep -q "^$WIREGUARD_NETWORK$" +then + print_text_in_color "$ICyan" "Creating the WireGuard docker network..." + if ! docker network create \ + --driver bridge \ + --ipv6 \ + --subnet 10.42.42.0/24 \ + --subnet fdcc:ad94:bacf:61a3::/64 \ + "$WIREGUARD_NETWORK" + then + msg_box "Failed to create the WireGuard docker network. + +Please report this issue here $ISSUES if you can't solve it yourself." + exit 1 + fi +fi + +# Create WireGuard +# The INIT_* variables are only used on the very first start of the container +# and set up the admin account automatically so that the user doesn't need to +# run through the setup wizard in the web interface. +# The web interface is only bound to 127.0.0.1 on the host, since Apache2 +# proxies https://$ADDRESS:$WIREGUARD_PROXY_PORT to it further down below. +# 'INSECURE=true' is needed because wg-easy itself only serves plain http and +# doesn't know that it is reached via https through the Apache2 proxy. +print_text_in_color "$ICyan" "Installing WireGuard..." +if ! docker run -d \ +--name wg-easy \ +--restart always \ +--network "$WIREGUARD_NETWORK" \ +--ip 10.42.42.42 \ +--ip6 fdcc:ad94:bacf:61a3::2a \ +-p "$WIREGUARD_PORT":"$WIREGUARD_PORT"/udp \ +-p 127.0.0.1:"$WIREGUARD_WEB_PORT":"$WIREGUARD_WEB_PORT"/tcp \ +--cap-add NET_ADMIN \ +--cap-add SYS_MODULE \ +--sysctl net.ipv4.ip_forward=1 \ +--sysctl net.ipv4.conf.all.src_valid_mark=1 \ +--sysctl net.ipv6.conf.all.disable_ipv6=0 \ +--sysctl net.ipv6.conf.all.forwarding=1 \ +--sysctl net.ipv6.conf.default.forwarding=1 \ +-e TZ="$(cat /etc/timezone)" \ +-e INSECURE=true \ +-e PORT="$WIREGUARD_WEB_PORT" \ +-e INIT_ENABLED=true \ +-e INIT_USERNAME=admin \ +-e INIT_PASSWORD="$PASSWORD" \ +-e INIT_HOST="$NCDOMAIN" \ +-e INIT_PORT="$WIREGUARD_PORT" \ +-v wg_easy:/etc/wireguard \ +-v /lib/modules:/lib/modules:ro \ +ghcr.io/wg-easy/wg-easy:15 +then + msg_box "Failed to create the WireGuard container. + +Please report this issue here $ISSUES if you can't solve it yourself." + # Remove the container leftovers so that this script can be run again + docker rm -f wg-easy &>/dev/null + exit 1 +fi + +# Add prune command +add_dockerprune + +# Install apache2 +install_if_not apache2 + +# Enable Apache2 module's +a2enmod headers +a2enmod rewrite +a2enmod ssl +a2enmod proxy +a2enmod proxy_http +a2enmod proxy_wstunnel + +# Only add TLS 1.3 on supported Ubuntu releases +if version "$SUPPORTED_VERSION_MIN" "$DISTRO" "$SUPPORTED_VERSION_MAX" +then + TLS13="+TLSv1.3" +fi + +# Create the vhost that proxies the wg-easy web interface via https. +# We use a self-signed certificate here since the web interface is only +# meant to be reachable inside the local network via the ip address. +cat << WIREGUARD_CONF > "$SITES_AVAILABLE/wg-easy.conf" +Listen $WIREGUARD_PROXY_PORT + + Header add Strict-Transport-Security: "max-age=15768000;includeSubdomains" + + # Intermediate configuration + SSLEngine on + SSLCompression off + SSLProtocol -all +TLSv1.2 $TLS13 + SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 + SSLHonorCipherOrder off + SSLSessionTickets off + ServerSignature off + + # Logs + LogLevel warn + CustomLog \${APACHE_LOG_DIR}/access.log combined + ErrorLog \${APACHE_LOG_DIR}/error.log + + # Just in case - see below + SSLProxyEngine On + SSLProxyVerify None + SSLProxyCheckPeerCN Off + SSLProxyCheckPeerName Off + + # This is needed to redirect access on http://$ADDRESS:$WIREGUARD_PROXY_PORT/ + # to https://$ADDRESS:$WIREGUARD_PROXY_PORT/ + ErrorDocument 400 https://$ADDRESS:$WIREGUARD_PROXY_PORT/ + + # wg-easy uses websockets to keep the web interface up to date + RewriteEngine On + RewriteCond %{HTTP:Upgrade} websocket [NC] + RewriteCond %{HTTP:Connection} upgrade [NC] + RewriteRule ^/?(.*) "ws://127.0.0.1:$WIREGUARD_WEB_PORT/\$1" [P,L] + + # basic proxy settings + ProxyRequests off + ProxyPass / "http://127.0.0.1:$WIREGUARD_WEB_PORT/" + ProxyPassReverse / "http://127.0.0.1:$WIREGUARD_WEB_PORT/" + ProxyPreserveHost On + +### LOCATION OF CERT FILES ### + SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem + SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key + +WIREGUARD_CONF + +# Enable config +check_command a2ensite wg-easy.conf + +# Restart webserver +if ! restart_webserver +then + msg_box "Apache2 could not restart... +The script will exit." + exit 1 +fi + +# Add firewall rules +ufw allow "$WIREGUARD_PORT"/udp comment 'WireGuard VPN' &>/dev/null +ufw allow "$WIREGUARD_PROXY_PORT"/tcp comment 'WireGuard Web' &>/dev/null + +# Check if the container is actually running, since it exits on startup +# if e.g. the wireguard kernel module cannot be loaded +countdown "Waiting for WireGuard to start... " 15 +if ! docker ps --format "{{.Names}}" | grep -q "^wg-easy$" +then + msg_box "The WireGuard container was created but is not running. + +These are the logs of the container: +$(docker logs --tail 20 wg-easy 2>&1) + +Please report this issue here $ISSUES if you can't solve it yourself." + exit 1 +fi + +# Inform the user about the successful installation +if [ "$EXISTING_CONFIG" = "yes" ] +then + # An existing configuration was found, which means that wg-easy ignored the + # initial admin account and kept the one from the previous installation + msg_box "Congratulations, your WireGuard server was set up correctly! + +The web interface is reachable inside your local network on: +https://$ADDRESS:$WIREGUARD_PROXY_PORT + +Since an existing WireGuard configuration was found in the 'wg_easy' docker \ +volume, your previous admin account and all your clients were kept. This means \ +that you need to log in with the same username and password as before. + +If you don't know your password anymore, you can start from scratch by running \ +the following commands and running this script again afterwards: +'sudo docker rm -f wg-easy' +'sudo docker volume rm wg_easy' + +Attention! This will delete all your clients as well. + +Please note that the certificate is self-signed, which means that your browser \ +will show a warning that you need to accept." +else + msg_box "Congratulations, your WireGuard server was set up correctly! + +The web interface is reachable inside your local network on: +https://$ADDRESS:$WIREGUARD_PROXY_PORT + +Username: admin +Password: $PASSWORD + +Please write down this password now! We cannot show it to you again later on, \ +since it is only used during the initial setup of the container. + +Please note that the certificate is self-signed, which means that your browser \ +will show a warning that you need to accept." +fi + +msg_box "How to add your devices: + +1. Visit https://$ADDRESS:$WIREGUARD_PROXY_PORT and log in +2. Create a new client for each of your devices +3. Scan the shown QR code with the WireGuard app on your phone, \ +or download the configuration file for your computer + +Attention! Every device needs its own client profile! + +Your clients will connect to '$NCDOMAIN' on port $WIREGUARD_PORT UDP. \ +You can change this host in the web interface if you want to connect \ +via a different address." + +msg_box "Concerning updates: +WireGuard runs in a Docker container, which means that you can update it \ +by running the following command: +'sudo docker pull ghcr.io/wg-easy/wg-easy:15' + +and afterwards running this script again and choosing 'Reinstall'. + +Your clients and settings in the 'wg_easy' docker volume will be kept in that \ +process, which also means that your admin password will stay the same." + +exit