Script for user configurations generation and sending at Ubuntu OpenVPN server

Ubuntu has a very detailed documentation about OpenVPN server configuration. The key feature of this note is script for automatic generation of single-file client configurations (keys and certs are embedded) and sending them by email. Looks interesting? Read below!

Prerequisities

All commands in this section must be executed as root user.

Update package list:

apt-get update
apt-get -y upgrade

Install needed packages (easy-rsa must be installed explicitly on modern Ubuntus):

apt-get install -y openvpn easy-rsa

Configure OpenVPN server on Ubuntu 14.04

Copy default configuration:

cp -r /usr/share/easy-rsa /etc/openvpn/easy-rsa
cd /etc/openvpn/easy-rsa

Edit vars file in /etc/openvpn/easy-rsa folder corresponding to your settings. Change the following lines corresponding to your options:

export KEY_SIZE=2048

export KEY_COUNTRY="US"
export KEY_PROVINCE="State"
export KEY_CITY="BigCityName"
export KEY_ORG="OrganizationName"
export KEY_EMAIL="mail@organization.com"
export KEY_OU="vpn.organization.com"

export KEY_NAME="vpn.organization.com"

export KEY_CN="vpn.organization.com"
export KEY_ALTNAMES="vpn.organization.com"

Activate saved settings:

source vars

And generate server keys:

./clean-all
./build-ca
./build-key-server vpn.organization.com
./build-dh
openvpn --genkey --secret keys/ta.key

Example of server config (must be placed into /etc/openvpn folder):

# /etc/openvpn/server.conf
# Which TCP/UDP port should OpenVPN listen on
port 1594

# Ip's
server 10.10.10.0 255.255.255.0

# UDP server
proto udp

# Create a routed IP tunnel
dev tun

# Root certificate, certificate, private key, DH key, SSL/TLS key
ca       easy-rsa/keys/ca.crt
cert     easy-rsa/keys/vpn.organization.com.crt
key      easy-rsa/keys/vpn.organization.com.key
dh       easy-rsa/keys/dh2048.pem
tls-auth easy-rsa/keys/ta.key 0

# Maintain a record of client <-> virtual IP address
ifconfig-pool-persist ipp.txt

# Allow different clients to be able to "see" each other
client-to-client

# Ping every 10 seconds, peer is down if no pong during a 120 seconds
keepalive 10 120

# Cryptographic cipher
cipher AES-256-CBC

# Enable compression on the VPN link
comp-lzo

# Reduce the OpenVPN daemon's privileges after initialization
user nobody
group nogroup

# Avoid errors caused by the privilege downgrade
persist-key
persist-tun

# Status file
status openvpn-status.log

# Set the appropriate level of log verbosity
verb 3

Be sure that your keys ca.crt, vpn.organization.com.crt, vpn.organization.com.key, dh2048.pem, ta.key are in the correct place corresponding to server config.

Client configuration

Client configuration must correspond to server one. For the above server config client one is:

# /etc/openvpn/easy-rsa/client.conf
# Specify that it is a client
client

# Use the same setting as on the server.
dev tun
proto udp

# The hostname/IP and port of the server.
remote vpn.organization.com 1594

# Keep trying indefinitely to resolve the host name of the OpenVPN server
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

# Verify server certificate
ns-cert-type server

# Enable compression on the VPN link
comp-lzo

# Set log file verbosity.
verb 3

# Set key direction for tls-auth
key-direction 1

# Cryptographic cipher
cipher AES-256-CBC

Сonvenient autosending of client configurations

Save the following script into folder:

#!/usr/bin/env bash

CLIENT=$1
CLIENT_MAIL=$2
SERVER=vpn.dima.io

cd /etc/openvpn/easy-rsa

source vars

mkdir -p bundles

./build-key ${CLIENT}.at.${SERVER}

cp client.conf bundles/${CLIENT}.at.${SERVER}.conf

echo "<ca>"  >> bundles/${CLIENT}.at.${SERVER}.conf
cat keys/ca.crt >> bundles/${CLIENT}.at.${SERVER}.conf
echo "</ca>" >> bundles/${CLIENT}.at.${SERVER}.conf

echo "<cert>"  >> bundles/${CLIENT}.at.${SERVER}.conf
cat keys/${CLIENT}.at.${SERVER}.crt >> bundles/${CLIENT}.at.${SERVER}.conf
echo "</cert>" >> bundles/${CLIENT}.at.${SERVER}.conf

echo "<key>"  >> bundles/${CLIENT}.at.${SERVER}.conf
cat keys/${CLIENT}.at.${SERVER}.key >> bundles/${CLIENT}.at.${SERVER}.conf
echo "</key>" >> bundles/${CLIENT}.at.${SERVER}.conf

echo "<tls-auth>"  >> bundles/${CLIENT}.at.${SERVER}.conf
cat keys/ta.key >> bundles/${CLIENT}.at.${SERVER}.conf
echo "</tls-auth>" >> bundles/${CLIENT}.at.${SERVER}.conf

if [ -n "$CLIENT_MAIL" ]; then
    echo -e "Hello, ${CLIENT}!\n\nConfiguration with embedded certificates is attached." > mail.txt
    echo "If you use Windows system, rename configuration from *.conf to *.ovpn." >> mail.txt
    echo "This mail is automatically generated. Please do not respond to it." >> mail.txt
    echo "--"
    echo "${SERVER} team."
    cat mail.txt | mutt -s "Configuration for $CLIENT on $SERVER OpenVPN server" -a bundles/${CLIENT}.at.${SERVER}.conf -- $CLIENT_MAIL
fi

rm mail.txt

add-key

And make it executable:

chmod +x add-key

You will have to install mutt (it is used for sending emails with attachments). Your server must have full hostname like server.organization.com, otherwise sendmail may hang during the install, so change it before mutt installation.

apt-get install -y mutt

If you install in LXC container

If you install VPN server into LXC container, you have to make additional steps. Firstly, add rule for iptabels in host system (use ip of your VPN container and port from VPN server config):

iptables -t nat -A PREROUTING -i eth0 -p udp --dport 1594 -j DNAT --to 10.0.3.111:1594

To make it persistent, you may use iptables-persistent.

Secondly, confugure tun device for lxc.