mirror of
https://github.com/wahyd4/docker-ipsec-vpn-server.git
synced 2026-08-09 04:46:22 +10:00
290 lines
8.5 KiB
Bash
290 lines
8.5 KiB
Bash
#!/bin/sh
|
|
#
|
|
# Docker script to configure and start an IPsec VPN server
|
|
#
|
|
# DO NOT RUN THIS SCRIPT ON YOUR PC OR MAC! THIS IS ONLY MEANT TO BE RUN
|
|
# IN A DOCKER CONTAINER!
|
|
#
|
|
# This file is part of IPsec VPN Docker image, available at:
|
|
# https://github.com/hwdsl2/docker-ipsec-vpn-server
|
|
#
|
|
# Copyright (C) 2016-2017 Lin Song <linsongui@gmail.com>
|
|
# Based on the work of Thomas Sarlandie (Copyright 2012)
|
|
#
|
|
# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0
|
|
# Unported License: http://creativecommons.org/licenses/by-sa/3.0/
|
|
#
|
|
# Attribution required: please include my name in any derivative and let me
|
|
# know how you have improved it!
|
|
|
|
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
|
|
exiterr() { echo "Error: $1" >&2; exit 1; }
|
|
nospaces() { printf '%s' "$1" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'; }
|
|
noquotes() { printf '%s' "$1" | sed -e 's/^"\(.*\)"$/\1/' -e "s/^'\(.*\)'$/\1/"; }
|
|
|
|
check_ip() {
|
|
IP_REGEX='^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'
|
|
printf '%s' "$1" | tr -d '\n' | grep -Eq "$IP_REGEX"
|
|
}
|
|
|
|
if [ ! -f "/.dockerenv" ]; then
|
|
exiterr "This script ONLY runs in a Docker container."
|
|
fi
|
|
|
|
if ip link add dummy0 type dummy 2>&1 | grep -q "not permitted"; then
|
|
cat 1>&2 <<'EOF'
|
|
Error: This Docker image must be run in privileged mode.
|
|
|
|
For detailed instructions, please visit:
|
|
https://github.com/hwdsl2/docker-ipsec-vpn-server
|
|
|
|
EOF
|
|
exit 1
|
|
fi
|
|
ip link delete dummy0 >/dev/null 2>&1
|
|
|
|
mkdir -p /opt/src
|
|
vpn_env="/opt/src/vpn-gen.env"
|
|
if [ -z "$VPN_IPSEC_PSK" ] && [ -z "$VPN_USER" ] && [ -z "$VPN_PASSWORD" ]; then
|
|
if [ -f "$vpn_env" ]; then
|
|
echo
|
|
echo "Retrieving previously generated VPN credentials..."
|
|
. "$vpn_env"
|
|
else
|
|
echo
|
|
echo "VPN credentials not set by user. Generating random PSK and password..."
|
|
VPN_IPSEC_PSK="$(LC_CTYPE=C tr -dc 'A-HJ-NPR-Za-km-z2-9' < /dev/urandom | head -c 16)"
|
|
VPN_USER=vpnuser
|
|
VPN_PASSWORD="$(LC_CTYPE=C tr -dc 'A-HJ-NPR-Za-km-z2-9' < /dev/urandom | head -c 16)"
|
|
|
|
echo "VPN_IPSEC_PSK=$VPN_IPSEC_PSK" > "$vpn_env"
|
|
echo "VPN_USER=$VPN_USER" >> "$vpn_env"
|
|
echo "VPN_PASSWORD=$VPN_PASSWORD" >> "$vpn_env"
|
|
chmod 600 "$vpn_env"
|
|
fi
|
|
fi
|
|
|
|
# Remove whitespace and quotes around VPN variables, if any
|
|
VPN_IPSEC_PSK="$(nospaces "$VPN_IPSEC_PSK")"
|
|
VPN_IPSEC_PSK="$(noquotes "$VPN_IPSEC_PSK")"
|
|
VPN_USER="$(nospaces "$VPN_USER")"
|
|
VPN_USER="$(noquotes "$VPN_USER")"
|
|
VPN_PASSWORD="$(nospaces "$VPN_PASSWORD")"
|
|
VPN_PASSWORD="$(noquotes "$VPN_PASSWORD")"
|
|
|
|
if [ -z "$VPN_IPSEC_PSK" ] || [ -z "$VPN_USER" ] || [ -z "$VPN_PASSWORD" ]; then
|
|
exiterr "All VPN credentials must be specified. Edit your 'env' file and re-enter them."
|
|
fi
|
|
|
|
if printf '%s' "$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD" | LC_ALL=C grep -q '[^ -~]\+'; then
|
|
exiterr "VPN credentials must not contain non-ASCII characters."
|
|
fi
|
|
|
|
case "$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD" in
|
|
*[\\\"\']*)
|
|
exiterr "VPN credentials must not contain these special characters: \\ \" '"
|
|
;;
|
|
esac
|
|
|
|
echo
|
|
echo 'Trying to auto discover IP of this server...'
|
|
|
|
# In case auto IP discovery fails, manually define the public IP
|
|
# of this server in your 'env' file, as variable 'VPN_PUBLIC_IP'.
|
|
PUBLIC_IP=${VPN_PUBLIC_IP:-''}
|
|
|
|
# Try to auto discover IP of this server
|
|
[ -z "$PUBLIC_IP" ] && PUBLIC_IP=$(dig @resolver1.opendns.com -t A -4 myip.opendns.com +short)
|
|
|
|
# Check IP for correct format
|
|
check_ip "$PUBLIC_IP" || PUBLIC_IP=$(wget -t 3 -T 15 -qO- http://ipv4.icanhazip.com)
|
|
check_ip "$PUBLIC_IP" || exiterr "Cannot detect this server's public IP. Define it in your 'env' file as 'VPN_PUBLIC_IP'."
|
|
|
|
L2TP_NET=${VPN_L2TP_NET:-'192.168.42.0/24'}
|
|
L2TP_LOCAL=${VPN_L2TP_LOCAL:-'192.168.42.1'}
|
|
L2TP_POOL=${VPN_L2TP_POOL:-'192.168.42.10-192.168.42.250'}
|
|
XAUTH_NET=${VPN_XAUTH_NET:-'192.168.43.0/24'}
|
|
XAUTH_POOL=${VPN_XAUTH_POOL:-'192.168.43.10-192.168.43.250'}
|
|
DNS_SRV1=${VPN_DNS_SRV1:-'8.8.8.8'}
|
|
DNS_SRV2=${VPN_DNS_SRV2:-'8.8.4.4'}
|
|
|
|
# Create IPsec (Libreswan) config
|
|
cat > /etc/ipsec.conf <<EOF
|
|
version 2.0
|
|
|
|
config setup
|
|
virtual-private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!$L2TP_NET,%v4:!$XAUTH_NET
|
|
protostack=netkey
|
|
interfaces=%defaultroute
|
|
uniqueids=no
|
|
|
|
conn shared
|
|
left=%defaultroute
|
|
leftid=$PUBLIC_IP
|
|
right=%any
|
|
encapsulation=yes
|
|
authby=secret
|
|
pfs=no
|
|
rekey=no
|
|
keyingtries=5
|
|
dpddelay=30
|
|
dpdtimeout=120
|
|
dpdaction=clear
|
|
ike=3des-sha1,3des-sha2,aes-sha1,aes-sha1;modp1024,aes-sha2,aes-sha2;modp1024,aes256-sha2_512
|
|
phase2alg=3des-sha1,3des-sha2,aes-sha1,aes-sha2,aes256-sha2_512
|
|
sha2-truncbug=yes
|
|
|
|
conn l2tp-psk
|
|
auto=add
|
|
leftprotoport=17/1701
|
|
rightprotoport=17/%any
|
|
type=transport
|
|
phase2=esp
|
|
also=shared
|
|
|
|
conn xauth-psk
|
|
auto=add
|
|
leftsubnet=0.0.0.0/0
|
|
rightaddresspool=$XAUTH_POOL
|
|
modecfgdns="$DNS_SRV1, $DNS_SRV2"
|
|
leftxauthserver=yes
|
|
rightxauthclient=yes
|
|
leftmodecfgserver=yes
|
|
rightmodecfgclient=yes
|
|
modecfgpull=yes
|
|
xauthby=file
|
|
ike-frag=yes
|
|
ikev2=never
|
|
cisco-unity=yes
|
|
also=shared
|
|
EOF
|
|
|
|
# Specify IPsec PSK
|
|
cat > /etc/ipsec.secrets <<EOF
|
|
%any %any : PSK "$VPN_IPSEC_PSK"
|
|
EOF
|
|
|
|
# Create xl2tpd config
|
|
cat > /etc/xl2tpd/xl2tpd.conf <<EOF
|
|
[global]
|
|
port = 1701
|
|
|
|
[lns default]
|
|
ip range = $L2TP_POOL
|
|
local ip = $L2TP_LOCAL
|
|
require chap = yes
|
|
refuse pap = yes
|
|
require authentication = yes
|
|
name = l2tpd
|
|
pppoptfile = /etc/ppp/options.xl2tpd
|
|
length bit = yes
|
|
EOF
|
|
|
|
# Set xl2tpd options
|
|
cat > /etc/ppp/options.xl2tpd <<EOF
|
|
+mschap-v2
|
|
ipcp-accept-local
|
|
ipcp-accept-remote
|
|
ms-dns $DNS_SRV1
|
|
ms-dns $DNS_SRV2
|
|
noccp
|
|
auth
|
|
mtu 1280
|
|
mru 1280
|
|
proxyarp
|
|
lcp-echo-failure 4
|
|
lcp-echo-interval 30
|
|
connect-delay 5000
|
|
EOF
|
|
|
|
# Create VPN credentials
|
|
cat > /etc/ppp/chap-secrets <<EOF
|
|
"$VPN_USER" l2tpd "$VPN_PASSWORD" *
|
|
EOF
|
|
|
|
VPN_PASSWORD_ENC=$(openssl passwd -1 "$VPN_PASSWORD")
|
|
cat > /etc/ipsec.d/passwd <<EOF
|
|
$VPN_USER:$VPN_PASSWORD_ENC:xauth-psk
|
|
EOF
|
|
|
|
# Update sysctl settings
|
|
SYST='/sbin/sysctl -e -q -w'
|
|
if [ "$(getconf LONG_BIT)" = "64" ]; then
|
|
SHM_MAX=68719476736
|
|
SHM_ALL=4294967296
|
|
else
|
|
SHM_MAX=4294967295
|
|
SHM_ALL=268435456
|
|
fi
|
|
$SYST kernel.msgmnb=65536
|
|
$SYST kernel.msgmax=65536
|
|
$SYST kernel.shmmax=$SHM_MAX
|
|
$SYST kernel.shmall=$SHM_ALL
|
|
$SYST net.ipv4.ip_forward=1
|
|
$SYST net.ipv4.conf.all.accept_source_route=0
|
|
$SYST net.ipv4.conf.all.accept_redirects=0
|
|
$SYST net.ipv4.conf.all.send_redirects=0
|
|
$SYST net.ipv4.conf.all.rp_filter=0
|
|
$SYST net.ipv4.conf.default.accept_source_route=0
|
|
$SYST net.ipv4.conf.default.accept_redirects=0
|
|
$SYST net.ipv4.conf.default.send_redirects=0
|
|
$SYST net.ipv4.conf.default.rp_filter=0
|
|
$SYST net.ipv4.conf.eth0.send_redirects=0
|
|
$SYST net.ipv4.conf.eth0.rp_filter=0
|
|
|
|
# Create IPTables rules
|
|
iptables -I INPUT 1 -p udp --dport 1701 -m policy --dir in --pol none -j DROP
|
|
iptables -I INPUT 2 -m conntrack --ctstate INVALID -j DROP
|
|
iptables -I INPUT 3 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
|
iptables -I INPUT 4 -p udp -m multiport --dports 500,4500 -j ACCEPT
|
|
iptables -I INPUT 5 -p udp --dport 1701 -m policy --dir in --pol ipsec -j ACCEPT
|
|
iptables -I INPUT 6 -p udp --dport 1701 -j DROP
|
|
iptables -I FORWARD 1 -m conntrack --ctstate INVALID -j DROP
|
|
iptables -I FORWARD 2 -i eth+ -o ppp+ -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
|
iptables -I FORWARD 3 -i ppp+ -o eth+ -j ACCEPT
|
|
iptables -I FORWARD 4 -i ppp+ -o ppp+ -s "$L2TP_NET" -d "$L2TP_NET" -j ACCEPT
|
|
iptables -I FORWARD 5 -i eth+ -d "$XAUTH_NET" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
|
iptables -I FORWARD 6 -s "$XAUTH_NET" -o eth+ -j ACCEPT
|
|
# Uncomment if you wish to disallow traffic between VPN clients themselves
|
|
# iptables -I FORWARD 2 -i ppp+ -o ppp+ -s "$L2TP_NET" -d "$L2TP_NET" -j DROP
|
|
# iptables -I FORWARD 3 -s "$XAUTH_NET" -d "$XAUTH_NET" -j DROP
|
|
iptables -A FORWARD -j DROP
|
|
iptables -t nat -I POSTROUTING -s "$XAUTH_NET" -o eth+ -m policy --dir out --pol none -j MASQUERADE
|
|
iptables -t nat -I POSTROUTING -s "$L2TP_NET" -o eth+ -j MASQUERADE
|
|
|
|
# Update file attributes
|
|
chmod 600 /etc/ipsec.secrets /etc/ppp/chap-secrets /etc/ipsec.d/passwd
|
|
|
|
cat <<EOF
|
|
|
|
================================================
|
|
|
|
IPsec VPN server is now ready for use!
|
|
|
|
Connect to your new VPN with these details:
|
|
|
|
Server IP: $PUBLIC_IP
|
|
IPsec PSK: $VPN_IPSEC_PSK
|
|
Username: $VPN_USER
|
|
Password: $VPN_PASSWORD
|
|
|
|
Write these down. You'll need them to connect!
|
|
|
|
Important notes: https://git.io/vpnnotes2
|
|
Setup VPN clients: https://git.io/vpnclients
|
|
|
|
================================================
|
|
|
|
EOF
|
|
|
|
# Load IPsec NETKEY kernel module
|
|
modprobe af_key
|
|
|
|
# Start services
|
|
mkdir -p /var/run/pluto /var/run/xl2tpd
|
|
rm -f /var/run/pluto/pluto.pid /var/run/xl2tpd.pid
|
|
|
|
/usr/local/sbin/ipsec start --config /etc/ipsec.conf
|
|
exec /usr/sbin/xl2tpd -D -c /etc/xl2tpd/xl2tpd.conf
|