Skip to content

Instantly share code, notes, and snippets.

@WinkelCode
Last active May 2, 2023 09:17
Show Gist options
  • Save WinkelCode/edce26cc99652e2d4bfeda44b0b21248 to your computer and use it in GitHub Desktop.
Save WinkelCode/edce26cc99652e2d4bfeda44b0b21248 to your computer and use it in GitHub Desktop.
WireGuard Config Generator
#!/usr/bin/env bash
wgcmd="wg"
if command -v qrencode >/dev/null 2>&1; then
generate_qr="true"
else
generate_qr="false"
fi
echo "WireGuard configuration file generator"
echo "======================================"
echo
if [ $# -ne 3 ]; then
echo "Usage: $0 <# of peers> <IP range (i.e. 10.0.0.0/24)> <output directory (put '.' for current dir)>"
exit 1
fi
generate_interface() {
# <peer name> <peer_private_key> <peer_public_key> <peer_ip> <vpn_netmask> <peer_endpoint>
peer_name="$1"
peer_private_key="$2"
peer_ip="$4"
vpn_netmask="$5"
peer_endpoint="$6"
echo "$(cat <<-EOF
# This Peer: '$peer_name' (Public Key: $peer_public_key)
[Interface]
PrivateKey = $peer_private_key
Address = ${peer_ip}/${vpn_netmask}
$(if [ "$peer_endpoint" != "roaming" ]; then printf "ListenPort = %s" "${peer_endpoint#*:}"; fi)
EOF
)"
}
generate_peer() {
# <peer name> <peer_public_key> <peer_psk> <peer_ip> <peer_endpoint>
peer_name="$1"
peer_public_key="$2"
peer_psk="$3"
peer_ip="$4"
peer_endpoint="$5"
echo "$(cat <<-EOF
# '$peer_name'
[Peer]
PublicKey = $peer_public_key
PresharedKey = $peer_psk
AllowedIPs = ${peer_ip}/32
$(if [ "$peer_endpoint" != "roaming" ]; then printf "Endpoint = %s" "${peer_endpoint}"; fi)
EOF
)"
}
num_peers="$1"
vpn_netmask="${2##*/}"
if [ "$vpn_netmask" = "$2" ]; then
echo "Error: No netmask specified (i.e. 10.0.0.0/24)"
exit 1
fi
ip_range="${2%/*}" # Remove netmask
ip_range="${ip_range%.*}" # Remove last octet
output_dir="$3"
if [ ! -d "$output_dir" ]; then
mkdir -p "$output_dir" || { echo "Error: Could not create directory '$output_dir'"; exit 1; }
fi
for peer in $(seq 1 "$num_peers"); do
# Populating variables with default values
peer_name="Peer $peer"
peer_ip="${ip_range}.${peer}"
# Interactive questionnaire
read -p "[Peer $peer/$num_peers] Name (Default = $peer_name): "; peer_name=${REPLY:-$peer_name}
read -p "[Peer $peer/$num_peers] VPN IP (Default = $peer_ip): "; peer_ip=${REPLY:-$peer_ip}
read -p "[Peer $peer/$num_peers] Peer [R]oaming or [S]tatic (Default = Roaming): "
case "$REPLY" in
[Ss]* )
read -p "[Peer $peer/$num_peers] Endpoint [IP(:51820) or IP:Port]: " peer_endpoint
# If peer_endpoint didn't contain a port, add the default port 51820
if [ "${peer_endpoint#*:}" = "$peer_endpoint" ]; then
peer_endpoint="${peer_endpoint}:51820"
fi
;;
* | [Rr]* )
peer_endpoint="roaming"
;;
esac
# Generate keys
peer_private_key="$($wgcmd genkey)" || { echo "Error: Could not generate private key"; exit 1; }
peer_public_key="$($wgcmd pubkey <<<"$peer_private_key")" || { echo "Error: Could not generate public key"; exit 1; }
# Set variables
eval peer_${peer}_name=\"$peer_name\"
eval peer_${peer}_ip=\"$peer_ip\"
eval peer_${peer}_endpoint=\"$peer_endpoint\"
eval peer_${peer}_private_key=\"$peer_private_key\"
eval peer_${peer}_public_key=\"$peer_public_key\"
done
# Generate preshared keys between peers
for peer in $(seq 1 "$num_peers"); do
for peer2 in $(seq $(($peer + 1)) $num_peers); do # seq automatically produces no output if $peer2 is greater than $num_peers
peers_psk="$($wgcmd genpsk)"
eval peer_${peer}_peer_${peer2}_psk=\"$peers_psk\"
done
done
for peer in $(seq 1 "$num_peers"); do
out_file="$output_dir/peer${peer}.conf"
out_file_qr="$output_dir/peer${peer}qr.txt"
# Retrieve variables for current peer
peer_name="$(eval echo \$peer_${peer}_name)"
peer_ip="$(eval echo \$peer_${peer}_ip)"
peer_endpoint="$(eval echo \$peer_${peer}_endpoint)"
peer_private_key="$(eval echo \$peer_${peer}_private_key)"
peer_public_key="$(eval echo \$peer_${peer}_public_key)"
touch "$out_file" || { echo "Error: Could not create file '$out_file'"; exit 1; }
# Generate interface section
generate_interface "$peer_name" "$peer_private_key" "$peer_public_key" "$peer_ip" "$vpn_netmask" "$peer_endpoint" >"$out_file"
echo >>"$out_file"
for peer2 in $(seq 1 "$num_peers"); do
if [ $peer2 -ne $peer ]; then
# Retrieve variables for peer to be added
peer2_name="$(eval echo \$peer_${peer2}_name)"
peer2_ip="$(eval echo \$peer_${peer2}_ip)"
peer2_endpoint="$(eval echo \$peer_${peer2}_endpoint)"
peer2_public_key="$(eval echo \$peer_${peer2}_public_key)"
if [ $peer2 -gt $peer ]; then
peers_psk="$(eval echo \$peer_${peer}_peer_${peer2}_psk)"
else
peers_psk="$(eval echo \$peer_${peer2}_peer_${peer}_psk)"
fi
# Generate peer section
generate_peer "$peer2_name" "$peer2_public_key" "$peers_psk" "$peer2_ip" "$peer2_endpoint" >>"$out_file"
fi
done
echo -n "Peer $peer ('$(eval echo \$peer_${peer}_name)') with VPN IP '$(eval echo \$peer_${peer}_ip)' generated in '$out_file'"
if [ "$generate_qr" = "true" ]; then
echo "WireGuard configuration QR code for peer $peer ('$(eval echo \$peer_${peer}_name)') with VPN IP '$(eval echo \$peer_${peer}_ip)':" >"$out_file_qr"
qrencode -t ansiutf8 <"$out_file" >>"$out_file_qr"
echo " + QR code in '$out_file_qr'"
else
echo
fi
done
echo "Done!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment