├── .gitignore
├── LICENSE
├── README.md
├── Vagrantfile
├── add-client.sh
├── bootstrap.sh
├── client-configs
└── .gitignore
├── config-default.sh
├── generate-client-certificate.sh
├── interfaces.sh
├── make-config.sh
├── openvpn.sh
├── revoke-full.sh
└── ubuntu.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | .vagrant
2 | .DS_Store
3 | *.log
4 | config.sh
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # openvpn-server-vagrant
2 |
3 | Spin up an OpenVPN Server
4 |
5 |
6 | ## Install Vagrant, VirtualBox and git
7 |
8 | http://www.vagrantup.com
9 | https://www.virtualbox.org (don't worry about setting up any VMs as the steps below will cover this)
10 | http://git-scm.com
11 |
12 |
13 | ## Set up
14 |
15 | $ git clone https://github.com/redgeoff/openvpn-server-vagrant.git
16 | $ cd openvpn-server-vagrant
17 | $ cp config-default.sh config.sh
18 | Edit config.sh and fill in your config
19 | $ vagrant up
20 | $ vagrant ssh
21 |
22 | You can then perform a sanity test with a connection from a VPN client with:
23 |
24 | $ sudo su -
25 | $ /vagrant/add-client.sh test-client
26 | $ cp ~/client-configs/files/test-client.ovpn /vagrant
27 | On the host, double click `test-client.ovpn` to load it into Tunnelblick
28 | Use Tunnelblick to connect to the VPN server
29 |
30 | # Add a route to a subnet
31 |
32 | Routes must be added to the server so that you clients know which traffic to route to the VPN Server. The following process should be repeated for each subnet in your network.
33 |
34 | Edit `/etc/openvpn/server.conf` and add something like the following, where `172.31.26.0` is your network and 255.255.255.0 is the netmask.
35 |
36 | push "route 172.31.26.0 255.255.255.0"
37 |
38 | Then restart the VPN Server:
39 |
40 | $ sudo systemctl restart openvpn@server
41 |
42 |
43 | ## Add a client
44 |
45 | The following should be repeated for each new client/user for whom you wish to grant access to your VPN. Replace client-name with a unique name.
46 |
47 | $ sudo su -
48 | $ /vagrant/add-client.sh client-name
49 |
50 | You will then find a file like the following that you should provide to the individual who will be connecting to your VPN. This ovpn file can then be used with Tunnelblick (OS X), OpenVPN (Linux, iOS, Android and Windows).
51 |
52 | ~/client-configs/files/client-name.ovpn
53 |
54 |
55 | ## Revoke client certificate
56 |
57 | If you ever need to revoke access, simply execute:
58 |
59 | $ sudo su -
60 | $ /vagrant/revoke-full.sh client-name
61 |
62 |
63 | ## Extra Info
64 |
65 | * See [Run a Free VPN Server on AWS](https://redgeoff.com/posts/free-vpn-aws-2022)
66 | * See [How To Set Up and Configure an OpenVPN Server on Ubuntu 20.04](https://www.digitalocean.com/community/tutorials/how-to-set-up-and-configure-an-openvpn-server-on-ubuntu-20-04)
67 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | Vagrant.configure("2") do |config|
2 |
3 | config.vm.box = "bento/ubuntu-22.04"
4 |
5 | # Use a private network so that we don't have to worry about forwarding ports
6 | config.vm.network "private_network", ip: "192.168.56.11"
7 |
8 | config.vm.provider "virtualbox" do |v|
9 | v.memory = 1024
10 |
11 | # Only allow drift of 1 sec, instead of 20 min default
12 | v.customize [ "guestproperty", "set", :id, "/VirtualBox/GuestAdd/VBoxService/--timesync-set-threshold", 1000 ]
13 | end
14 |
15 | # Bootstrap script for configuring VM
16 | config.vm.provision :shell, path: "bootstrap.sh"
17 |
18 | end
19 |
--------------------------------------------------------------------------------
/add-client.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Change to script directory
4 | sd=`dirname $0`
5 | cd $sd
6 |
7 | name=$1
8 |
9 | if [ "$name" = "" ]; then
10 | echo "Usage: add-client.sh name"
11 | exit;
12 | fi
13 |
14 | # Generate a client certificate and key pair
15 | $sd/generate-client-certificate.sh $name
16 |
17 | # Make config
18 | $sd/make-config.sh $name
19 |
--------------------------------------------------------------------------------
/bootstrap.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | /vagrant/ubuntu.sh
4 |
5 | /vagrant/openvpn.sh
6 |
--------------------------------------------------------------------------------
/client-configs/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/config-default.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | KEY_COUNTRY="US"
4 | KEY_PROVINCE="CA"
5 | KEY_CITY="SanFrancisco"
6 | KEY_ORG="Fort-Funston"
7 | KEY_EMAIL="me@myhost.mydomain"
8 | KEY_OU="MyOrganizationalUnit"
9 |
10 | PUBLIC_IP="192.168.56.11"
11 |
--------------------------------------------------------------------------------
/generate-client-certificate.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Change to script directory
4 | sd=`dirname $0`
5 | cd $sd
6 | sd=`pwd`
7 |
8 | name=$1
9 |
10 | if [ "$name" = "" ]; then
11 | echo "Usage: generate-client-certificate.sh name"
12 | exit;
13 | fi
14 |
15 | cd ~/openvpn-ca
16 | yes "" | ./easyrsa gen-req ${name} nopass
17 | cp pki/private/${name}.key ~/client-configs/keys/
18 | yes "yes" | ./easyrsa sign-req client ${name}
19 | cp /root/openvpn-ca/pki/issued/${name}.crt ~/client-configs/keys/
20 | cp /etc/openvpn/server/ta.key ~/client-configs/keys/
21 | cp /etc/openvpn/server/ca.crt ~/client-configs/keys/
--------------------------------------------------------------------------------
/interfaces.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | DEVICES=$(ifconfig -s | grep -v "Iface\|lo\|tun0" | cut -d " " -f 1)
4 | NUMDEVICES=$(ifconfig -s | wc -l)
5 | VPNDEVICE=""
6 |
7 | # If we have an eth0 device, use that to maintain current functionality.
8 | if ifconfig -s | grep -q eth0
9 | then
10 | export VPNDEVICE="eth0"
11 |
12 | # If we hit newer systemd/hypervisor combination, it won't be eth0, but there
13 | # will probably be only one obvious device to use: not the loop back, and not
14 | # the tunnel. Use it instead.
15 | elif [ $NUMDEVICES -eq 3 ]
16 | then
17 | # no eth0 device, but only one option, use it.
18 | export VPNDEVICE=$(ifconfig -s | tail -n 2 | cut -d " " -f 1 | grep -v "lo\|tun0")
19 |
20 | # If we end up on a server that has multiple devices and no eth0, just ask.
21 | # This is fairly common, Docker containers, wifi cards, dual nics, etc.
22 | else
23 | echo "There are multiple network devices on this server:"
24 | echo ""
25 | ifconfig -s | cut -d " " -f 1 | grep -v "Iface\|lo\|tun0"
26 | echo ""
27 | echo "Please type the name of the device you'd like to use"
28 | read VPNDEVICE
29 |
30 | # Catch bad user input
31 | while ! echo $DEVICES | grep -q "${VPNDEVICE}"
32 | do
33 | echo "${VPNDEVICE} was not found in the list of devices. Please type the device name again"
34 | read VPNDEVICE
35 | done
36 | export $VPNDEVICE
37 |
38 | fi
39 |
--------------------------------------------------------------------------------
/make-config.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | name=$1
4 |
5 | if [ "$name" = "" ]; then
6 | echo "Usage: make-config.sh name"
7 | exit;
8 | fi
9 |
10 | KEY_DIR=~/client-configs/keys
11 | OUTPUT_DIR=~/client-configs/files
12 | BASE_CONFIG=~/client-configs/base.conf
13 |
14 | cat ${BASE_CONFIG} \
15 | <(echo -e '') \
16 | ${KEY_DIR}/ca.crt \
17 | <(echo -e '\n') \
18 | ${KEY_DIR}/${name}.crt \
19 | <(echo -e '\n') \
20 | ${KEY_DIR}/${name}.key \
21 | <(echo -e '\n') \
22 | ${KEY_DIR}/ta.key \
23 | <(echo -e '') \
24 | > ${OUTPUT_DIR}/${name}.ovpn
25 |
26 | # sed -i "s/group nogroup/group nobody/" ${OUTPUT_DIR}/${name}.ovpn
27 |
--------------------------------------------------------------------------------
/openvpn.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # For details on why certain options have been chosen, see
4 | # https://www.digitalocean.com/community/tutorials/how-to-set-up-and-configure-an-openvpn-server-on-ubuntu-20-04
5 |
6 | # Change to script directory
7 | sd=`dirname $0`
8 | cd $sd
9 | # if you ran the script from its own directory you actually just got '.'
10 | # so capture the abs path to wd now
11 | sd=`pwd`
12 |
13 | # Make sure config file exists
14 | if [ ! -f ./config.sh ]; then
15 | echo "config.sh not found!"
16 | exit;
17 | fi
18 |
19 | # Install OpenVPN and net-tools (ifconfig)
20 | apt-get -y install openvpn easy-rsa net-tools
21 |
22 | # Load config
23 | source ./config.sh
24 | source ./interfaces.sh
25 |
26 | # Set up the CA directory
27 | make-cadir ~/openvpn-ca
28 | cd ~/openvpn-ca
29 |
30 | # Update vars
31 | echo "set_var EASYRSA_REQ_COUNTRY \"${KEY_COUNTRY}\"" >> vars
32 | echo "set_var EASYRSA_REQ_PROVINCE \"${KEY_PROVINCE}\"" >> vars
33 | echo "set_var EASYRSA_REQ_CITY \"${KEY_CITY}\"" >> vars
34 | echo "set_var EASYRSA_REQ_ORG \"${KEY_ORG}\"" >> vars
35 | echo "set_var EASYRSA_REQ_EMAIL \"${KEY_EMAIL}\"" >> vars
36 | echo "set_var EASYRSA_REQ_OU \"${KEY_OU}\"" >> vars
37 | echo "set_var EASYRSA_ALGO \"ec\"" >> vars
38 | echo "set_var EASYRSA_DIGEST \"sha512\"" >> vars
39 |
40 | # Build the Certificate Authority
41 | ./easyrsa init-pki
42 | yes "" | ./easyrsa build-ca nopass
43 |
44 | # Create the server certificate
45 | yes "" | ./easyrsa gen-req server nopass
46 | cp pki/private/server.key /etc/openvpn/server/
47 | cp pki/private/ca.key /etc/openvpn/server/
48 | cp pki/ca.crt /etc/openvpn/server/
49 |
50 | # Sign the certificate request
51 | yes "yes" | ./easyrsa sign-req server server
52 | yes "yes" | cp pki/issued/server.crt /etc/openvpn/server/
53 |
54 | # Generate an extra shared secret key
55 | openvpn --genkey secret pki/ta.key
56 | cp pki/ta.key /etc/openvpn/server/
57 |
58 | # Copy the sample config to the OpenVPN directory
59 | cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf /etc/openvpn/server/server.conf
60 |
61 | # Adjust the OpenVPN configuration
62 | sed -i "s/^;tls-auth ta.key.*$/tls-crypt ta.key 0/" /etc/openvpn/server/server.conf
63 | # sed -i "s/cipher AES-256-CBC/cipher AES-256-GCM\nauth SHA256/" /etc/openvpn/server/server.conf
64 | sed -i "s/dh dh2048.pem/;dh dh2048.pem\ndh none/" /etc/openvpn/server/server.conf
65 | # sed -i "s/;user openvpn/user openvpn/" /etc/openvpn/server/server.conf
66 | # sed -i "s/;group openvpn/group openvpn/" /etc/openvpn/server/server.conf
67 |
68 | # Allow IP forwarding
69 | sed -i "s/#net.ipv4.ip_forward/net.ipv4.ip_forward/" /etc/sysctl.conf
70 | sysctl -p
71 |
72 | # Firewall configuration
73 | sed -i "s/# rules.before/# rules.before\n# START OPENVPN RULES\n# NAT table rules\n*nat\n:POSTROUTING ACCEPT [0:0]\n-A POSTROUTING -s 10.8.0.0\/8 -o ${VPNDEVICE} -j MASQUERADE\nCOMMIT\n# END OPENVPN RULES/" /etc/ufw/before.rules
74 | sed -i "s/DEFAULT_FORWARD_POLICY=\"DROP\"/DEFAULT_FORWARD_POLICY=\"ACCEPT\"/" /etc/default/ufw
75 | ufw allow 1194/udp
76 | ufw allow OpenSSH
77 | ufw disable
78 | yes "y" | ufw enable
79 |
80 | # Start and enable the OpenVPN service
81 | systemctl -f enable openvpn-server@server.service
82 | systemctl start openvpn-server@server.service
83 |
84 | # Creating the Client Configuration Infrastructure
85 | mkdir -p ~/client-configs/keys
86 | chmod -R 700 ~/client-configs
87 | mkdir -p ~/client-configs/files
88 | cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ~/client-configs/base.conf
89 | sed -i "s/remote my-server-1 1194/remote ${PUBLIC_IP} 1194/" ~/client-configs/base.conf
90 | # sed -i "s/;user openvpn/user openvpn/" ~/client-configs/base.conf
91 | # sed -i "s/;group openvpn/group openvpn/" ~/client-configs/base.conf
92 | sed -i "s/ca ca.crt/;ca ca.crt/" ~/client-configs/base.conf
93 | sed -i "s/cert client.crt/;cert client.crt/" ~/client-configs/base.conf
94 | sed -i "s/key client.key/;key client.key/" ~/client-configs/base.conf
95 | sed -i "s/tls-auth ta.key 1/;tls-auth ta.key 1/" ~/client-configs/base.conf
96 | # sed -i "s/cipher AES-256-CBC/cipher AES-256-GCM/" ~/client-configs/base.conf
97 | echo "auth SHA256" >> ~/client-configs/base.conf
98 | echo "key-direction 1" >> ~/client-configs/base.conf
99 | echo ";script-security 2" >> ~/client-configs/base.conf
100 | echo ";up /etc/openvpn/update-resolv-conf" >> ~/client-configs/base.conf
101 | echo ";down /etc/openvpn/update-resolv-conf" >> ~/client-configs/base.conf
102 | echo ";script-security 2" >> ~/client-configs/base.conf
103 | echo ";up /etc/openvpn/update-systemd-resolved" >> ~/client-configs/base.conf
104 | echo ";down /etc/openvpn/update-systemd-resolved" >> ~/client-configs/base.conf
105 | echo ";down-pre" >> ~/client-configs/base.conf
106 | echo ";dhcp-option DOMAIN-ROUTE ." >> ~/client-configs/base.conf
107 |
--------------------------------------------------------------------------------
/revoke-full.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | name=$1
4 |
5 | if [ "$name" = "" ]; then
6 | echo "Usage: revoke-full.sh name"
7 | exit;
8 | fi
9 |
10 | cd ~/openvpn-ca
11 |
12 | yes "yes" | ./easyrsa revoke $name
13 |
14 | ./easyrsa gen-crl
15 |
16 | # Install the revocation files
17 | cp pki/crl.pem /etc/openvpn/server
18 |
19 | # Configure the server to check the client revocation list. This should only be done once
20 | if [ $(grep -R 'crl-verify crl.pem' /etc/openvpn/server/server.conf | wc -l) -eq 0 ]; then
21 | echo -e "\ncrl-verify crl.pem" >> /etc/openvpn/server/server.conf
22 | systemctl restart openvpn-server@server.service
23 | fi
24 |
--------------------------------------------------------------------------------
/ubuntu.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Update apt-get
4 | apt-get -y update
5 |
6 | # Update Ubuntu
7 | apt-get -y upgrade
8 | apt-get -y dist-upgrade
--------------------------------------------------------------------------------