- Add wg0 interface cleanup before startup (prevents 'already exists' crash) - Always regenerate wg0.conf to pick up key changes - Remove obsolete 'version' from docker-compose files - Fix read-only /proc/sys writes (host-level ip_forward already set)
145 lines
7.2 KiB
Bash
145 lines
7.2 KiB
Bash
#!/usr/bin/env bash
|
||
# =============================================================================
|
||
# WireGuard VPS Tunnel — точка входа сервера (VPS)
|
||
# Генерирует конфигурацию wg0.conf из переменных окружения и поднимает туннель.
|
||
# =============================================================================
|
||
set -euo pipefail
|
||
|
||
# ── Значения по умолчанию ───────────────────────────────────────────────────
|
||
SERVER_WG_IP="${SERVER_WG_IP:-10.0.0.1}"
|
||
SERVER_WG_PORT="${SERVER_WG_PORT:-51820}"
|
||
FORWARD_PORTS="${FORWARD_PORTS:-80,443}"
|
||
WG_CONF="/etc/wireguard/wg0.conf"
|
||
|
||
# ── Логирование ─────────────────────────────────────────────────────────────
|
||
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$1] $*"; }
|
||
|
||
# ── Автоопределение внешнего интерфейса и IP ────────────────────────────────
|
||
detect_network() {
|
||
if [[ -z "${SERVER_PUBLIC_IFACE:-}" ]]; then
|
||
SERVER_PUBLIC_IFACE=$(ip route get 8.8.8.8 2>/dev/null | awk '{print $5; exit}')
|
||
if [[ -z "$SERVER_PUBLIC_IFACE" ]]; then
|
||
log "ERROR" "Не удалось определить внешний сетевой интерфейс"
|
||
exit 1
|
||
fi
|
||
log "INFO" "Автоопределён внешний интерфейс: ${SERVER_PUBLIC_IFACE}"
|
||
fi
|
||
|
||
if [[ -z "${SERVER_PUBLIC_IP:-}" ]]; then
|
||
SERVER_PUBLIC_IP=$(curl -4 -s ifconfig.me 2>/dev/null || curl -4 -s icanhazip.com 2>/dev/null || echo "")
|
||
if [[ -z "$SERVER_PUBLIC_IP" ]]; then
|
||
log "ERROR" "Не удалось определить публичный IP. Укажите SERVER_PUBLIC_IP"
|
||
exit 1
|
||
fi
|
||
log "INFO" "Автоопределён публичный IP: ${SERVER_PUBLIC_IP}"
|
||
fi
|
||
}
|
||
|
||
# ── Генерация ключей ───────────────────────────────────────────────────────
|
||
generate_keys() {
|
||
local private_key_file="/etc/wireguard/server_private.key"
|
||
local public_key_file="/etc/wireguard/server_public.key"
|
||
|
||
if [[ -f "$private_key_file" ]] && [[ -f "$public_key_file" ]]; then
|
||
log "INFO" "Ключи сервера уже существуют"
|
||
else
|
||
log "INFO" "Генерация ключей сервера..."
|
||
wg genkey | tee "$private_key_file" | wg pubkey > "$public_key_file"
|
||
chmod 600 "$private_key_file"
|
||
log "INFO" "Ключи сервера сгенерированы"
|
||
fi
|
||
|
||
SERVER_PRIVATE_KEY=$(cat "$private_key_file")
|
||
SERVER_PUBLIC_KEY=$(cat "$public_key_file")
|
||
}
|
||
|
||
# ── Создание конфигурации WireGuard ────────────────────────────────────────
|
||
create_wg_config() {
|
||
# Всегда пересоздаём конфиг — ключи или порты могли измениться
|
||
if [[ -f "$WG_CONF" ]]; then
|
||
log "INFO" "Обновление конфигурации ${WG_CONF}..."
|
||
rm -f "$WG_CONF"
|
||
fi
|
||
|
||
if [[ -z "${CLIENT_PUBLIC_KEY:-}" ]]; then
|
||
log "ERROR" "CLIENT_PUBLIC_KEY не задан. Укажите публичный ключ клиента."
|
||
exit 1
|
||
fi
|
||
|
||
local client_wg_ip="${CLIENT_WG_IP:-10.0.0.2}"
|
||
|
||
# Формируем правила DNAT для каждого порта
|
||
local dnat_rules=""
|
||
local dnat_down_rules=""
|
||
IFS=',' read -ra PORT_ARRAY <<< "$FORWARD_PORTS"
|
||
|
||
for port in "${PORT_ARRAY[@]}"; do
|
||
port=$(echo "$port" | xargs)
|
||
dnat_rules+="iptables -t nat -A PREROUTING -d ${SERVER_PUBLIC_IP} -p tcp --dport ${port} -j DNAT --to-destination ${client_wg_ip}:${port}; "
|
||
dnat_down_rules+="iptables -t nat -D PREROUTING -d ${SERVER_PUBLIC_IP} -p tcp --dport ${port} -j DNAT --to-destination ${client_wg_ip}:${port}; "
|
||
done
|
||
|
||
mkdir -p "$(dirname "$WG_CONF")"
|
||
|
||
cat > "$WG_CONF" <<WGCONF
|
||
# WireGuard VPS Tunnel — конфигурация сервера (VPS)
|
||
# Создано: $(date '+%Y-%m-%d %H:%M:%S')
|
||
|
||
[Interface]
|
||
PrivateKey = ${SERVER_PRIVATE_KEY}
|
||
Address = ${SERVER_WG_IP}/24
|
||
ListenPort = ${SERVER_WG_PORT}
|
||
|
||
PostUp = ${dnat_rules} iptables -t nat -A POSTROUTING -d ${client_wg_ip} -j MASQUERADE; iptables -I FORWARD 1 -i ${SERVER_PUBLIC_IFACE} -o wg0 -p tcp -m multiport --dports ${FORWARD_PORTS} -j ACCEPT; iptables -I FORWARD 2 -i wg0 -o ${SERVER_PUBLIC_IFACE} -m state --state ESTABLISHED,RELATED -j ACCEPT; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT
|
||
PostDown = ${dnat_down_rules} iptables -t nat -D POSTROUTING -d ${client_wg_ip} -j MASQUERADE; iptables -D FORWARD -i ${SERVER_PUBLIC_IFACE} -o wg0 -p tcp -m multiport --dports ${FORWARD_PORTS} -j ACCEPT; iptables -D FORWARD -i wg0 -o ${SERVER_PUBLIC_IFACE} -m state --state ESTABLISHED,RELATED -j ACCEPT; iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT
|
||
|
||
[Peer]
|
||
# Клиент (домашний сервер / Raspberry Pi)
|
||
PublicKey = ${CLIENT_PUBLIC_KEY}
|
||
AllowedIPs = ${client_wg_ip}/32
|
||
WGCONF
|
||
|
||
chmod 600 "$WG_CONF"
|
||
log "INFO" "Конфигурация WireGuard создана: ${WG_CONF}"
|
||
}
|
||
|
||
# ── Запуск WireGuard ───────────────────────────────────────────────────────
|
||
start_wireguard() {
|
||
log "INFO" "Запуск WireGuard интерфейса wg0..."
|
||
|
||
# Включаем IP-форвардинг (может быть read-only в Docker, хост уже настроен)
|
||
echo 1 > /proc/sys/net/ipv4/ip_forward 2>/dev/null || true
|
||
echo 1 > /proc/sys/net/ipv6/conf/all/forwarding 2>/dev/null || true
|
||
|
||
# Удаляем старый интерфейс если остался от предыдущего запуска
|
||
if ip link show wg0 &>/dev/null; then
|
||
log "INFO" "Удаление старого интерфейса wg0..."
|
||
ip link del wg0 2>/dev/null || true
|
||
sleep 1
|
||
fi
|
||
|
||
wg-quick up wg0
|
||
|
||
log "INFO" "WireGuard интерфейс wg0 запущен"
|
||
log "INFO" "Публичный ключ сервера: ${SERVER_PUBLIC_KEY}"
|
||
log "INFO" "Скопируйте его на клиент: SERVER_PUBLIC_KEY=${SERVER_PUBLIC_KEY}"
|
||
}
|
||
|
||
# ── Главная функция ────────────────────────────────────────────────────────
|
||
main() {
|
||
log "INFO" "=== Запуск WireGuard VPS Tunnel (сервер) ==="
|
||
log "INFO" "SERVER_WG_IP=${SERVER_WG_IP}"
|
||
log "INFO" "SERVER_WG_PORT=${SERVER_WG_PORT}"
|
||
log "INFO" "FORWARD_PORTS=${FORWARD_PORTS}"
|
||
|
||
detect_network
|
||
generate_keys
|
||
create_wg_config
|
||
start_wireguard
|
||
|
||
log "INFO" "Сервер запущен. Ожидание..."
|
||
exec sleep infinity
|
||
}
|
||
|
||
main
|