Created
February 14, 2025 19:18
-
-
Save freefirex/95e4dc0f93388d620c26d91371b8f1dc to your computer and use it in GitHub Desktop.
softether vpn setup script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
if [ $(id -u) -ne 0 ]; then | |
echo "This script must be run as root" | |
exit | |
fi | |
# Function to prompt for input and ensure it's not blank (except for domain) | |
prompt_input() { | |
local var_name="$1" | |
local prompt_text="$2" | |
local allow_empty="$3" | |
local input_value | |
while true; do | |
read -rp "$prompt_text: " input_value | |
if [[ -z "$input_value" && "$allow_empty" == "no" ]]; then | |
echo "Error: $var_name cannot be blank. Please enter a value." | |
else | |
eval "$var_name=\"$input_value\"" | |
break | |
fi | |
done | |
} | |
prompt_input "adminpassword" "Enter admin password" "no" | |
prompt_input "vpnuser" "Enter VPN username" "no" | |
prompt_input "vpnpwd" "Enter VPN password" "no" | |
prompt_input "domain" "Enter domain (leave blank for none)" "yes" | |
while true; do | |
prompt_input "interface" "Enter network interface we will bridge to" "no" | |
if ip link show "$interface" > /dev/null 2>&1; then | |
break | |
else | |
echo "Error: Interface '$interface' does not exist. Please enter a valid interface." | |
fi | |
done | |
prompt_input "tapname" "Enter TAP name" "no" | |
while true; do | |
prompt_input "configiptables" "Should this script configure iptables for forwarding? (y/n)" "no" | |
if [[ "$configiptables" == "y" || "$configiptables" == "n" ]]; then | |
break | |
else | |
echo "Error: answer must be 'y' or 'n' alone." | |
fi | |
done | |
prompt_input "vpnnet" "Enter the cidr based range for the vpn network. ex. 192.168.30.0/24" "no" | |
vpnbase=${vpnnet%%/*} | |
vpncidr=${vpnnet##*/} | |
prompt_input "vpngateway" "Enter the ip within the cidr range the vpn should use as its gateway ex. 192.168.30.1" "no" | |
prompt_input "vpnnetmask" "Please enter the 4 octet netmask as given by your cider in vpnnet. ex. 255.255.255.0" "no" | |
prompt_input "dhcpstart" "Please enter the start of the dhcp server range ie. 192.168.30.100" "no" | |
prompt_input "dhcpend" "Please enter the end of the dhcp server range ie. 192.168.30.200" "no" | |
echo "\nConfiguration:" | |
echo "Admin Password: [HIDDEN]" | |
echo "VPN User: $vpnuser" | |
echo "VPN Password: [HIDDEN]" | |
echo "Domain: ${domain:-"(none)"}" | |
echo "Network Interface: $interface" | |
echo "TAP Name: $tapname" | |
echo "Configuring iptables $configiptables" | |
echo "VPN network: $vpnnet" | |
echo "VPN gateway: $vpngateway" | |
echo "VPN netmask: $vpnnetmask" | |
echo "DHCP range: $dhcpstart - $dhcpend" | |
while true; do | |
prompt_input "continue" "Is this configuration correct? (y/n)" "no" | |
if [[ "$continue" == "y" ]]; then | |
break | |
elif [[ "$continue" == "n" ]]; then | |
exit | |
else | |
echo "Error: answer must be 'y' or 'n' alone." | |
fi | |
done | |
tapinterface="tap_$tapname" | |
#install dependencies | |
function install_dependencies { | |
apt update && \ | |
apt install -y cmake isc-dhcp-server gcc certbot git g++ make pkgconf libncurses5-dev libssl-dev libsodium-dev libreadline-dev zlib1g-dev && \ | |
apt clean | |
systemctl disable isc-dhcp-server | |
systemctl stop isc-dhcp-server | |
} | |
#clone vpn package at tag and build it, removing git history | |
function install_softether { | |
if command -v vpnserver > /dev/null 2>&1; then | |
echo "vpnserver appears to already be installed, skipping" | |
return | |
fi | |
git clone -b 5.02.5187 --depth 1 --recurse-submodules https://github.com/SoftEtherVPN/SoftEtherVPN.git && \ | |
cd SoftEtherVPN && \ | |
find . -type d -name ".git" -exec rm -rf {} + && \ | |
CMAKE_FLAGS="-DSE_PIDDIR=/run/softether -DSE_LOGDIR=/var/log/softether -DSE_DBDIR=/var/lib/softether" ./configure && \ | |
make -C build | |
make -C build install | |
mkdir -p /run/softether | |
mkdir -p /var/log/softether | |
mkdir -p /var/lib/softether | |
cd /root | |
} | |
#if domain was specified, get ssl cert | |
function get_cert { | |
if [ ! -f /etc/letsencrypt/live/$domain/fullchain.pem ]; then | |
certbot certonly -d $domain --standalone --agree-tos --register-unsafely-without-email | |
if [ ! -f /etc/letsencrypt/live/$domain/fullchain.pem ]; then | |
echo "Failed to get Cert for domain $domain, correct domain in script and retry" | |
exit | |
fi | |
fi | |
} | |
#perform initial server configuration | |
function initial_setup { | |
vpnserver start | |
sleep 10 | |
#create user / pwd | |
vpncmd 127.0.0.1 /SERVER /hub:default /cmd UserCreate $vpnuser /Group:none /RealName:none /Note:none | |
vpncmd 127.0.0.1 /SERVER /hub:default /cmd UserPasswordSet $vpnuser /PASSWORD:$vpnpwd | |
#disable securenat since we will use a local bridge | |
vpncmd 127.0.0.1 /SERVER /hub:default /cmd SecureNatDisable | |
vpncmd 127.0.0.1 /SERVER /cmd BridgeCreate default /DEVICE:$tapname /TAP:yes | |
#use cert we got from letsencrypt if domain name was given | |
if [[ -n "$domain" ]]; then | |
vpncmd 127.0.0.1 /SERVER /hub:none /cmd ServerCertSet /LOADCERT:/etc/letsencrypt/live/$domain/fullchain.pem /LOADKEY:/etc/letsencrypt/live/$domain/privkey.pem | |
fi | |
#finally lets set passwords on the admin / hub | |
vpncmd 127.0.0.1 /SERVER /hub:none /cmd ServerPasswordSet $adminpassword | |
vpncmd 127.0.0.1 /SERVER /hub:default /cmd SetHubPassword $adminpassword | |
} | |
#Configure IP tables to forward traffic | |
function config_iptables { | |
iptables -A FORWARD -s $vpnnet -j ACCEPT | |
iptables -A FORWARD -d $vpnnet -j ACCEPT | |
iptables -t nat -A POSTROUTING -s $vpnnet -o $interface -j MASQUERADE | |
iptables-save > /root/nat.conf | |
echo "saving iptables to /root/nat.conf" | |
} | |
#enable ip forwarding, both now and for reboots | |
function config_forwarding { | |
sysctl -w net.ipv4.ip_forward=1 | |
# Check if the setting is already in /etc/sysctl.conf | |
if grep -q "^net.ipv4.ip_forward=" /etc/sysctl.conf; then | |
echo "Updating existing net.ipv4.ip_forward entry..." | |
sudo sed -i 's/^net.ipv4.ip_forward=.*/net.ipv4.ip_forward=1/' /etc/sysctl.conf | |
else | |
echo "Appending net.ipv4.ip_forward=1 to /etc/sysctl.conf..." | |
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf | |
fi | |
} | |
#configure dhcp to server on tap interfacce | |
function config_dhcp { | |
#write out our tap interface as the one to bind | |
# File to modify | |
local dhcp_config="/etc/default/isc-dhcp-server" | |
local dhcp_block=$(cat << EOF | |
option classless-win code 249 = array of unsigned integer 8; | |
subnet $vpnbase netmask $vpnnetmask { | |
range $dhcpstart $dhcpend; | |
option routers $vpngateway; | |
option subnet-mask $vpnnetmask; | |
option domain-name-servers 1.1.1.1; | |
} | |
EOF | |
) | |
# Comment out INTERFACESv6 line if present | |
sed -i 's/^\(INTERFACESv6=.*\)$/#\1/' "$dhcp_config" | |
# Update INTERFACESv4 with the new tap interface | |
sed -i "s|^INTERFACESv4=.*|INTERFACESv4=\"$tapinterface\"|" "$dhcp_config" | |
echo "$dhcp_block" >> /etc/dhcp/dhcpd.conf | |
echo "updated dhcp server settings" | |
} | |
#set up script to restart server on reboot | |
function setup_autorun_script { | |
echo "mkdir -p /run/softether" > /root/vpnstartup.sh | |
echo "mkdir -p /var/log/softether" >> /root/vpnstartup.sh | |
echo "mkdir -p /var/lib/softether" >> /root/vpnstartup.sh | |
echo "vpnserver start" >> /root/vpnstartup.sh | |
echo "sleep 10" >> /root/vpnstartup.sh | |
echo "ip addr add $vpngateway/$vpncidr dev $tapinterface" >> /root/vpnstartup.sh | |
if [[ $configiptables == "y" ]]; then | |
echo "iptables-restore /root/nat.conf" >> /root/vpnstartup.sh | |
fi | |
echo "sleep 1" >> /root/vpnstartup.sh | |
echo "systemctl start isc-dhcp-server" >> /root/vpnstartup.sh | |
echo "Created Auto startup script at /root/vpnstartup.sh" | |
} | |
#configure systemctl to call startup script | |
function setup_systemctl { | |
local systemctl=$(cat << EOF | |
[Unit] | |
Description=Start softether vpn server and apply ip | |
After=network.target | |
[Service] | |
Type=simple | |
ExecStart=/bin/bash /root/vpnstartup.sh | |
RemainAfterExit=yes | |
User=root | |
[Install] | |
WantedBy=multi-user.target | |
EOF | |
) | |
echo "$systemctl" > /etc/systemd/system/vpnserver.service | |
systemctl daemon-reload | |
systemctl enable vpnserver.service | |
echo "installed and enabled systemctl startup script" | |
} | |
#we are using root as our working directory | |
cd /root | |
install_dependencies | |
install_softether | |
if [[ -n "$domain" ]]; then | |
get_cert | |
fi | |
initial_setup | |
if [[ "$configiptables" == "y" ]]; then | |
config_iptables | |
fi | |
config_forwarding | |
config_dhcp | |
setup_autorun_script | |
setup_systemctl | |
#now do our initial start here | |
ip addr add $vpngateway/$vpncidr dev $tapinterface | |
systemctl restart isc-dhcp-server |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment