This post is now superceded by a friendlier and more eficient method: https://ducakedhare.co.uk/?p=1512
The following are a bunch of quick notes about setting up security certificates, enabling OpenVPN and forcing all traffic through a VPN tunnel, and adding SSL
It’s all tailored for Ubuntu 12.04 / 14.04 servers, and exists primarily as learning notes. I may or may not come to cleaning them up.
OpenVPN details and dialectic can be found at https://help.ubuntu.com/14.04/serverguide/openvpn.html
Longer description of Apache SSL activation can be fouind here https://www.digitalocean.com/community/tutorials/how-to-create-a-ssl-certificate-on-apache-for-ubuntu-12-04
Key signing – how it works
This section is very simplified. See https://en.wikipedia.org/wiki/Certificate_authority for technical details.
A Certificate Authority is an organisation we trust to confirm we can trust other people’s certificates.
A key and certificate for trusting are created: the Certificate Authority’s ca.key and ca.crt
ca.crt is given to anybody to say “I am the CA, anything coming from me is trusted.” Like a hologram on an ID sheet.
ca.key is used to confirm that CA has approved whatever the key is used to sign, like a hologram-creating machine, with the hologram blueprint. The key is used to say “We, CA, confirm that the item we hereby sign is genuine.”
Let’s saqy that we trust CA.
Now a server, say FantasticDotCom comes along and says, “I want CA to confirm that I am legit.”
FantasticDotCom creates a fantastic.key with which it can start affirming with. It then creates a fantastic.csr – a Certificate Signing Request – that it sends to CA.
CA processes fantastic.csr with its ca.key to produce a new file, fantastic.crt.
The fantastic.crt certificate has been signed by CA- which means that fantastic.crt is trusted by CA to do Everything Right.
Since we already trust CA, we can trust FantasticDotCom
If FantasticDotCom then tells us “my product that I signed with my own fantastic.key is legit”, we know that we trust the product signed by Fantstic, who is endorsed in turn by CA.
The importance of the KEY files is to be noted: only Fantastic must be able to sign with the fantastic.key and only the CA must be able to sign with the ca.key
If MrNasty got a hold of fantastic.key, we would not be able to tell if a product purportedly endorsed by FantasticDotCom really was genuine.
If MrNasty got a hold of ca.key, he could cause CA to endorse any number of NefariousDotCom and EvilDotNet certificates as he liked.
To rectify this, CA would need to revoke ca.key and anything that was signed with it, including alFantasticDotCom keys and anything underneath them, then create a new ca2.key and ca2.crt, ask everyone to stop trusting ca.crt and start trusting ca2.crt, and re-sign fantastic.csr again to produce a different fantastic.crt, which we could then trust.
Examples of real-world CAs are VeriSign, GlobalSign and CASC
Certificate & Key generation
Install required software
apt-get install openvpn
Setup Easy RSA from OpenVPN
Tasks: setup a certifying authority certificate
set the KEY_* params: Country, Province, City, Org, Email
Now the Certificate Authority certificate should be created.
This key is to be used to authenticate a server. Create as many as necessary (node01, node02)
Key identifying a client
Create one per identity (computer, user, app, etc)
Diffie Helman parameters
Not sure what this is used for… Used in OpenVPN configuration (not necessary for Apache/SSL)
Overview of contents now in ./keys/
*.crt → these files are certificates. Entities show these publicly to others to say “I am who I am”
*.key → these files are keys that guarantee the certificates. Entities must keep these secret. Do not share.
*.csr → certificate signing request. Not needed right now, but in other use cases. See below.
ca.crt → this certificate is the certificate authority. Add this certificate to a client so that any sub-certificate signed with ca.key can be trusted.
ca.key → the key used to sign other certificates. SUPER-SECRET. Compromising ca.key renders the chain of trust based on that ca.key useless.
Self-sign in one line:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout <keypath> -out <crtpath>
or – Create a CSR and sign it on a different server [notes to come]
Adding the key to Apache
apt-get install apache2
service apache2 restart
Edit SSL config
Adjust the email
Under the email add
For example “ServerName example.com:443”
(replace paths as appropriate)
service apache2 reload
You can now access your website via HTTPS:// as well as HTTP://
Disable default to disable regulat HTTP access.
Get the server configuration
Edit server.conf – note the port (1194 for ex)
Edit the sections:
ca → ca.crt path
cert → server.crt path
key → server.key path
dh → dh1024.pem path
Edit the “server” property to give it an address in the right local-network range:
10.0.0.0 – 10.255.255.255
172.16.0.0 – 172.31.255.255
192.168.0.0 – 192.168.255.255
Use appropriate network mask. Example 10.9.8.0/0.255.255.255 so that the VPN server will assign addresses in the range 10.9.8.* to connecting clients
Uncomment out the “user nobody” and “group nobody” lines to run openvpn without provileges and improve security
Install OpenVPN on client, and go to cd /usr/share/doc/openvpn/sample-config-files and edit client.conf
Update the keys
ca → ca.crt path
cert → client.crt path
key → client.key path (client’s key to identify itself, keep secret!)
Edit the “remote” directive to specify the public IP address of the server.
On the server run:
On the client run:
Tunnel all client traffic through the VPN
By default, the setup allows the client to access the internet as itself from home, and also access to the internal network of the VPN.
To make the client look like it’s coming from inside the VPN network, we need to modify a few things in the firewall
# open the OpenVPN port iptables -A INPUT -p udp --dport 1194 -j ACCEPT # perform network address translation iptables -t nat -A POSTROUTING -s 10.9.8.0/24 -o eth0 -j MASQUERADE # forward TUN interface to eth0 iptables -A INPUT -i tun+ -s 10.9.8.0/255.255.25.0 -j ACCEPT iptables -A FORWARD -i tun+ -j ACCEPT iptables -A FORWARD -i tun+ -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT iptables -A FORWARD -i eth0 -o tun+ -m state --state RELATED,ESTABLISHED -j ACCEPT
Run this along with other firewall iptables rules.
Appendix – iptables script
I run this script as root to change my firewall settings, and store it as a script in ~/bin
Add lines, comment out lines etc to switch things on and off.
# See http://wiki.centos.org/HowTos/Network/IPTables # for more info #  if we have connected from a remote machine - make sure # we maintain connection! # add a live rule iptables -P INPUT ACCEPT #  flush current rules table, which closes all external # connections - hence step 1. iptables -F #  add our first rule on incoming connections: # "-m state" load module state # "--state ESTABLISHED,RELATED" any connections that originated # from us # "-j ACCEPT" jump to setting the target action, which is ACCEPT iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT #  Accept any input for protocol ("-p") ICMP iptables -A INPUT -p icmp -j ACCEPT #  Accept anything from localhost -- the distinction is not visible in the above dump iptables -A INPUT -i lo -j ACCEPT #  Accept incoming new ssh (tcp port 22) connections ; existing ones are served by rule  iptables -A INPUT -m state --state NEW -p tcp --dport 22 -j ACCEPT # [6.1] XTRA - allow other connections iptables -A INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT iptables -A INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT # iptables -A INPUT -m state --state NEW -p tcp --dport 8080 -j ACCEPT # iptables -A INPUT -m state --state NEW -p tcp --dport 21 -j ACCEPT # iptables -A INPUT -m state --state NEW -p tcp --dport 3306 -j ACCEPT # port 80 is for Apache; 3306 is for MySQL, for example. # ========= OpenVPN configurations # open the OpenVPN port iptables -A INPUT -p udp --dport 1194 -j ACCEPT # perform network address translation iptables -t nat -A POSTROUTING -s 10.9.8.0/24 -o eth0 -j MASQUERADE # redirect DNS requersts straight to DNS server # iptables -t nat -A PREROUTING -i tun+ -p udp --dport 53 -j DNAT --to-destination 188.8.131.52 # forward TUN interface to eth0 iptables -A INPUT -i tun+ -s 10.9.8.0/255.255.25.0 -j ACCEPT iptables -A FORWARD -i tun+ -j ACCEPT iptables -A FORWARD -i tun+ -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT iptables -A FORWARD -i eth0 -o tun+ -m state --state RELATED,ESTABLISHED -j ACCEPT # ========== /OpenVPN #iptables -A INPUT -m state --state NEW -p tcp --dport 1022 -j ACCEPT # open for additional SSH during upgrade #  Reject everything else # iptables -A INPUT -j REJECT # original setup iptables -P INPUT DROP # the more correct step #  Reject all forwards (we are not a router) # iptables -A FORWARD -j REJECT # original setup iptables -P FORWARD DROP # the more correct step #iptables -P FORWARD ACCEPT # VPN tunnel passthru #  Accept any outgoing traffic iptables -P OUTPUT ACCEPT #  Save the settings we've just defined so that # they apply when we reboot # service iptables save iptables-save