Getting OpenVPN and Nginx to share port 443

If you are running an VPN-server to circumvent censorship, or browse securely while connected to a public wifi network, you will have at some point to consider server VPN on port 443, the standard port for HTTPS, which is very unlikely to be blocked by ISPs.

But what if you wanted to server a secure web page on same server? That will mean that the HTTP-server will need to listen to port 443, the same port that the VPN-server is listening to. Something the operating system of the server will most probably not allow.

There are solutions for this issue. I discuss different approaches for the OpenVPN, and Nginx on Ubuntu 16.04. The solutions might be similar or valid for other VPN and HTTP servers or Operating Systems.

OpenVPN share-port

In this approach, OpenVPN listens to all traffic coming to port 443, and forwards all non-vpn traffic to Nginx which will be listening to a different port.

To implement this approach, add the following line to the OpenVPN server configuration file [1]:

port-share x.x.x.x n

replace the x.x.x.x with the IP address of the Nginx server, and the n with the port number Nginx is setup to listen to. For example:

port-share 4545

This means OpenVPN will forward all non-vpn traffic to the IP address: (which is actually localhost) and the port 4545 that Nginx is setup to listening to.

In the Nginx enabled sites configuration file make sure Nginx is listening to the same port n, 4545 in our example:

listen 4545 ssl http2 default_server;
listen [::]:4545 ssl http2 default_server;

And actually that would do the work.

Using a reverse-proxy

In the first approach requests reaching the Nginx server appears to be coming from the IP address of the OpenVPN server (mostly instead of the original IP address of the request [2]. That might not be the desired behaviour. Which means that using fail2ban to limit password-guessing attackers on the website login page for example will not work.

To get around this limitation, and to have much more control on the traffic it is possible to use a reverse-proxy in transparent proxy mode. a reverse-proxy is a software that listens to a specific port then forward the traffic to other ip-addresses/ports depending on the configuration of the reverse-proxy.

In this example we will use HAProxy [3] an open-source, and free reverse-proxy available on many operating systems including Ubuntu 16.04, but we will not go through the transparent proxy mode.

Installing HAProxy on Ubuntu 16.04 is straight forward:

$ sudo apt install haproxy

After the installation has concluded, haproxy starts as a service, one can check if the software has been installed and if the service has been launched correctly:

$ haproxy -vv

should return the version of the installed haproxy and additional build information and capabilities

To configure haproxy, edit the file /etc/haproxy/haproxy.cfg and make sure to add the following sections from [4]:

frontend ssl
mode tcp
tcp-request inspect-delay 5s
tcp-request content accept if HTTP
# use_backend ssh if { payload(0,7) -m bin 5353482d322e30 }
use_backend main-ssl if { req.ssl_hello_type 1 }
default_backend openvpn

backend main-ssl
mode tcp
server main-ssl

backend openvpn
mode tcp
timeout server 2h
server openvpn-localhost

#backend ssh
# mode tcp
# timeout server 2h
# server ssh-localhost

store the file and start the daemon

$ systemctrl start haproxy

Now you have a running reverse proxy service https, openvpn, and optionally ssh if you uncomment the ssh specific configuration instructions, all on the same 443 port.

Using a protocol Demultiplexer

It is also possible to allow different protocols such as HTTPS and VPN to share a port using a protocol demultiplexer such as sslh [5].

To install sslh on Ubuntu 16.04 use aptitude:

$ sudo apt intall sslh

At the end of the installation procedure you will be asked if you want to run sslh as part of inetd or as “standalone”; Let’s chose “standalone”.

To run correctly sslh must be configured. The configuration file is located in /etc/defaults/sslh. Make the following changes to the file:

DAEMON_OPTS="--user sslh --transparent --listen \
--ssl --openvpn \
--pidfile /var/run/sslh/"

Make sure that openvpn server listens to port 1194 in the configuration file /etc/openvpn/server.conf, and that nginx listens to the standard 443 port in the configuration file in the /etc/nginx/sites-enabled/ folder.

start the service:

$ systemctrl start sslh

And that’s it. Now you have a running protocol demultiplexer serving both https and openvpn on port 443.


[1] OpenVPN: Sharing a port with a web server
[2] Write X-Forwarded-For field with share-port option
[3] HAProxy on
[4] Running HTTPS, SSH and VPN on port 443

Leave a Reply