Home How to install OpenVPN on 443 port (Debian 9 with Nginx)
Post
Cancel

How to install OpenVPN on 443 port (Debian 9 with Nginx)

If your connection primarily through an overly restrictive firewall then all of the setups mentioned below work when used through a reasonably-firewalled connection.

Prerequisites:

  • Nginx
  • Debian 9
  • UFW

Step 1. Install OpenVPN

Firstly update apt package

1
# apt-get update

Then you can install OpenVPN

1
# apt-get update

Step 2. Generate certificates

Then we should generate certificates. We will use Easy RSA tool. The latest release could be found on GitHub repository (https://github.com/OpenVPN/easy-rsa/releases).

Assume you are running macOS 10.12 (Sierra)

Create a directory for the server keys:

1
mkdir -p ~/Documents/vpn/server/keys

Create a directory for the client keys:

1
mkdir -p ~/Documents/vpn/client/keys

2.1. Configure EasyRSA

Copy the vars file to configure the certificate authority parameters:

1
cp ~/Documents/EasyRSA-3.0.4/vars.example ~/Documents/EasyRSA-3.0.4/vars

Open this file to edit:

1
subl ~/Documents/EasyRSA-3.0.4/vars

Uncomment these lines by deleting ‘#’ symbol and change variable to your needs

1
2
3
4
5
6
#set_var EASYRSA_REQ_COUNTRY "US"
#set_var EASYRSA_REQ_PROVINCE "California"
#set_var EASYRSA_REQ_CITY "San Francisco"
#set_var EASYRSA_REQ_ORG "Copyleft Certificate Co"
#set_var EASYRSA_REQ_EMAIL "me@example.net"
#set_var EASYRSA_REQ_OU "My Organizational Unit"

Uncomment current line and change value to 4096(size of bit key)

1
#set_var EASYRSA_KEY_SIZE 2048

2.2. Generating the server credentials

Navigate to EasyRSA folder:

1
cd ~/Documents/EasyRSA-3.0.4/

Initialize the PKI (Public Key Infrastructure). This command will create pki folder to store certificates.

1
./easyrsa init-pki

Create the certificate authority

1
./easyrsa build-ca nopass

And you will be prompted to provide a Common Name. Enter the name server.

Copy the certificate authority to your server keys dir:

1
cp ~/Documents/EasyRSA-3.0.4/pki/ca.crt ~/Documents/vpn/server/keys/ca.crt

Create the server .crt and .key files:

1
./easyrsa build-server-full server nopass

Copy the server certificate and key to server dir:

1
2
cp ~/Documents/EasyRSA-3.0.4/pki/issued/server.crt ~/Documents/vpn/server/keys/server.crt
cp ~/Documents/EasyRSA-3.0.4/pki/private/server.key ~/Documents/vpn/server/keys/server.key

Generate the encryption (Diffie-Hellman) parameters. This process can take pretty long:

1
./easyrsa gen-dh

Copy generated Diffie-Hellman file

1
cp ~/Documents/EasyRSA-3.0.4/pki/dh.pem ~/Documents/vpn/server/keys/dh4096.pem

2.3. Generating the Client Credentials

We will name our client certificate as reheda1. You can use whatever name you prefer.

Create the client credentials:

1
./easyrsa build-client-full reheda1 nopass

Copy generated certificate and key to client dir:

1
2
cp ~/Documents/EasyRSA-3.0.4/pki/issued/reheda1.crt ~/Documents/vpn/client/keys/reheda1.crt
cp ~/Documents/EasyRSA-3.0.4/pki/private/reheda1.key ~/Documents/vpn/client/keys/reheda1.key

Copy certificate authority to client dir:

1
cp ~/Documents/EasyRSA-3.0.4/pki/ca.crt ~/Documents/vpn/client/keys/ca.crt

Step 3. Upload generated certificates

Next we create folders server and client inside /etc/openvpn/ to store keys and certificates:

1
2
sudo mkdir /etc/openvpn/server
sudo mkdir /etc/openvpn/client

And copy generated credentials in the previous step from local machine:

1
2
local$ cd ~/Documents/vpn/server/keys/
local$ scp ca.crt dh4096.pem server.crt server.key reheda.pro:/etc/openvpn/server
1
2
local$ cd ~/Documents/vpn/client/keys/
local$ scp ca.crt reheda1.crt reheda1.key reheda.pro:/etc/openvpn/client

And we will generate a matching HMAC signature for all packets involved in the TLS handshake between the server and connecting clients. Packets without this signature are dropped. To generate the HMAC signature file run following command on the remote server:

1
openvpn --genkey --secret /etc/openvpn/server/ta.key

Step 4. Configure OpenVPN

Copy example config

1
gunzip -c /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz > /etc/openvpn/server.conf

Next open server configuration file with editor

1
nano /etc/openvpn/server.conf

Search through file (ctrl + w in Nano editor) and change highlighted parts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
proto tcp
;proto udp
ca /etc/openvpn/server/ca.crt
cert /etc/openvpn/server/server.crt
key /etc/openvpn/server/server.key
dh /etc/openvpn/server/dh4096.pem
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"
duplicate-cn
keepalive 300 900
tls-auth /etc/openvpn/server/ta.key 0
max-clients 100
user nobody
group nogroup
status logs/openvpn-status.log
log logs/openvpn.log
;explicit-exit-notify 1

So your configuration file should looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
port 1194
proto tcp
dev tun
ca /etc/openvpn/server/ca.crt
cert /etc/openvpn/server/server.crt
key /etc/openvpn/server/server.key
dh /etc/openvpn/server/dh4096.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"
duplicate-cn
keepalive 300 900
tls-auth /etc/openvpn/server/ta.key 0
cipher AES-256-CBC
max-clients 100
user nobody
group nogroup
persist-key
persist-tun
status logs/openvpn-status.log
log logs/openvpn.log
verb 3

Step 5. Configure ufw

Change UFW forwarding policy:

1
nano /etc/default/ufw

Look for the following line:

1
DEFAULT_FORWARD_POLICY="DROP"

And change DROP to ACCEPT. So it should be look like:

1
DEFAULT_FORWARD_POLICY="ACCEPT"

Save and exit.

Now we add additional UFW rules for network address translation and IP masquerading of connected clients.

1
nano /etc/ufw/before.rules

Add highlited code for rules:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#
# rules.before
#
# Rules that should be run before the ufw command line added rules. Custom
# rules should be added to one of these chains:
# ufw-before-input
# ufw-before-output
# ufw-before-forward
#
# START OPENVPN RULES
# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]
# Allow traffic from OpenVPN client to eth0
-A POSTROUTING -s 10.8.0.0/8 -o eth0 -j MASQUERADE
COMMIT
# END OPENVPN RULES
# Don't delete these required lines, otherwise there will be errors
Now we should apply new UFW settings:
ufw enable
This action will return the following prompt:
Command may disrupt existing ssh connections. Proceed with operation (y|n)?
Answer y.  And the result will be this:
Firewall is active and enabled on system startup
To check UFW's firewall rules just type:
ufw status
So OpenVPN almost ready. We can run and enable it:
systemctl start openvpn@server
systemctl status openvpn@server
systemctl enable openvpn@server

Now we should apply new UFW settings:

1
ufw enable

This action will return the following prompt:

1
Command may disrupt existing ssh connections. Proceed with operation (y|n)?

Answer y. And the result will be this:

1
Firewall is active and enabled on system startup

To check UFW’s firewall rules just type:

1
ufw status

So OpenVPN almost ready. We can run and enable it:

1
2
3
systemctl start openvpn@server
systemctl status openvpn@server
systemctl enable openvpn@server

Step 5. Install ‘sslh’

We should install ‘sslh’ to share 443 port with Nginx. OpenVPN also supply possibility to use port-share option (https://snikt.net/blog/2016/12/01/openvpn-over-https/) but is may cause some problem in future. So we will use sslh for that purpose:

1
apt-get install sslh

5.1. Configure Nginx webserver

As you know, Nginx webserver will listen on all network interfaces (i.e 0.0.0.0:443) by default. We need to change this setting to tell the webserver to listen on the localhost interface only (i.e 127.0.0.1:443 or localhost:443).

To do so, edit the webserver configuration file (/etc/nginx/sites-available/default) and find the following line:

1
listen 443 ssl;

And, change it to:

1
listen 127.0.0.1:443 ssl;

Save and exit. Also restart web server, but don’t forget to check if config is ok before:

1
2
nginx -t
systemctl restart nginx

5.2. Configure SSLH

Edit SSLH config file:

1
nano /etc/default/sslh

Then you configure it like so:

1
2
3
4
5
RUN=yes
# binary to use: forked (sslh) or single-thread (sslh-select) version
# systemd users: don't forget to modify /lib/systemd/system/sslh.service
DAEMON=/usr/sbin/sslh
DAEMON_OPTS="--user sslh --listen <public_ip>:443 --ssh 127.0.0.1:22 --ssl 127.0.0.1:443 --openvpn 127.0.0.1:1194 --pidfile /var/run/sslh/sslh.pid"

Check if sslh daemon is listening to 443 port:

1
ps -ef | grep sslh

Finally, enable and start sslh service to update the changes:

1
2
systemctl enable sslh
systemctl start sslh

Step 6. Prepare client configuration

Now we can prepare client configuration to use our server. Note that we change the extension from .conf to .ovpn

1
cp /usr/share/doc/openvpn/examples/sample-config-files/reheda-all.conf /etc/openvpn/client/reheda-all.ovpn

We should configure our new .ovpn file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
client
dev tun
proto tcp
remote <domain or ip> 443
resolv-retry infinite
nobind
user nobody
group nogroup
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-CBC
verb 3
key-direction 1
;ca ca.crt
;cert client.crt
;key client.key
;tls-auth ta.key

We will include Certificate Authority, client certificate, client key and TLS auth key to our .ovpn file:

1
2
3
echo '<ca>' >> /etc/openvpn/client/reheda-all.ovpn
cat /etc/openvpn/client/ca.crt >> /etc/openvpn/client/reheda-all.ovpn
echo '</ca>' >> /etc/openvpn/client/reheda-all.ovpn
1
2
3
echo '<cert>' >> /etc/openvpn/client/reheda-all.ovpn
cat /etc/openvpn/client/reheda1.crt >> /etc/openvpn/client/reheda-all.ovpn
echo '</cert>' >> /etc/openvpn/client/reheda-all.ovpn
1
2
3
echo '<key>' >> /etc/openvpn/client/reheda-all.ovpn
cat /etc/openvpn/client/reheda1.key >> /etc/openvpn/client/reheda-all.ovpn
echo '</key>' >> /etc/openvpn/client/reheda-all.ovpn
1
2
3
echo '<tls-auth>' >> /etc/openvpn/client/reheda-all.ovpn
cat /etc/openvpn/server/ta.key >> /etc/openvpn/client/reheda-all.ovpn
echo '</tls-auth>' >> /etc/openvpn/client/reheda-all.ovpn

So, our final version should look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
client
dev tun
proto tcp
remote vpn.reheda.pro 443
resolv-retry infinite
nobind
user nobody
group nogroup
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-CBC
verb 3
key-direction 1
<ca>
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
</ca>
<cert>
-----BEGIN CERTIFICATE-----
...
-----END RSA PRIVATE KEY-----
</key>
<tls-auth>
-----BEGIN OpenVPN Static key V1-----
...
-----END OpenVPN Static key V1-----
</tls-auth>

Step 7. Conclusion

To start using our VPN you can install Tunnelblick for Mac, or OpenVPN for Android, etc.

Use .ovpn file to configure your client app.

Step 8. Adjust Nginx config (optional)

In case you want to redirect all your HTTP traffic of vpn subdomain to the main page, we will step you through this.

Let’s create new Nginx server block configuration with the following content:

1
nano /etc/nginx/sites-available/vpn
1
2
3
4
5
6
7
8
# Vpn
server {
listen 80;
server_name vpn.reheda.pro;
# $scheme will get the http protocol
# and 301 is best practice for tablet, phone, desktop and seo
return 301 https://www.reheda.pro$request_uri;
}

Save and exit.

Create symlink for nginx:

1
sudo ln -s /etc/nginx/sites-available/vpn /etc/nginx/sites-enabled/vpn

Check for config for errors:

1
sudo nginx -t

And reload:

1
sudo systemctl reload nginx