Created
March 3, 2025 13:34
-
-
Save legout/25b80e0d8233ae99910fb28442d622f2 to your computer and use it in GitHub Desktop.
Setup Docker Swarm and Wireguard VPN
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 | |
# WireGuard VPN Setup Script for Docker Swarm | |
# This script sets up a WireGuard VPN between multiple VPS servers | |
# Error handling | |
set -e | |
trap 'echo "Error on line $LINENO. Exiting."; exit 1' ERR | |
# Check if running as sudo/root | |
if [ "$(id -u)" -ne 0 ]; then | |
echo "This script must be run with sudo privileges" | |
exit 1 | |
fi | |
# Configuration variables | |
SERVER_IP=$(hostname -I | awk '{print $1}') | |
VPN_SUBNET="10.10.10.0/24" | |
VPN_PORT=51820 | |
VPN_DIR="/etc/wireguard" | |
SERVER_PRIVATE_KEY="${VPN_DIR}/privatekey" | |
SERVER_PUBLIC_KEY="${VPN_DIR}/publickey" | |
WG_CONF="${VPN_DIR}/wg0.conf" | |
# Node info collection function | |
collect_node_info() { | |
read -p "Is this the main VPN server node? (y/n): " IS_MAIN_NODE | |
if [[ "$IS_MAIN_NODE" == "y" ]]; then | |
read -p "How many total nodes in your swarm (including this one)? " TOTAL_NODES | |
# This node will be 10.10.10.1 | |
VPN_IP="10.10.10.1" | |
else | |
read -p "Enter the IP address of the main VPN server: " MAIN_SERVER_IP | |
read -p "Enter the public key of the main VPN server: " MAIN_SERVER_PUBKEY | |
read -p "Enter the VPN IP for this node (e.g., 10.10.10.2): " VPN_IP | |
fi | |
} | |
# Install WireGuard | |
install_wireguard() { | |
echo "Installing WireGuard..." | |
apt-get update | |
apt-get install -y wireguard | |
# Generate key pair | |
mkdir -p "$VPN_DIR" | |
chmod 700 "$VPN_DIR" | |
wg genkey | tee "$SERVER_PRIVATE_KEY" | wg pubkey > "$SERVER_PUBLIC_KEY" | |
chmod 600 "$SERVER_PRIVATE_KEY" | |
# Show public key | |
echo "Your WireGuard public key is:" | |
cat "$SERVER_PUBLIC_KEY" | |
echo "Keep a note of this key to configure the other nodes." | |
} | |
# Configure main server node | |
configure_main_server() { | |
echo "Configuring the main VPN server node..." | |
# Create basic server config | |
cat > "$WG_CONF" <<EOF | |
[Interface] | |
PrivateKey = $(cat "$SERVER_PRIVATE_KEY") | |
Address = ${VPN_IP}/24 | |
ListenPort = ${VPN_PORT} | |
SaveConfig = true | |
# Docker Swarm requires masquerading for cross-node communication | |
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o $(ip route get 1.1.1.1 | awk '{print $5}') -j MASQUERADE | |
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o $(ip route get 1.1.1.1 | awk '{print $5}') -j MASQUERADE | |
EOF | |
# Enable IP forwarding | |
echo "net.ipv4.ip_forward = 1" > /etc/sysctl.d/99-wireguard.conf | |
sysctl -p /etc/sysctl.d/99-wireguard.conf | |
echo "Main server configuration complete." | |
echo "For each additional node, you'll need to add a peer section to this server's config." | |
echo "Example peer section to add for each node:" | |
echo "[Peer]" | |
echo "PublicKey = <OTHER_NODE_PUBLIC_KEY>" | |
echo "AllowedIPs = 10.10.10.X/32" | |
} | |
# Configure client node | |
configure_client_node() { | |
echo "Configuring VPN client node..." | |
# Create client config | |
cat > "$WG_CONF" <<EOF | |
[Interface] | |
PrivateKey = $(cat "$SERVER_PRIVATE_KEY") | |
Address = ${VPN_IP}/24 | |
[Peer] | |
PublicKey = ${MAIN_SERVER_PUBKEY} | |
Endpoint = ${MAIN_SERVER_IP}:${VPN_PORT} | |
AllowedIPs = ${VPN_SUBNET} | |
PersistentKeepalive = 25 | |
EOF | |
# Enable IP forwarding | |
echo "net.ipv4.ip_forward = 1" > /etc/sysctl.d/99-wireguard.conf | |
sysctl -p /etc/sysctl.d/99-wireguard.conf | |
echo "Client node configuration complete." | |
} | |
# Enable WireGuard Service | |
enable_wireguard() { | |
echo "Enabling WireGuard service..." | |
systemctl enable wg-quick@wg0 | |
systemctl start wg-quick@wg0 | |
echo "WireGuard service enabled and started." | |
echo "Current WireGuard status:" | |
wg show | |
} | |
# Update Docker Swarm to use VPN IPs | |
update_docker_swarm() { | |
echo "Updating Docker Swarm configuration..." | |
# If this is the main node, no need to leave and rejoin | |
if [[ "$IS_MAIN_NODE" == "y" ]]; then | |
echo "Updating the advertise address for the main node..." | |
docker swarm init --advertise-addr ${VPN_IP} --force-new-cluster | |
# Get new join tokens | |
WORKER_TOKEN=$(docker swarm join-token worker -q) | |
MANAGER_TOKEN=$(docker swarm join-token manager -q) | |
echo "New worker join token: ${WORKER_TOKEN}" | |
echo "New manager join token: ${MANAGER_TOKEN}" | |
echo "Other nodes should join using: docker swarm join --token <TOKEN> ${VPN_IP}:2377" | |
else | |
echo "To update this node in the swarm:" | |
echo "1. First leave the swarm with: docker swarm leave --force" | |
echo "2. Then rejoin using the VPN IP of the main node: docker swarm join --token <TOKEN> 10.10.10.1:2377" | |
fi | |
} | |
# Main execution | |
main() { | |
echo "Starting WireGuard VPN setup for Docker Swarm..." | |
collect_node_info | |
install_wireguard | |
if [[ "$IS_MAIN_NODE" == "y" ]]; then | |
configure_main_server | |
else | |
configure_client_node | |
fi | |
enable_wireguard | |
update_docker_swarm | |
echo "WireGuard VPN setup complete!" | |
echo "Your VPN IP is: ${VPN_IP}" | |
echo "Remember to configure all other nodes and update the main server's config with each new peer." | |
} | |
# Run the script | |
main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment