Last active
May 2, 2023 09:17
-
-
Save WinkelCode/edce26cc99652e2d4bfeda44b0b21248 to your computer and use it in GitHub Desktop.
WireGuard Config Generator
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
#!/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