minor docs
[vpn-setup] / vpn-server-setup
1 #!/bin/bash
2 # Copyright (C) 2016 Ian Kelling
3
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7
8 # http://www.apache.org/licenses/LICENSE-2.0
9
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16
17 set -eE -o pipefail
18 trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
19
20 [[ $EUID == 0 ]] || exec sudo -E "$BASH_SOURCE" "$@"
21
22 usage() {
23 cat <<'EOF'
24 usage: ${0##*/} [OPTIONS] [IPV6_ADDR/BITS]
25
26 -4 Prefix of range for ipv4, default 10.8.0
27 -6 IP6_NETWORK Do ip6 nat for this network. ipv6 will work without nat,
28 but you may want it in certain circumstances.
29 -d Do not push dns
30 -n NAME default = server. 2 servers on the same host need different names.
31 -p PORT default 1194
32 -r Do not push default route
33 -s Do not start openvpn
34 -h --help print help
35
36 Sets up a vpn server which pushes gateway route and dns server so all
37 traffic goes through the vpn. requires systemd, and might have some
38 debian specific paths.
39
40 For ipv6, we assume ipv6_addr routes to the server.
41
42 You can save all the keys by storing /etc/openvpn/easy-rsa-NAME/keys, and
43 the script will not generate them if it sees they exist already.
44
45 For future updates to this script, this is a good place to
46 take inspiration.
47 https://github.com/angristan/openvpn-install/blob/master/openvpn-install.sh
48
49 Note: Uses GNU getopt options parsing style
50 EOF
51 exit $1
52 }
53
54 dns=true
55 route=true
56 start=true
57 ip4=10.8.0
58 name=server
59 temp=$(getopt -l help 4:6:dn:p:rsh "$@") || usage 1
60 eval set -- "$temp"
61 while true; do
62 case $1 in
63 -4) ip4=$2; shift 2 ;;
64 -6) ip6net=$2; shift 2 ;;
65 -d) dns=false; shift ;;
66 -n) name=$2; shift 2 ;;
67 -p) port=$2; shift 2 ;;
68 -r) route=false; shift ;;
69 -s) start=false; shift ;;
70 -h|--help) usage ;;
71 --) shift; break ;;
72 *) echo "$0: Internal error! unexpected args: $*" ; exit 1 ;;
73 esac
74 done
75
76 read -r ip6 ip6route <<<"$@"
77
78 source /a/bin/distro-functions/src/package-manager-abstractions
79
80 pi-nostart openvpn openssl resolvconf easy-rsa uuid-runtime
81
82 if [[ -e /lib/systemd/system/openvpn-server@.service ]]; then
83 vpn_service=openvpn-server@$name
84 else
85 vpn_service=openvpn@$name
86 fi
87 rsadir=/etc/openvpn/easy-rsa-$name
88 mkdir -p $rsadir
89 cd $rsadir
90 cp -r /usr/share/easy-rsa/* .
91 if [[ -e openssl-1.0.0.cnf && ! -e openssl.cnf ]]; then
92 # there's a debian bug about this.
93 ln -s openssl-1.0.0.cnf openssl.cnf
94 fi
95
96 server_dir=/etc/openvpn/server
97 mkdir -p $server_dir
98 chmod 700 $server_dir
99 conf=$server_dir/$name.conf
100
101
102 new=true
103 ca_origin=$rsadir/pki/ca.crt
104 keyfiles=(
105 $rsadir/pki/private/$name.key
106 $rsadir/pki/issued/$name.crt
107 )
108 if [[ -e /etc/openvpn/easy-rsa/build-ca ]]; then
109 new=false
110 ca_origin=$rsadir/ca.crt
111 keyfiles=(
112 $rsadir/keys/$name.key
113 $rsadir/keys/$name.crt
114 )
115 fi
116
117 keys_exist=true
118 for f in ${keyfiles[@]}; do
119 if [[ ! -e $f ]]; then
120 keys_exist=false
121 break
122 fi
123 done
124
125 f=$server_dir/dh2048.pem
126 if [[ ! -e $f ]]; then
127 openssl dhparam -out $f 2048
128 fi
129
130 f=$server_dir/ta-$name.key
131 if [[ ! -e $f ]]; then
132 openvpn --genkey --secret $server_dir/ta-$name.key
133 fi
134
135
136 if ! $keys_exist; then
137 # newer sample configs (post stretch) use ta.key. no harm making it for earlier oses
138 if $new; then
139 echo 'set_var EASYRSA_NS_SUPPORT "yes"' >vars
140 ./easyrsa init-pki
141 ./easyrsa --batch build-ca nopass
142 ./easyrsa build-server-full $name nopass
143 else
144 # dun care about settning cert cn etc from the non-example values
145 source vars
146 # doesnt exist in buster
147 ./clean-all # note: removes and creates /etc/openvpn/easy-rsa/keys
148 # accept default prompts
149 echo -e '\n\n\n\n\n\n\n\n' | ./build-ca
150
151 # This builds the server's key/cert. argument is the name of the file,
152 # but it also is the default common name of the cert.
153 # 'server' is the default name in our conf file for the name of the file
154 # and I've seen no reason to change it.
155 # Note, this is not idempotent.
156 { echo -e '\n\n\n\n\n\n\n\n\n\n'; sleep 1; echo -e 'y\ny\n'; } | ./build-key-server $name
157 ./build-dh
158 fi
159 fi
160
161
162 gzip -dc /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz >$conf
163
164 cafile=$server_dir/ca-$name.crt
165 cp $ca_origin $cafile
166 cp ${keyfiles[@]} $server_dir
167 # for legacy systems
168 for f in ${keyfiles[@]} $cafile; do
169 ln -sf server/${f##*/} /etc/openvpn
170 done
171
172 cat >>$conf <<EOF
173
174 # I cat an extra blank line to start because the example config does
175 # not have a final newline. ....
176
177 # not in example config, but openvpn outputs a warning about insecure
178 # cipher without a setting like this (the default i can understand due
179 # to compatibility issues, but not changing the example config... not
180 # cool).
181 # requires the same setting on the client side.
182 cipher AES-256-CBC
183 # just sets up the ability to have client specific configs
184 client-config-dir /etc/openvpn/client-config
185
186 # duplicate in newer sample configs
187 tls-auth ta-$name.key 0 # This file is secret
188
189 # depending on sample config, this may not be there, which means i can't
190 # talk to $ip4.1, there might be some other way, but stretch's
191 # sample config says:
192 # Should be subnet (addressing via IP)
193 # unless Windows clients v2.0.9 and lower have to
194 # be supported (then net30, i.e. a /30 per client)
195 # Defaults to net30 (not recommended)
196 topology subnet
197
198 status /var/log/openvpn/openvpn-status-$name.log
199 ifconfig-pool-persist /var/log/openvpn/ipp-$name.txt
200 ca ca-$name.crt
201 cert $name.crt
202 key $name.key
203 client-config-dir /etc/openvpn/client-config-$name
204 server $ip4.0 255.255.255.0
205 EOF
206 mkdir -p /etc/openvpn/client-config-$name
207
208 # dh improve security,
209 # remove comp-lzo to increase perf
210 sed -i --follow-symlinks -f - $conf <<'EOF'
211 s/^dh dh1024.pem/dh dh2048.pem/
212 /^comp-lzo.*/d
213 EOF
214
215
216 if $dns; then
217 # Be the dns server for clients
218 cat >>$conf <<EOF
219 push "dhcp-option DNS $ip4.1"
220 EOF
221 fi
222
223 if [[ $ip6 ]]; then
224 cat >>$conf <<EOF
225 push tun-ipv6 # legacy option that flidas needs, has no harm.
226 # the ::1 is not used, i just put a short valid address there
227 ifconfig-ipv6 $ip6 ::1
228 EOF
229
230 sed -i --follow-symlinks '/^ *net.ipv6.conf.all.forwarding=.*/d' /etc/sysctl.conf
231 cat >>/etc/sysctl.conf <<'EOF'
232 net.ipv6.conf.all.forwarding=1
233 EOF
234
235 fi
236
237
238 if $route; then
239 cat >>$conf <<'EOF'
240 # Be the default gateway for clients.
241 push "redirect-gateway def1"
242 EOF
243 if [[ $ip6 ]]; then
244 cat >>$conf <<'EOF'
245 push "route-ipv6 2000::/3"
246 EOF
247 fi
248 fi
249 if [[ $port ]]; then
250 cat >>$conf <<EOF
251 port $port
252 EOF
253 fi
254
255
256 sed -i --follow-symlinks '/^ *net\.ipv4\.ip_forward=.*/d' /etc/sysctl.conf
257 cat >>/etc/sysctl.conf <<'EOF'
258 net.ipv4.ip_forward=1
259 EOF
260 sysctl -p /etc/sysctl.conf
261
262 gw=$(ip route | sed -rn 's/^default via .* dev (\S+).*/\1/p' | head -n1)
263
264 d=/etc/systemd/system/$vpn_service.service.d
265 mkdir -p $d
266 f=$d/nat.conf
267 cat >$f <<EOF
268 [Service]
269 ExecStartPre=/sbin/iptables -t nat -A POSTROUTING -s $ip4.0/24 -o $gw -j MASQUERADE
270 ExecStopPost=/sbin/iptables -t nat -D POSTROUTING -s $ip4.0/24 -o $gw -j MASQUERADE
271 EOF
272 if [[ $ip6net ]]; then
273 cat >>$f <<EOF
274 ExecStartPre=/sbin/ip6tables -t nat -A POSTROUTING -s $ip6net -o $gw -j MASQUERADE
275 ExecStopPost=/sbin/ip6tables -t nat -D POSTROUTING -s $ip6net -o $gw -j MASQUERADE
276 EOF
277 systemctl daemon-reload # needed if the file was already there
278
279 if $start; then
280 systemctl enable $vpn_service
281 systemctl restart $vpn_service
282 fi
283 fi