Skip to content

Instantly share code, notes, and snippets.

@legout
Created March 3, 2025 13:34
Show Gist options
  • Save legout/25b80e0d8233ae99910fb28442d622f2 to your computer and use it in GitHub Desktop.
Save legout/25b80e0d8233ae99910fb28442d622f2 to your computer and use it in GitHub Desktop.
Setup Docker Swarm and Wireguard VPN
#!/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