2 # I, Ian Kelling, follow the GNU license recommendations at
3 # https://www.gnu.org/licenses/license-recommendations.en.html. They
4 # recommend that small programs, < 300 lines, be licensed under the
5 # Apache License 2.0. This file contains or is part of one or more small
6 # programs. If a small program grows beyond 300 lines, I plan to switch
9 # Copyright 2024 Ian Kelling
11 # Licensed under the Apache License, Version 2.0 (the "License");
12 # you may not use this file except in compliance with the License.
13 # You may obtain a copy of the License at
15 # http://www.apache.org/licenses/LICENSE-2.0
17 # Unless required by applicable law or agreed to in writing, software
18 # distributed under the License is distributed on an "AS IS" BASIS,
19 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 # See the License for the specific language governing permissions and
21 # limitations under the License.
25 trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
27 [[ $EUID == 0 ]] ||
exec sudo
-E "$BASH_SOURCE" "$@"
31 usage: ${0##*/} [OPTIONS] [IPV6_ADDR/BITS]
33 -4 Prefix of range for ipv4, default 10.8.0
34 -6 IP6_NETWORK Do ip6 nat for this network. ipv6 will work without nat,
35 but you may want it in certain circumstances.
37 -i INTERFACE_NAME name of tun interface
38 -n NAME default = server. 2 servers on the same host need different names.
40 -r Do not push default route
41 -s Do not start openvpn
44 IPV6_ADDR/BITS Ipv6 address of the vpn interface.
46 Sets up a vpn server which pushes gateway route and dns server so all
47 traffic goes through the vpn. requires systemd, and might have some
48 debian specific paths.
50 For ipv6, we assume ipv6_addr routes to the server.
52 You can save all the keys by storing /etc/openvpn/easy-rsa-NAME/keys, and
53 the script will not generate them if it sees they exist already.
55 For future updates to this script, this is a good place to
57 https://github.com/angristan/openvpn-install/blob/master/openvpn-install.sh
59 Note: Uses GNU getopt options parsing style
69 temp
=$
(getopt
-l help 4:6:di
:n
:p
:rsh "$@") || usage
1
73 -4) ip4
=$2; shift 2 ;;
74 -6) ip6net
=$2; shift 2 ;;
75 -d) dns
=false
; shift ;;
76 -i) ifname
=$2; shift 2 ;;
77 -n) name
=$2; shift 2 ;;
78 -p) port
=$2; shift 2 ;;
79 -r) route
=false
; shift ;;
80 -s) start
=false
; shift ;;
83 *) echo "$0: Internal error! unexpected args: $*" ; exit 1 ;;
87 read -r ip6 ip6route
<<<"$@"
89 source /a
/bin
/distro-functions
/src
/package-manager-abstractions
91 pi-nostart openvpn openssl easy-rsa uuid-runtime
93 if [[ -e /lib
/systemd
/system
/openvpn-server@.service
]]; then
94 vpn_service
=openvpn-server@
$name
96 vpn_service
=openvpn@
$name
98 rsadir
=/etc
/openvpn
/easy-rsa-
$name
101 cp -r /usr
/share
/easy-rsa
/* .
102 if [[ -e openssl-1.0
.0.cnf
&& ! -e openssl.cnf
]]; then
103 # there's a debian bug about this.
104 ln -s openssl-1.0
.0.cnf openssl.cnf
107 server_dir
=/etc
/openvpn
/server
109 chmod 700 $server_dir
110 conf
=$server_dir/$name.conf
114 ca_origin
=$rsadir/pki
/ca.crt
116 $rsadir/pki
/private
/$name.key
117 $rsadir/pki
/issued
/$name.crt
119 if [[ -e /etc
/openvpn
/easy-rsa
/build-ca
]]; then
121 ca_origin
=$rsadir/ca.crt
123 $rsadir/keys
/$name.key
124 $rsadir/keys
/$name.crt
129 for f
in ${keyfiles[@]}; do
130 if [[ ! -e $f ]]; then
136 f
=$server_dir/dh2048.pem
137 if [[ ! -e $f ]]; then
138 openssl dhparam
-out $f 2048
141 f
=$server_dir/ta-
$name.key
142 if [[ ! -e $f ]]; then
143 openvpn
--genkey --secret $server_dir/ta-
$name.key
147 if ! $keys_exist; then
148 # newer sample configs (post stretch) use ta.key. no harm making it for earlier oses
150 echo 'set_var EASYRSA_NS_SUPPORT "yes"' >vars
152 .
/easyrsa
--batch build-ca nopass
153 .
/easyrsa
--days=3650 build-server-full
$name nopass
155 # dun care about settning cert cn etc from the non-example values
157 # doesnt exist in buster
158 .
/clean-all
# note: removes and creates /etc/openvpn/easy-rsa/keys
159 # accept default prompts
160 echo -e '\n\n\n\n\n\n\n\n' | .
/build-ca
162 # This builds the server's key/cert. argument is the name of the file,
163 # but it also is the default common name of the cert.
164 # 'server' is the default name in our conf file for the name of the file
165 # and I've seen no reason to change it.
166 # Note, this is not idempotent.
167 { echo -e '\n\n\n\n\n\n\n\n\n\n'; sleep 1; echo -e 'y\ny\n'; } | .
/build-key-server
$name
172 if [[ -e /usr
/share
/doc
/openvpn
/examples
/sample-config-files
/server.conf
]]; then
173 cat /usr
/share
/doc
/openvpn
/examples
/sample-config-files
/server.conf
>$conf
176 gzip -dc /usr
/share
/doc
/openvpn
/examples
/sample-config-files
/server.conf.gz
>$conf
179 cafile
=$server_dir/ca-
$name.crt
180 cp $ca_origin $cafile
181 cp ${keyfiles[@]} $server_dir
183 for f
in ${keyfiles[@]} $cafile; do
184 ln -sf server
/${f##*/} /etc
/openvpn
189 # I cat an extra blank line to start because the example config does
190 # not have a final newline. ....
192 # not in example config, but openvpn outputs a warning about insecure
193 # cipher without a setting like this (the default i can understand due
194 # to compatibility issues, but not changing the example config... not
196 # requires the same setting on the client side.
198 # just sets up the ability to have client specific configs
199 client-config-dir /etc/openvpn/client-config
201 # duplicate in newer sample configs
202 tls-auth ta-$name.key 0 # This file is secret
204 # depending on sample config, this may not be there, which means i can't
205 # talk to $ip4.1, there might be some other way, but stretch's
206 # sample config says:
207 # Should be subnet (addressing via IP)
208 # unless Windows clients v2.0.9 and lower have to
209 # be supported (then net30, i.e. a /30 per client)
210 # Defaults to net30 (not recommended)
213 status /var/log/openvpn/openvpn-status-$name.log
214 ifconfig-pool-persist /var/log/openvpn/ipp-$name.txt
218 client-config-dir /etc/openvpn/client-config-$name
219 server $ip4.0 255.255.255.0
221 mkdir
-p /etc
/openvpn
/client-config-
$name
223 # dh improve security,
224 # remove comp-lzo to increase perf
225 sed -i --follow-symlinks -f - $conf <<'EOF'
226 s/^dh dh1024.pem/dh dh2048.pem/
232 # Be the dns server for clients
234 push "dhcp-option DNS $ip4.1"
238 if [[ $ifname ]]; then
246 push tun-ipv6 # legacy option that flidas needs, has no harm.
247 # the ::1 is not used, i just put a short valid address there
248 ifconfig-ipv6 $ip6 ::1
251 sed -i --follow-symlinks '/^ *net.ipv6.conf.all.forwarding=.*/d' /etc
/sysctl.conf
252 cat >>/etc
/sysctl.conf
<<'EOF'
253 net.ipv6.conf.all.forwarding=1
261 # Be the default gateway for clients.
262 push "redirect-gateway def1"
266 push "route-ipv6 2000::/3"
277 sed -i --follow-symlinks '/^ *net\.ipv4\.ip_forward=.*/d' /etc
/sysctl.conf
278 cat >>/etc
/sysctl.conf
<<'EOF'
279 net.ipv4.ip_forward=1
281 sysctl
-p /etc
/sysctl.conf
283 gw
=$
(ip route |
sed -rn 's/^default via .* dev (\S+).*/\1/p' |
head -n1)
285 d
=/etc
/systemd
/system
/$vpn_service.service.d
290 ExecStartPre=/sbin/iptables -t nat -A POSTROUTING -s $ip4.0/24 -o $gw -j MASQUERADE
291 ExecStopPost=/sbin/iptables -t nat -D POSTROUTING -s $ip4.0/24 -o $gw -j MASQUERADE
293 if [[ $ip6net ]]; then
295 ExecStartPre=/sbin/ip6tables -t nat -A POSTROUTING -s $ip6net -o $gw -j MASQUERADE
296 ExecStopPost=/sbin/ip6tables -t nat -D POSTROUTING -s $ip6net -o $gw -j MASQUERADE
298 systemctl daemon-reload
# needed if the file was already there
301 systemctl
enable $vpn_service
302 systemctl restart
$vpn_service