update for multiple servers on one host
[vpn-setup] / vpn-server-setup
index bbfd41b8687c9ab31f9c1176b07f32610b7823f7..0710dc801072e749df602364226a5fbd216d082b 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/bash -x
+#!/bin/bash
 # Copyright (C) 2016 Ian Kelling
 
 # Licensed under the Apache License, Version 2.0 (the "License");
 # Copyright (C) 2016 Ian Kelling
 
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,11 +20,14 @@ trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
 [[ $EUID == 0 ]] || exec sudo -E "$BASH_SOURCE" "$@"
 
 usage() {
 [[ $EUID == 0 ]] || exec sudo -E "$BASH_SOURCE" "$@"
 
 usage() {
-    cat <<'EOF'
-usage: ${0##*/} [-d|-h|--help]
+  cat <<'EOF'
+usage: ${0##*/} [OPTIONS] [IPV6_ADDR/BITS IPV6_DEFAULT_ROUTE]
 
 
--r  Do not push default route
+-4  I prefix of range for ipv4, default 10.8.0
 -d  Do not push dns
 -d  Do not push dns
+-n  Name. default = server. 2 servers on the same host need different names.
+-p  Port. default 1194
+-r  Do not push default route
 -s  Do not start openvpn
 -h --help print help
 
 -s  Do not start openvpn
 -h --help print help
 
@@ -32,61 +35,113 @@ Sets up a vpn server which pushes gateway route and dns server so all
 traffic goes through the vpn. requires systemd, and might have some
 debian specific paths.
 
 traffic goes through the vpn. requires systemd, and might have some
 debian specific paths.
 
+For ipv6, we assume ipv6_addr routes to the server.
+
 You can save all the keys by storing /etc/openvpn/easy-rsa/keys, and
 the script will not generate them if it sees they exist already.
 
 You can save all the keys by storing /etc/openvpn/easy-rsa/keys, and
 the script will not generate them if it sees they exist already.
 
+For future updates to this script, this is a good place to
+take inspiration.
+https://github.com/angristan/openvpn-install/blob/master/openvpn-install.sh
+
 Note: Uses GNU getopt options parsing style
 EOF
 Note: Uses GNU getopt options parsing style
 EOF
-    exit $1
+  exit $1
 }
 
 dns=true
 route=true
 start=true
 }
 
 dns=true
 route=true
 start=true
-temp=$(getopt -l help drsh "$@") || usage 1
+ip4=10.8.0
+name=server
+temp=$(getopt -l help 4:dn:p:rsh "$@") || usage 1
 eval set -- "$temp"
 while true; do
 eval set -- "$temp"
 while true; do
-    case $1 in
-        -d) dns=false; shift ;;
-        -r) route=false; shift ;;
-        -s) start=false; shift ;;
-        -h|--help) usage ;;
-        --) shift; break ;;
-        *) echo "$0: Internal error! unexpected args: $*" ; exit 1 ;;
-    esac
+  case $1 in
+    -4) ip4=$2; shift 2 ;;
+    -d) dns=false; shift ;;
+    -n) name=$2; shift 2 ;;
+    -p) port=$2; shift 2 ;;
+    -r) route=false; shift ;;
+    -s) start=false; shift ;;
+    -h|--help) usage ;;
+    --) shift; break ;;
+    *) echo "$0: Internal error! unexpected args: $*" ; exit 1 ;;
+  esac
 done
 
 done
 
-apt-get update
-# suggests get's us openssl
-apt-get install --install-suggests -y openvpn
+read -r ip6 ip6route <<<"$@"
+
+source /a/bin/distro-functions/src/package-manager-abstractions
+
+pi-nostart openvpn openssl resolvconf easy-rsa uuid-runtime
+
 if [[ -e /lib/systemd/system/openvpn-server@.service ]]; then
 if [[ -e /lib/systemd/system/openvpn-server@.service ]]; then
-    vpn_service=openvpn-server@server
+  vpn_service=openvpn-server@$name
 else
 else
-    vpn_service=openvpn@server
+  vpn_service=openvpn@$name
 fi
 fi
-apt-get install -y uuid-runtime easy-rsa
-mkdir -p /etc/openvpn/easy-rsa
-cd /etc/openvpn/easy-rsa
+rsadir=/etc/openvpn/easy-rsa-$name
+mkdir -p $rsadir
+cd $rsadir
 cp -r /usr/share/easy-rsa/* .
 if [[ -e openssl-1.0.0.cnf && ! -e openssl.cnf ]]; then
 cp -r /usr/share/easy-rsa/* .
 if [[ -e openssl-1.0.0.cnf && ! -e openssl.cnf ]]; then
-    # there's a debian bug about this.
-    ln -s openssl-1.0.0.cnf openssl.cnf
+  # there's a debian bug about this.
+  ln -s openssl-1.0.0.cnf openssl.cnf
+fi
+
+server_dir=/etc/openvpn/server
+mkdir -p $server_dir
+chmod 700 $server_dir
+conf=$server_dir/$name.conf
+
+
+new=true
+ca_origin=$rsadir/pki/ca.crt
+keyfiles=(
+  $rsadir/pki/private/$name.key
+  $rsadir/pki/issued/$name.crt
+)
+if [[ -e /etc/openvpn/easy-rsa/build-ca ]]; then
+  new=false
+  ca_origin=$rsadir/ca.crt
+  keyfiles=(
+    $rsadir/keys/$name.key
+    $rsadir/keys/$name.crt
+  )
 fi
 
 keys_exist=true
 fi
 
 keys_exist=true
-keyfiles=(/etc/openvpn/easy-rsa/keys/{ca.crt,server.{crt,key},dh2048.pem,ta.key})
 for f in ${keyfiles[@]}; do
 for f in ${keyfiles[@]}; do
-    if [[ ! -e $f ]]; then
-        keys_exist=false
-        break
-    fi
+  if [[ ! -e $f ]]; then
+    keys_exist=false
+    break
+  fi
 done
 
 done
 
+f=$server_dir/dh2048.pem
+if [[ ! -e $f ]]; then
+  openssl dhparam -out $f 2048
+fi
+
+f=$server_dir/ta-$name.key
+if [[ ! -e $f ]]; then
+  openvpn --genkey --secret $server_dir/ta-$name.key
+fi
+
+
 if ! $keys_exist; then
 if ! $keys_exist; then
-    source vars # dun care about setting cert cn etc from the non-example values
+  # newer sample configs (post stretch) use ta.key. no harm making it for earlier oses
+  if $new; then
+    echo 'set_var EASYRSA_NS_SUPPORT      "yes"' >vars
+    ./easyrsa init-pki
+    ./easyrsa --batch build-ca nopass
+    ./easyrsa build-server-full $name nopass
+  else
+    # dun care about settning cert cn etc from the non-example values
+    source vars
+    # doesnt exist in buster
     ./clean-all # note: removes and creates /etc/openvpn/easy-rsa/keys
     ./clean-all # note: removes and creates /etc/openvpn/easy-rsa/keys
-    # newer sample configs (post stretch) use ta.key. no harm making it for earlier oses
-    openvpn --genkey --secret /etc/openvpn/easy-rsa/keys/ta.key
     # accept default prompts
     echo -e '\n\n\n\n\n\n\n\n' | ./build-ca
 
     # accept default prompts
     echo -e '\n\n\n\n\n\n\n\n' | ./build-ca
 
@@ -95,25 +150,23 @@ if ! $keys_exist; then
     # 'server' is the default name in our conf file for the name of the file
     # and I've seen no reason to change it.
     # Note, this is not idempotent.
     # 'server' is the default name in our conf file for the name of the file
     # and I've seen no reason to change it.
     # Note, this is not idempotent.
-    { echo -e '\n\n\n\n\n\n\n\n\n\n'; sleep 1; echo -e 'y\ny\n'; } | ./build-key-server server
+    { echo -e '\n\n\n\n\n\n\n\n\n\n'; sleep 1; echo -e 'y\ny\n'; } | ./build-key-server $name
     ./build-dh
     ./build-dh
+  fi
 fi
 
 fi
 
-server_dir=/etc/openvpn/server
-mkdir -p $server_dir
-chmod 700 $server_dir
-
-cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz $server_dir
-gzip -df $server_dir/server.conf.gz
 
 
+gzip -dc /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz >$conf
 
 
+cafile=$server_dir/ca-$name.crt
+cp $ca_origin $cafile
 cp ${keyfiles[@]} $server_dir
 # for legacy systems
 cp ${keyfiles[@]} $server_dir
 # for legacy systems
-for f in ${keyfiles[@]}; do
-    ln -sf server/${f##*/} /etc/openvpn
+for f in ${keyfiles[@]} $cafile; do
+  ln -sf server/${f##*/} /etc/openvpn
 done
 
 done
 
-cat >>$server_dir/server.conf <<'EOF'
+cat >>$conf <<EOF
 
 # I cat an extra blank line to start because the example config does
 # not have a final newline. ....
 
 # I cat an extra blank line to start because the example config does
 # not have a final newline. ....
@@ -128,22 +181,30 @@ cipher AES-256-CBC
 client-config-dir /etc/openvpn/client-config
 
 # duplicate in newer sample configs
 client-config-dir /etc/openvpn/client-config
 
 # duplicate in newer sample configs
-tls-auth ta.key 0 # This file is secret
+tls-auth ta-$name.key 0 # This file is secret
 
 # depending on sample config, this may not be there, which means i can't
 
 # depending on sample config, this may not be there, which means i can't
-# talk to 10.8.0.1, there might be some other way, but stretch's
+# talk to $ip4.1, there might be some other way, but stretch's
 # sample config says:
 # Should be subnet (addressing via IP)
 # unless Windows clients v2.0.9 and lower have to
 # be supported (then net30, i.e. a /30 per client)
 # Defaults to net30 (not recommended)
 topology subnet
 # sample config says:
 # Should be subnet (addressing via IP)
 # unless Windows clients v2.0.9 and lower have to
 # be supported (then net30, i.e. a /30 per client)
 # Defaults to net30 (not recommended)
 topology subnet
-EOF
 
 
+status /var/log/openvpn/openvpn-status-$name.log
+ifconfig-pool-persist /var/log/openvpn/ipp-$name.txt
+ca ca-$name.crt
+cert $name.crt
+key $name.key
+client-config-dir /etc/openvpn/client-config-$name
+server $ip4.0 255.255.255.0
+EOF
+mkdir -p /etc/openvpn/client-config-$name
 
 # dh improve security,
 # remove comp-lzo to increase perf
 
 # dh improve security,
 # remove comp-lzo to increase perf
-sed -i --follow-symlinks -f - $server_dir/server.conf <<'EOF'
+sed -i --follow-symlinks -f - $conf <<'EOF'
 s/^dh dh1024.pem/dh dh2048.pem/
 /^comp-lzo.*/d
 EOF
 s/^dh dh1024.pem/dh dh2048.pem/
 /^comp-lzo.*/d
 EOF
@@ -153,44 +214,70 @@ mkdir -p /etc/openvpn/client-config
 
 
 if $dns; then
 
 
 if $dns; then
-    # Be the dns server for clients
-    cat >>$server_dir/server.conf <<'EOF'
-push "dhcp-option DNS 10.8.0.1"
+  # Be the dns server for clients
+  cat >>$conf <<EOF
+push "dhcp-option DNS $ip4.1"
+EOF
+fi
+
+if [[ $ip6 ]]; then
+  cat >>$conf <<EOF
+push tun-ipv6 # legacy option that flidas needs, has no harm.
+ifconfig-ipv6 $ip6 $ip6route
 EOF
 EOF
+
+  sed -i --follow-symlinks '/^ *net.ipv6.conf.all.forwarding=.*/d' /etc/sysctl.conf
+  cat >>/etc/sysctl.conf <<'EOF'
+net.ipv6.conf.all.forwarding=1
+EOF
+
 fi
 
 fi
 
+
 if $route; then
 if $route; then
-    cat >>$server_dir/server.conf <<'EOF'
+  cat >>$conf <<'EOF'
 # Be the default gateway for clients.
 push "redirect-gateway def1"
 EOF
 # Be the default gateway for clients.
 push "redirect-gateway def1"
 EOF
-    echo "1" > /proc/sys/net/ipv4/ip_forward
-    sed -i --follow-symlinks '/^ *net\.ipv4\.ip_forward=.*/d' /etc/sysctl.conf
-    cat >>/etc/sysctl.conf <<'EOF'
-net.ipv4.ip_forward=1
+  if [[ $ip6 ]]; then
+    cat >>$conf <<'EOF'
+push "route-ipv6 2000::/3"
 EOF
 EOF
+  fi
+fi
+if [[ $port ]]; then
+  cat >>$conf <<EOF
+port $port
+EOF
+fi
 
 
 
 
-    gw=$(ip route | sed -rn 's/^default via .* dev (\S+).*/\1/p')
+sed -i --follow-symlinks '/^ *net\.ipv4\.ip_forward=.*/d' /etc/sysctl.conf
+cat >>/etc/sysctl.conf <<'EOF'
+net.ipv4.ip_forward=1
+EOF
+sysctl -p /etc/sysctl.conf
 
 
-    cat >/etc/systemd/system/vpnnat.service <<EOF
+gw=$(ip route | sed -rn 's/^default via .* dev (\S+).*/\1/p' | head -n1)
+
+cat >/etc/systemd/system/vpnnat.service <<EOF
 [Unit]
 Description=Turns on nat iptables setting
 
 [Service]
 Type=oneshot
 RemainAfterExit=yes
 [Unit]
 Description=Turns on nat iptables setting
 
 [Service]
 Type=oneshot
 RemainAfterExit=yes
-ExecStart=/sbin/iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o $gw -j MASQUERADE
-ExecStop=/sbin/iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o $gw -j MASQUERADE
+ExecStart=/sbin/iptables -t nat -A POSTROUTING -s $ip4.0/24 -o $gw -j MASQUERADE
+ExecStop=/sbin/iptables -t nat -D POSTROUTING -s $ip4.0/24 -o $gw -j MASQUERADE
 
 [Install]
 
 [Install]
-WantedBy=$vpn_service
+WantedBy=$vpn_service.service
 EOF
 EOF
-    systemctl daemon-reload # needed if the file was already there
-    # note, no need to start it, the vpn_service does that.
-fi
+systemctl daemon-reload # needed if the file was already there
+# note, no need to start it, the vpn_service does that.
+systemctl enable vpnnat
 
 if $start; then
 
 if $start; then
-    systemctl enable $vpn_service
-    systemctl restart $vpn_service
+  systemctl enable $vpn_service
+  systemctl restart $vpn_service
 fi
 fi