#!/bin/bash # Category : Networking # Description : Wireguard Easy - VPN Server (c/u/s/r/i): installWireguard() { local config_variables="$1" if [[ "$wireguard" == *[cCtTuUsSrRiI]* ]]; then dockerConfigSetupToContainer silent wireguard; local app_name=$CFG_WIREGUARD_APP_NAME initializeAppVariables $app_name; fi if [[ "$wireguard" == *[cC]* ]]; then editAppConfig $app_name; fi if [[ "$wireguard" == *[uU]* ]]; then dockerUninstallApp $app_name; fi if [[ "$wireguard" == *[sS]* ]]; then dockerComposeDown $app_name; fi if [[ "$wireguard" == *[rR]* ]]; then dockerComposeRestart $app_name; fi if [[ "$wireguard" == *[iI]* ]]; then isHeader "Install $app_name" ((menu_number++)) echo "" echo "---- $menu_number. Checking if $app_name can be installed." echo "" # Host-conflict guard: a host-level WireGuard (e.g. the angristan # wireguard-install script — marker /etc/wireguard/params) collides with # this container on the wg kernel module + UDP 51820. Abort if present. if [[ -e /etc/wireguard/params ]]; then isError "WireGuard is already installed on the host — this conflicts with the $app_name app." isError "Installation is now aborting..." dockerUninstallApp "$app_name" return 1 fi ((menu_number++)) echo "" echo "---- $menu_number. Setting up install folder and config file for $app_name." echo "" dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables"; isSuccessful "Install folders and Config files have been setup for $app_name." ((menu_number++)) echo "" ((menu_number++)) echo "" echo "---- $menu_number. Setting up the $app_name docker-compose.yml file." echo "" dockerComposeSetupFile $app_name; monitoringToggleAppConfig "$app_name" "docker-compose.yml"; ((menu_number++)) echo "" echo "---- $menu_number. Resolving wireguard tunnel subnet (WG_DEFAULT_ADDRESS)" echo "" # Generate-once-and-persist tunnel subnet. Second-octet 200-250 is # outside the docker network generator range (100-149), so the two # subnets cannot collide. Reusing the persisted value keeps existing # peer configs valid across reinstalls. local _wg_compose_for_subnet="$containers_dir$app_name/docker-compose.yml" if [[ -z "$CFG_WIREGUARD_SUBNET" ]]; then local _wg_second=$(( RANDOM % 51 + 200 )) # 200-250 local _wg_third=$(( RANDOM % 256 )) # 0-255 CFG_WIREGUARD_SUBNET="10.${_wg_second}.${_wg_third}.0" updateConfigOption "CFG_WIREGUARD_SUBNET" "$CFG_WIREGUARD_SUBNET" isSuccessful "Generated wireguard tunnel subnet: $CFG_WIREGUARD_SUBNET" else isNotice "Reusing existing wireguard tunnel subnet: $CFG_WIREGUARD_SUBNET" fi # wg-easy expects the address pattern `.x` (literal x). local _wg_addr_pattern="${CFG_WIREGUARD_SUBNET%.0}.x" tagsManagerUpdateUniversalTag "$_wg_compose_for_subnet" "WIREGUARD_SUBNET_TAG" "$_wg_addr_pattern" isSuccessful "WG_DEFAULT_ADDRESS set to $_wg_addr_pattern" ((menu_number++)) echo "" echo "---- $menu_number. Resolving WG_HOST for peer configs" echo "" local wg_compose_file="$containers_dir$app_name/docker-compose.yml" local wg_host_value="" local _wg_traefik_installed=0 if declare -f checkServiceInstalled >/dev/null 2>&1 && checkServiceInstalled "traefik"; then _wg_traefik_installed=1 fi if [[ -n "$domain_full" && $_wg_traefik_installed -eq 1 ]]; then wg_host_value="$host_setup" isNotice "Domain + Traefik present — peer configs will use $wg_host_value" else wg_host_value="${public_ip_v4:-127.0.0.1}" if [[ -n "$domain_full" && $_wg_traefik_installed -eq 0 ]]; then isNotice "Domain configured but Traefik not installed — falling back to IP $wg_host_value so peer configs actually resolve." else isNotice "No domain configured — peer configs will use IP $wg_host_value (LAN only)" fi fi tagsManagerUpdateUniversalTag "$wg_compose_file" "PUBLIC_IP_TAG" "$wg_host_value" isSuccessful "WG_HOST set to $wg_host_value" ((menu_number++)) echo "" echo "---- $menu_number. Enabling IP forwarding" echo "" # Drop in /etc/sysctl.d/99-libreportal-wireguard.conf + reload — the # whole thing runs as root through libreportal-appcfg so the manager # never needs blanket /etc write or `sudo sysctl` itself. local result=$(runAppCfg wireguard-ip-forward) checkSuccess "Enabling IPv4 IP Forwarding (sysctl drop-in + reload)" ((menu_number++)) echo "" echo "---- $menu_number. Updating file permissions before starting." echo "" fixPermissionsBeforeStart $app_name; ((menu_number++)) echo "" echo "---- $menu_number. Running the docker-compose.yml to Install $app_name" echo "" dockerComposeUpdateAndStartApp $app_name install; ((menu_number++)) echo "" echo "---- $menu_number. Restarting $app_name after firewall changes" echo "" dockerComposeRestart $app_name; ((menu_number++)) echo "" echo "---- $menu_number. Running Application specific updates (if required)" echo "" appUpdateSpecifics $app_name; ((menu_number++)) echo "" echo "---- $menu_number. Running Headscale setup (if required)" echo "" setupHeadscale $app_name; ((menu_number++)) echo "" echo "---- $menu_number. Adding $app_name to the Apps Database table." echo "" databaseInstallApp $app_name; ((menu_number++)) echo "" echo "---- $menu_number. Updating WebUI config file." echo "" webuiContainerSetup $app_name install; ((menu_number++)) echo "" echo "---- $menu_number. Refreshing monitoring integration." echo "" monitoringRefreshAll; ((menu_number++)) echo "" echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name" echo "" echo " You can now navigate to your $app_name service using any of the options below : " echo "" menuShowFinalMessages $app_name; menu_number=0 #sleep 3s cd fi wireguard=n }