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 127.0.0.1 4545
This means OpenVPN will forward all non-vpn traffic to the IP address: 127.0.0.1 (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:
server{ 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 127.0.0.1) 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 bind 0.0.0.0:443 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 127.0.0.1:4545 backend openvpn mode tcp timeout server 2h server openvpn-localhost 127.0.0.1:1193 #backend ssh # mode tcp # timeout server 2h # server ssh-localhost 127.0.0.1:22
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:
RUN=yes DAEMON_OPTS="--user sslh --transparent --listen 0.0.0.0:443 \ --ssl 127.0.0.1:4545 --openvpn 127.0.0.1:1194 \ --pidfile /var/run/sslh/sslh.pid"
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.
References
[1] OpenVPN: Sharing a port with a web server
[2] Write X-Forwarded-For field with share-port option
[3] HAProxy on wikipedia.org
[4] Running HTTPS, SSH and VPN on port 443
[5] SSLH – A SSL/SSH MULTIPLEXER