Home » Computing » SSL on Apache and tunneling VPN with OpenVPN on Ubuntu

SSL on Apache and tunneling VPN with OpenVPN on Ubuntu

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

Become root


Install required software

apt-get install openvpn

Setup Easy RSA from OpenVPN

Tasks: setup a certifying authority certificate

Switch dir

cd /usr/share/doc/openvpn/examples/easy-rsa/2.0

Edit vars

edit ./vars

set the KEY_* params: Country, Province, City, Org, Email

Process parameters

source vars

Now the Certificate Authority certificate should be created.

Generate Keys

Server key

./build-key-server <SERVERNAME>

This key is to be used to authenticate a server. Create as many as necessary (node01, node02)

Client key

./build-key <USERID>

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

Install apache

apt-get install apache2

a2enmod ssl

service apache2 restart

Edit SSL config

nano /etc/apache2/sites-available/default-ssl

Adjust the email

Under the email add

ServerName <SERVERNAME>:443

For example “ServerName example.com:443”

Set keys

SSLEngine on

SSLCertificateFile <crtpath>

SSLCertificateKeyFile <keypath>

(replace paths as appropriate)

a2ensite default-ssl

service apache2 reload

You can now access your website via HTTPS:// as well as HTTP://

Disable default to disable regulat HTTP access.

OpenVPN enablement

Get the server configuration

Go to

cd /usr/share/doc/openvpn/sample-config-files

gunzip server.conf.gz

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: – – –

Use appropriate network mask. Example 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

Client setup

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:

openvpn server.conf

On the client run:

openvpn client.conf

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 -o eth0 -j MASQUERADE

# forward TUN interface to eth0
iptables -A INPUT -i tun+ -s -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

# [1] if we have connected from a remote machine - make sure
#    we maintain connection!
# add a live rule
iptables -P INPUT ACCEPT

# [2] flush current rules table, which closes all external
#   connections - hence step 1.
iptables -F

# [3] 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

# [4] Accept any input for protocol ("-p") ICMP
iptables -A INPUT -p icmp -j ACCEPT

# [5] Accept anything from localhost -- the distinction is not visible in the above dump
iptables -A INPUT -i lo -j ACCEPT

# [6] Accept incoming new ssh (tcp port 22) connections ; existing ones are served by rule [3]
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 -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

# forward TUN interface to eth0
iptables -A INPUT -i tun+ -s -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

# [7] Reject everything else
# iptables -A INPUT -j REJECT # original setup
iptables -P INPUT DROP # the more correct step

# [8] 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

# [9] Accept any outgoing traffic

# [10] Save the settings we've just defined so that
# they apply when we reboot
# service iptables save
Posted in Computing, Internet, Linux

Leave a Reply

Your email address will not be published. Required fields are marked *