# VPN tunnel one click setup

Intro

There are so many tutorials "how to setup vpn tunnel". Unfortunately most of them are pretty much manual or are based on some bash magic.
I found myself repetitively doing the same thing over and over again…

This article will show you how to setup full vpn tunnel (with sniproxy and dns server) with as little as one click (once you have keys) with vagrant and CoreOS. As bonus point I’ll briefly describe how to setup your openwrt to transparently pass traffic through the tunnel.

Goal

Automate VPS creation process with OpenVPN, DNS and SNI Proxy servers. I am using vultr.com, but you can choose anything else like digitalocean, amazon etc.

Set up vagrant

Just a few commands to run. Make sure that you use vagrant >= 1.9. You have to add your ssh key to vultr via web-panel (https://www.vultr.com/docs/how-do-i-generate-ssh-keys/) if you wish to log automatically to new VM.

sudo apt-get update
sudo apt-get install vagrant
vagrant plugin install vagrant-vultr
ssh-keygen  -t rsa -b 4096 -f $HOME/.ssh/vultr

Set up noip.com

On our target VPN vm we’ll be running dns resolver. It’s good practice to limit access to the resolver as some villains can use it for ddos attacks. We’ll go one step further and limit the access to whole vm from given IP or subnet.

Because I don’t have static IP I am using dynamic dns service (rather IP directly). The setup is quite simple, just register and request the API key. Once you have it, update Vagrantfile:

cloud_config = {
    :hostname => box.vm.box,
    :no_ip_username => "YOUR_EMAIL:API_KEY",
    :no_ip_hostname => "YOUR_DDNS_HOSTNAME",
    :no_ip_allowed_sources => "HOSTNAME1 HOSTNAME2 SUBNET3",
}

Your new VM is going to update A record (YOUR_DDNS_HOSTNAME) via curl call. This way, every time you spawn a new VM with different IP you don’t need to update anything.

Start VPS

First you need to configure your vultr api key and update Vagrant config.

vultr.token = 'YOUR_VULTR_API'
vultr.region = 'New Jersey'
vultr.plan = '768 MB RAM,15 GB SSD,1.00 TB BW'
vultr.os = 'CoreOS Stable'
vultr.enable_ipv6 = 'yes'
vultr.enable_private_network = 'no'

Once your config is all set, run:

vagrant up --provider=vultr

This will setup new VM on your vultr and run cloudinit. At this point vpn will fail because you have no keys set up.

Generate VPN keys

There are multiple ways you can do it but for compatibility purposes lets follow the tutorial: https://github.com/kylemanna/docker-openvpn
I didn’t want to reinvent the wheel again, so we are using publicly available docker containers such as "kylemanna/docker-openvpn".

Once your keys are in place, copy them to the same directory where you store Vagrantfile and run:

vagrant provision

Connect via OpenVPN server

It’s time to configure your openvpn client. Basic openvpn configuration may look like this:

```
client
nobind
dev tun
key-direction 1
remote-cert-tls server
remote YOUR_HOSTNAME 1194 udp

<key>
PRIVATE_KEY
</key>
<cert>
CERT
</cert>
<ca>
CA_CERT
</ca>
<tls-auth>
OPEN_VPN_STATIC_KEY
</tls-auth>
key-direction 1

redirect-gateway def1
```

Configure OpenWRT

I will just briefly describe overall configuration rather than going into details.
I have special wifi network where all the traffic for certain client IPs is routed through VPN interface.

Network configuration (/etc/config/network):

config interface 'VUS_VULTR'
        option proto 'none'
        option ifname 'tun0'

config interface 'VUS_WIFI'
        option _orig_ifname 'wlan1'
        option _orig_bridge 'false'
        option proto 'static'
        option ipaddr '192.168.8.1'
        option netmask '255.255.255.0'

config rule
        option lookup 'vus'
        option priority '10'
        option src '192.168.8.1/24'

OpenVPN has pretty nice plugin for managing VPN and DDNS:

opkg update
opkg install openvpn-openssl luci-app-openvpn
opkg install luci-app-ddns

OpenVPN configuration is pretty easy over UI, but you can do it also over CLI (/etc/config/openvpn):

config openvpn 'us_vultr'
    option nobind '1'
    option verb '3'
    option client '1'
    option ca '/lib/uci/upload/cbid.openvpn.us_vultr.ca'
    option key '/lib/uci/upload/cbid.openvpn.us_vultr.key'
    option cert '/lib/uci/upload/cbid.openvpn.us_vultr.cert'
    option enabled '1'
    option remote_cert_tls 'server'
    option dev 'tun0'
    option remote 'YOUR_REMOTE_SERVER_HOSTNAME'
    option tls_auth '/etc/openvpn/tlsauth.key 1'
    option up '/lib/uci/upload/set_route'
    option script_security '2 system'

Also we need to setup firewall rules(/etc/config/firewall):

config zone
    option output 'ACCEPT'
    option masq '1'
    option mtu_fix '1'
    option network 'VUS_VULTR'
    option name 'VUS'
    option log '1'
    option input 'ACCEPT'
    option forward 'ACCEPT'

config zone
    option input 'ACCEPT'
    option output 'ACCEPT'
    option network 'NETFLIX'
    option name 'VUS_VULTR'
    option forward 'ACCEPT'
    option log '1'

config forwarding
    option dest 'VUS'
    option src 'VUS_VULTR'

As you probably noticed, when tun0 interface is brought up ‘/lib/uci/upload/set_route’ is being executed.

#!/bin/sh
/usr/sbin/ip route add 192.168.8.203 dev tun0 table vus
/usr/sbin/ip route add 192.168.8.245 dev tun0 table vus
/usr/sbin/ip route add default via 192.168.255.5 dev tun0 table vus
/usr/sbin/ip route flush cache

Yeah, it’s a bit hacky but works. It adds routes to IP rules table ‘vus’, so that clients .203 and .245 are going through 192.168.255.5 gateway (vpn).

Sources

https://github.com/mkaczanowski/vpn-tunnel

Demo

Whoa! Wait! It was supposed to be one-click?
You’re right… We did way more than one-click. But now as you have:

  • Vultr account set
  • Noip ddns set
  • Vagrant set
  • VPN keys set
  • OpenWRT set

spawning up new vm in different region is just matter of modifying one line in Vagrantfile. Run:

vagrant up new_vm_in_france --provider=vultr

All of the configuration is based on dynamic dns, so changing vm’s is not a problem.
As you see on screenshots I am easily switching between countries (including DNS, yay!).