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