- 1 What is a personal VPN?
- 2 Creating the certificates
- 2.1 Create the Certificate Authority
- 2.2 Create a server certificate
- 2.3 Build diffie hellman parameters
- 3 A minimal test setup
- 4 A word on address space
- 5 Routing all the client’s traffic through the VPN
- 6 Network configuration
- 6.1 Option A: all clients share a single public IP address
- 6.2 Option B: each client gets their own public IP address
- 7 Database authentication
- 8 Putting it all together
- 9 Configuring clients
What is a personal VPN?¶
Typically, the goal of a normal VPN is to give trusted clients (optional) access to a trusted network.
The goal of a personal VPN service is totally different:
- We don’t trust the clients
- Clients route ALL their traffic through the VPN and out onto the public internet.
- Clients have no ability to communicate with eachother over the VPN.
The purpose of this is to bypass surveillance from the ISP, encrypt the last mile transmission, and prevent data retention of IP addresses.
This HOWTO will create a personal VPN service with the following properties:
- Each VPN client gets their own public IP address. This means they can accept incoming connections on the public IP and it will get routed to their VPN IP. It also means two users won’t have the same IP at the same time. The IP might change between sessions.
- Any user with a valid login/password in your user database may use the VPN service. For this HOWTO, we do not create client certificates.
- The client will use the DNS on the VPN server.
Creating the certificates¶
There are many great tutorials on the internet for creating certificates for use with openvpn. The main openvpn.net howto is very useful as well.
For this setup, we don’t need client certificates, so you can skip that part. In brief, the process is:
Create the Certificate Authority¶
apt-get install openvpn
cp -r /usr/share/doc/openvpn/examples/easy-rsa/ /etc/openvpn
cd /etc/openvpn/easy-rsa
edit vars
. ./vars
./build-ca
This will create:
keys/ca.crt
— This is the root certificate of the CA we created. In order for a client to connect to your vpn, they will need a copy of this file in advance.keys/ca.key
— This is the private key of the CA. It must be kept private and secure. You will only use it to create server certificates.
Create a server certificate¶
cd /etc/openvpn/easy-rsa
./build-key-server vpn.domain.org
Replace vpn.domain.org with the actual DNS of the vpn server. It must match, or the client will reject the certificate.
This will create:
keys/vpn.domain.org.crt
— The server certificate. This will be sent to the clients by openvpn.keys/vpn.domain.org.key
— The server private key. Keep this secure.
Build diffie hellman parameters¶
The dh file is used to negotiate a shared secret over an insecure connection.
cd /etc/openvpn/easy-rsa
./build-dh
This generates:
dh1024.pem
— we will specify this file in our openvpn configuration. It is not particularly secret, but you don’t distribute it to clients.
A minimal test setup¶
apt-get install openvpn
Create the file /etc/openvpn/personal-vpn.conf
:
dev tun
ca /etc/openvpn/easy-rsa/keys/ca.crt
cert /etc/openvpn/easy-rsa/keys/vpn.domain.org.crt
key /etc/openvpn/easy-rsa/keys/vpn.domain.org.key
dh /etc/openvpn/easy-rsa/dh1024.pem
server 172.27.0.0 255.255.0.0
plugin /usr/lib/openvpn/openvpn-auth-pam.so login
client-cert-not-required
username-as-common-name
On the server run (as root):
export LD_PRELOAD=/lib/libpam.so.0
openvpn /etc/openvpn/personal-vpn.conf
(you can omit the LD_PRELOAD in debian ‘squeeze’ or later)
Now run ifconfig on the server to check that it created a tun0
network interface and set the ip to be 172.27.0.1
.
On the client run (as root):
sudo openvpn --remote vpn.domain.org --client --dev tun --auth-user-pass --ca ca.crt
The file ca.crt
is the one you created earlier. Login with any normal user account on the VPN server. Later we will use an SQL user database.
If it works, you can ping the VPN server, but you won’t yet be able to get out onto the internet over the VPN. That will come later.
A word on address space¶
It is good to use the 172 IP netblock because it is rarely used for home NAT. We have to make sure that the IP address we assign to clients does not conflict with any other networks they are on. So, it would be very bad to pick 192.168.0.0 as a VPN network, because this is the most common IP space used for local networks.
The possible reserved netblocks that can be used for your VPN:
IP range | max addresses | class | max netmask |
10.0.0.0 – 10.255.255.255 | 16,777,216 | single class A | 10.0.0.0/8 (255.0.0.0) |
172.16.0.0 – 172.31.255.255 | 1,048,576 | 16 contiguous class Bs | 172.16.0.0/12 (255.240.0.0) |
192.168.0.0 – 192.168.255.255 | 65,536 | 256 contiguous class Cs | 192.168.0.0/16 (255.255.0.0) |
Routing all the client’s traffic through the VPN¶
For this HOWTO, we want all the client’s traffic to be routed through the VPN server. To tell the client to do this, just add these lines to the openvpn configuration:
push "redirect-gateway def1"
push "dhcp-option DNS 172.27.0.1"
Where 172.27.0.1
is the VPN IP address the VPN server.
We need to run a DNS server on the VPN server otherwise the client won’t have access to DNS anymore (since most ISPs will block access to their DNS from other networks, and once connected to the VPN you will appear to be coming from an external network).
Setting up a DNS server is beyond the scope of this HOWTO, but a simple one might look like:
apt-get install bind9
Edit /etc/bind/named.conf.options
acl "trusted" {
127.0.0.1;
localhost;
};
acl "vpnclients" {
172.27.0.0/16;
};
options {
allow-query {
trusted;
vpnclients;
};
allow-recursion {
trusted;
vpnclients;
};
}
Network configuration¶
OK, so you have the VPN connection established and you can ping the VPN server from the client, and the client from the VPN server.
How do you get your traffic out to the internet? There are two methods listed here: either everyone can share a single IP or you can give each client their own public IP.
Option A: all clients share a single public IP address¶
This setup is fairly easy. It is just like if you were setting up a local network with a firewall and NAT. Run this once:
echo '1' > /proc/sys/net/ipv4/ip_forward
iptables --table nat --append POSTROUTING --source 172.27.0.0/16 --out-interface eth0 --jump MASQUERADE
To confirm the iptables are setup:
iptables --table nat --list
should produce:
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.27.0.0/16 anywhere
To remove this:
iptables --table nat --delete POSTROUTING --source 172.27.0.0/16 --out-interface eth0 --jump MASQUERADE
Option B: each client gets their own public IP address¶
For this setup, we will be generating a unique route for each client. These routes will be setup and torn down in special scripts called by openvpn when a new connection is created or destroyed.
In this example, we have available the public IPs 198.252.153.192/26
(ie .192 to .254) to use for the VPN. We will hand out private IPs in the range 172.27.0.192/26
and then set up a 1:1 mapping between the 172.27.0.192-254
block and the 198.252.153.192-254
block.
cd /etc/openvpn
touch client-connect.sh
touch client-disconnect.sh
chmod u+x *.sh
In /etc/openvpn/person-vpn.conf
, add these lines:
script-security 2
client-connect /etc/openvpn/client-connect.sh
client-disconnect /etc/openvpn/client-disconnect.sh
topology subnet
The option topology subnet
will make openvpn allocate a single IP for each client. The default is p2p
, which will allocate a /30 subnet to each client. This is more compatible with older openvpn clients, but throws off our 1:1 mapping.
Create client-connect.sh
:
#!/bin/sh
public_ip_prefix="198.252.153."
vpn_ip_prefix="172.27.0."
netmask="255.255.255.192"
vpn_ip=$ifconfig_pool_remote_ip
ip_suffix=${vpn_ip##$vpn_ip_prefix}
public_ip=${vpn_ip/$vpn_ip_prefix/$public_ip_prefix}
ifconfig eth0:$ip_suffix up $public_ip netmask $netmask
# rewrite incoming packets to use vpn ip
iptables --table nat --append PREROUTING --dst $public_ip --jump DNAT --to-destination $vpn_ip
# rewrite outoing packets to use public ip
iptables --table nat --append POSTROUTING --src $vpn_ip --jump SNAT --to-source $public_ip
exit 0
Create client-disconnect.sh
:
#!/bin/sh
public_ip_prefix="198.252.153."
vpn_ip_prefix="172.27.0."
netmask="255.255.255.192"
vpn_ip=$ifconfig_pool_remote_ip
ip_suffix=${vpn_ip##$vpn_ip_prefix}
public_ip=${vpn_ip/$vpn_ip_prefix/$public_ip_prefix}
ifconfig eth0:$ip_suffix down
iptables --table nat --delete PREROUTING --dst $public_ip --jump DNAT --to-destination $vpn_ip
iptables --table nat --delete POSTROUTING --src $vpn_ip --jump SNAT --to-source $public_ip
exit 0
Database authentication¶
OK, we are almost done. The final thing is to use an external database for the user/password, instead of using the /etc/password file.
Change /etc/openvpn/personal-vpn.conf
to use openvpn
instead of login
for pam authentication:
plugin /usr/lib/openvpn/openvpn-auth-pam.so openvpn
Then create the file /etc/pam.d/openvpn
:
auth required /lib/security/pam_mysql.so host=127.0.0.1 user={dbuser} passwd={dbpass} db={db} table=users usercolumn=username passwdcolumn=password where=is_active=1 crypt=1
account sufficient pam_permit.so
session sufficient pam_permit.so
Replace {dbuser} and {dbpass} with whatever is appropriate for your database. In this example, we also limit access to records where is_active = 1
.
Putting it all together¶
Modify /etc/default/openvpn
:
AUTOSTART="all"
export LD_PRELOAD=/lib/libpam.so.0
The fully completed /etc/openvpn/personal-vpn.conf
##
## NETWORKING
##
dev tun
keepalive 20 120
topology subnet
##
## SCRIPTS
##
#user nobody \ well, this sucks, but the current setup needs to be able
#group nogroup / to run ifconfig and iptables. so, for now, we run as root.
script-security 2
client-connect /etc/openvpn/client-connect.sh
client-disconnect /etc/openvpn/client-disconnect.sh
##
## KEYS and CERTIFICATES
##
ca /etc/openvpn/easy-rsa/keys/ca.crt
cert /etc/openvpn/easy-rsa/keys/vpn.domain.org.crt
key /etc/openvpn/easy-rsa/keys/vpn.domain.org.key
dh /etc/openvpn/easy-rsa/dh1024.pem
##
## SERVER MODE
##
server 172.27.0.192 255.255.255.192
push "redirect-gateway def1"
push "dhcp-option DNS 198.252.153.28"
# ^^ note: if using MASQUERADE, push the vpn ip for dns. If using SNAT, push the public ip.
##
## AUTHENTICATION
##
plugin /usr/lib/openvpn/openvpn-auth-pam.so openvpn
client-cert-not-required
username-as-common-name
Comments:
- dev tun
- easier than tap
- keepalive 20 120
- keeps the connection from dying due to inactivity.
- topology subnet
- allocates only a single ip per client, instead of 4.
- script-security 2
- allows client-connect scripts
- client-connect /etc/openvpn/client-connect.sh
- where the networking is setup for a client
- client-disconnect /etc/openvpn/client-disconnect.sh
- where the networking is taken down for a client
- push “redirect-gateway def1”
- makes the client send all their traffic to the server.
- push “dhcp-option DNS 198.252.153.28”
- tells the client to use our dns server. note: if using MASQUERADE, push the vpn ip for dns. If using SNAT, push the public ip.
- client-cert-not-required
- don’t use client certs. the clients are not ‘trusted’
- plugin /usr/lib/openvpn/openvpn-auth-pam.so openvpn
- use pam for password authentication, service named ‘openvpn’ (ie whatever is in /etc/pam.d/openvpn)
- username-as-common-name
- not sure of the benefit. we don’t have a common-name (because there is no client cert) so this seemed like a good idea.
Other commonly suggested server options:
persist-tun
persist-key
But I am not sure what the benefit is.
Configuring clients¶
You must download to each client the ca.crt
file created earlier.
Network Manager (gnome)¶
apt-get install network-manager-openvpn
/etc/init.d/network-manager restart
- Click on the network manager applet
- Select VPN Connections > Configure VPN… menu item
- Click Add button
- Choose OpenVPN if you get a choice of vpn type. Then click Create…
- Use these settings:
- Gateway: vpn.domain.org
- Type: password
- User name: your user name on vpn.domain.org
- Password: your password
- CA Certificate: the file ca.crt.
- Advanced:: TLS Authentication: select “verify peer…”, and select “server” in the list “remote peer certificate TLS type” (you will need network-manager-openvpn >= 0.9.8)
If you move the location of the CA cert file, then the vpn will break.
After you have saved the configuration, you can click on the network manager applet and apply it. If it worked, you should see a lock in the corner of the applet. If it didn’t work, tail /var/log/syslog.
tunnelblick (mac)¶
Edit the configuration file:
client
dev tun
auth-user-pass
remote vpn.domain.org 1194
ca /path/to/ca.crt
You can easily build custom bundles with tunnelblick so that you can distribute a single program pre-configured for a particular vpn with the certificates already included. This way, no configuration is required, just download and double click.
openvpn command line (mac and linux)¶
requirements:
apt-get install resolvconf openvpn
required files:
/etc/openvpn/riseup/client.conf
: a configuration file for connecting as a client/etc/openvpn/riseup/auth
: a file to store your username and password/etc/openvpn/riseup/riseup-ca-cert.pem
: the CA cert needed to authenticate the server.
running openvpn:
sudo openvpn --config /etc/openvpn/riseup/client.conf
Create the file /etc/openvpn/riseup/auth
:
joehill
jghw82dfa1
The first line is your vpn username, the second line is your password. This can be commented out for a login prompt on startup
Create the file /etc/openvpn/riseup/client.conf
:
# Specify that we are a client and that we
# will be pulling certain config file directives
# from the server.
client
# Use the same setting as you are using on
# the server.
# On most systems, the VPN will not function
# unless you partially or fully disable
# the firewall for the TUN/TAP interface.
dev tun
# Are we connecting to a TCP or
# UDP server? Use the same setting as
# on the server.
;proto tcp
proto udp
# The hostname/IP and port of the server.
# You can have multiple remote entries
# to load balance between the servers.
#
# choose whichever is closer for you
remote seattle.vpn.riseup.net 1194
;remote nyc.vpn.riseup.net 1194
# Keep trying indefinitely to resolve the
# host name of the OpenVPN server. Very useful
# on machines which are not permanently connected
# to the internet such as laptops.
resolv-retry infinite
# Most clients don't need to bind to
# a specific local port number.
nobind
# Downgrade privileges after initialization (non-Windows only)
user nobody
group nogroup
# Try to preserve some state across restarts.
persist-key
persist-tun
# If you are connecting through an
# HTTP proxy to reach the actual OpenVPN
# server, put the proxy server/IP and
# port number here. See the man page
# if your proxy server requires
# authentication.
;http-proxy-retry # retry on connection failures
;http-proxy [proxy server] [proxy port #]
# Wireless networks often produce a lot
# of duplicate packets. Set this flag
# to silence duplicate packet warnings.
mute-replay-warnings
# SSL/TLS parms.
# See the server config file for more
# description. It's best to use
# a separate .crt/.key file pair
# for each client. A single ca
# file can be used for all clients.
ca /etc/openvpn/riseup/riseup-ca-cert.pem
auth-user-pass /etc/openvpn/riseup/auth
auth-nocache
# Verify server certificate by checking
# that the certicate has the nsCertType
# field set to "server". This is an
# important precaution to protect against
# a potential attack discussed here:
# http://openvpn.net/howto.html#mitm
#
# To use this feature, you will need to generate
# your server certificates with the nsCertType
# field set to "server". The build-key-server
# script in the easy-rsa folder will do this.
remote-cert-tls server
# If a tls-auth key is used on the server
# then every client must also have the key.
;tls-auth ta.key 1
# Select a cryptographic cipher.
# If the cipher option is used on the server
# then you must also specify it here.
;cipher x
# Set log file verbosity.
verb 3
# Silence repeating messages
mute 20
# Log-File
log /etc/openvpn/riseup/openvpn.log
# DNS
script-security 2
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf