152 lines
4.9 KiB
Bash
152 lines
4.9 KiB
Bash
#!/usr/bin/env bash
|
||
# ovpn-p2p.sh — OpenVPN только для связи клиентов между собой.
|
||
# Интернет-трафик и DNS клиентов через VPN НЕ идут.
|
||
#
|
||
# ./ovpn-p2p.sh install <публичный_IP_или_домен>
|
||
# ./ovpn-p2p.sh add <имя> <vpn_ip> # пример: add pc1 10.8.0.11
|
||
# ./ovpn-p2p.sh revoke <имя>
|
||
#
|
||
# Требования: Debian 11+/Ubuntu 22.04+ (OpenVPN 2.5+), запуск от root.
|
||
set -euo pipefail
|
||
|
||
PORT="${PORT:-1194}"
|
||
NET="10.8.0.0"
|
||
MASK="255.255.255.0"
|
||
SRV=/etc/openvpn/server
|
||
PKI_DIR=$SRV/easy-rsa
|
||
OUT=/root/ovpn-clients
|
||
export EASYRSA_CRL_DAYS=3650 # иначе через 180 дней CRL протухнет и сервер перестанет пускать всех
|
||
|
||
die(){ echo "ERROR: $*" >&2; exit 1; }
|
||
[[ $EUID -eq 0 ]] || die "запускай от root"
|
||
|
||
update_crl(){
|
||
cd "$PKI_DIR"
|
||
./easyrsa --batch gen-crl
|
||
cp pki/crl.pem "$SRV/crl.pem"
|
||
chmod 644 "$SRV/crl.pem"
|
||
}
|
||
|
||
cmd_install(){
|
||
local host="${1:-}"
|
||
[[ -n $host ]] || die "usage: $0 install <публичный_IP_или_домен>"
|
||
|
||
apt-get update
|
||
apt-get install -y openvpn easy-rsa openssl
|
||
mkdir -p "$SRV/ccd" /var/log/openvpn "$OUT"
|
||
echo "$host" > "$SRV/public_host"
|
||
|
||
[[ -d $PKI_DIR ]] || make-cadir "$PKI_DIR"
|
||
cd "$PKI_DIR"
|
||
[[ -d pki ]] || ./easyrsa --batch init-pki
|
||
[[ -f pki/ca.crt ]] || EASYRSA_REQ_CN="p2p-vpn-ca" ./easyrsa --batch build-ca nopass
|
||
[[ -f pki/issued/server.crt ]] || ./easyrsa --batch build-server-full server nopass
|
||
cp pki/ca.crt pki/issued/server.crt pki/private/server.key "$SRV/"
|
||
[[ -f $SRV/ta.key ]] || openvpn --genkey secret "$SRV/ta.key"
|
||
update_crl
|
||
|
||
cat > "$SRV/server.conf" <<EOF
|
||
port $PORT
|
||
proto udp
|
||
dev tun
|
||
topology subnet
|
||
server $NET $MASK
|
||
|
||
# Клиенты видят друг друга
|
||
client-to-client
|
||
# Статические IP по имени сертификата; клиенты без файла в ccd не пускаются
|
||
client-config-dir $SRV/ccd
|
||
ccd-exclusive
|
||
|
||
# НИКАКИХ push "redirect-gateway" / push "dhcp-option DNS" — трафик клиентов не перехватываем
|
||
|
||
ca $SRV/ca.crt
|
||
cert $SRV/server.crt
|
||
key $SRV/server.key
|
||
dh none
|
||
tls-crypt $SRV/ta.key
|
||
crl-verify $SRV/crl.pem
|
||
data-ciphers AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305
|
||
|
||
keepalive 10 60
|
||
persist-key
|
||
persist-tun
|
||
user nobody
|
||
group nogroup
|
||
status /var/log/openvpn/status.log
|
||
verb 3
|
||
explicit-exit-notify 1
|
||
EOF
|
||
|
||
if command -v ufw >/dev/null && ufw status | grep -q "Status: active"; then
|
||
ufw allow "${PORT}/udp"
|
||
fi
|
||
|
||
systemctl enable openvpn-server@server
|
||
systemctl restart openvpn-server@server
|
||
systemctl --no-pager status openvpn-server@server | head -n 5
|
||
echo
|
||
echo "Сервер готов. Теперь добавь клиентов: $0 add pc1 10.8.0.11"
|
||
}
|
||
|
||
cmd_add(){
|
||
local name="${1:-}" ip="${2:-}"
|
||
[[ -n $name && -n $ip ]] || die "usage: $0 add <имя> <vpn_ip, например 10.8.0.11>"
|
||
[[ -f $SRV/server.conf ]] || die "сначала: $0 install <host>"
|
||
[[ $ip =~ ^10\.8\.0\.([0-9]+)$ ]] && (( BASH_REMATCH[1] >= 2 && BASH_REMATCH[1] <= 254 )) \
|
||
|| die "IP должен быть в диапазоне 10.8.0.2–10.8.0.254"
|
||
|
||
for f in "$SRV"/ccd/*; do
|
||
[[ -f $f && $(basename "$f") != "$name" ]] || continue
|
||
grep -qx "ifconfig-push $ip $MASK" "$f" && die "IP $ip уже занят клиентом $(basename "$f")"
|
||
done
|
||
|
||
cd "$PKI_DIR"
|
||
[[ -f pki/issued/$name.crt ]] || ./easyrsa --batch build-client-full "$name" nopass
|
||
echo "ifconfig-push $ip $MASK" > "$SRV/ccd/$name"
|
||
|
||
local host; host=$(cat "$SRV/public_host")
|
||
mkdir -p "$OUT"
|
||
{
|
||
cat <<EOF
|
||
client
|
||
dev tun
|
||
proto udp
|
||
remote $host $PORT
|
||
resolv-retry infinite
|
||
nobind
|
||
persist-key
|
||
persist-tun
|
||
remote-cert-tls server
|
||
data-ciphers AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305
|
||
# Страховка: даже если сервер что-то пушнет — не отдаём ему маршрут по умолчанию и DNS
|
||
pull-filter ignore "redirect-gateway"
|
||
pull-filter ignore "dhcp-option"
|
||
verb 3
|
||
EOF
|
||
echo "<ca>"; cat pki/ca.crt; echo "</ca>"
|
||
echo "<cert>"; openssl x509 -in "pki/issued/$name.crt"; echo "</cert>"
|
||
echo "<key>"; cat "pki/private/$name.key"; echo "</key>"
|
||
echo "<tls-crypt>"; cat "$SRV/ta.key"; echo "</tls-crypt>"
|
||
} > "$OUT/$name.ovpn"
|
||
chmod 600 "$OUT/$name.ovpn"
|
||
echo "Готово: $OUT/$name.ovpn (VPN IP: $ip)"
|
||
}
|
||
|
||
cmd_revoke(){
|
||
local name="${1:-}"
|
||
[[ -n $name ]] || die "usage: $0 revoke <имя>"
|
||
cd "$PKI_DIR"
|
||
./easyrsa --batch revoke "$name"
|
||
update_crl
|
||
rm -f "$SRV/ccd/$name" "$OUT/$name.ovpn"
|
||
systemctl restart openvpn-server@server
|
||
echo "Клиент $name отозван."
|
||
}
|
||
|
||
case "${1:-}" in
|
||
install) shift; cmd_install "$@" ;;
|
||
add) shift; cmd_add "$@" ;;
|
||
revoke) shift; cmd_revoke "$@" ;;
|
||
*) echo "usage: $0 {install <host> | add <name> <ip> | revoke <name>}"; exit 1 ;;
|
||
esac |