If the network environment you're operating in is restrictive then chances are port 1194 (standard openvpn port) will be blocked - which means that you wont' be able to connect to your openvpn server from that environment without making some changes on your end. One way to get around this is to change your openvpn port to something that will most likely NOT be blocked, like port 443 (https/ssl port). Doing so is trivial within your openvpn server.conf file. However, issues arise if you also use said server for other things, like a webserver - especially if you run multiple applications from said server (see Apache reverse-proxy SSL to multiple server applications for a standard setup running multiple web applications with Apache).
In this use case, we can actually use port 443 for both OpenVPN and our Apache2 reverse proxy. Now, we can't bind port 443 simultaneously to OpenVPN and Apache2 but we can "share" port 443 by fronting these with a SSL/OpenVPN multiplexer like SSLH.
How this works is we'll change our Apache reverse-proxy listening port to something else (like 4443), then bind port 443 to SSLH. SSLH will analyse traffic incoming to port 443, and if it's standard https then it transparently forwards this traffic to port 4443, and if it's OpenVPN traffic then it forwards it to our standard server-side OpenVPN port 1194.
SSLH also supports SSH traffic as well, so you could also route SSH traffic through port 443. This means having https, openvpn, and SSH traffic all going through a single port (443) on your server (although we won't cover adding SSH here - leave a comment if you have issues also adding SSH traffic to SSLH).
The steps outlined here assumes you've setup an Apache reverse-proxy in which you take care of SSL termination with the relevant SSL certs within said reverse-proxy which listens (is binded) to port 443. It also assumes that you've setup OpenVPN as outlined previously in this article and are using port 1194 for OpenVPN.
Although we are using Apache and OpenVPN in this guide, the same approach can be used to multiplex various other web applications to use/share a port.
Change OpenVPN to tcp-server mode
First let's make a small change to our OpenVPN by replacing
Note that with this change you'll also need to change your .ovpn client configuration to use
proto tcp-client and port 443 (e.g. the SSLH port instead of the internal OpenVPN port).
Change Apache SSL listening port and update any vhosts directives
Next, we're going to change our Apache SSL listening port to 4443 (you should check that this port is free - if not choose another valid arbitrary port number).
For this we'll need to change several files, the first should be changed to look like:
Listen 80 <IfModule ssl_module> Listen 4443 </IfModule> <IfModule mod_gnutls.c> Listen 4443 </IfModule>
We'll also need to change any and all site configuration
vhost directives from:
<VirtualHost *:443> ... </VirtualHost>
<VirtualHost *:4443> ... </VirtualHost>
Don't restart Apache2 just yet...
Install and configure sslh
Next install SSLH using distro's package manager. If you're running a Debian or Ubuntu Server you would do:
sudo apt install sslh
Select standalone mode when asked to select a mode.
Configuration of SSLH is done in a single file. Your
sslh configuration file should look like:
# Default options for sslh initscript # sourced by /etc/init.d/sslh # Disabled by default, to force yourself # to read the configuration: # - /usr/share/doc/sslh/README.Debian (quick start) # - /usr/share/doc/sslh/README, at "Configuration" section # - sslh(8) via "man sslh" for more configuration details. # Once configuration ready, you *must* set RUN to yes here # and try to start sslh (standalone mode only) 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 --transparent --listen <INTERNAL-IP-ADDRESS>:443 --ssl <INTERNAL-IP-ADDRESS>:4443 --openvpn <INTERNAL-IP-ADDRESS>:1194 --pidfile /var/run/sslh/sslh.pid"
where <INTERNAL-IP-ADDRESS> should be replaced with your server's internal IP address (e.g. 10.0.0.x or 192.168.1.x).
Note: it MUST be your internal ip address. SSLH transparent mode does NOT work if you use
transparent mode to work we also need to modify
iptables. To ease configuration I created a script which will set the requisite ip table rules. Note that these settings won't survive a reboot so once we're happy we're going to make these settings persistent.
Copy the following to a file in your path (I suggest
/usr/local/sbin), make it executable, and execute with sudo:
cd /usr/local/sbin sudo vim sslh-transparent
and copy/paste the following:
#!/bin/bash iptables -t mangle -N SSLH iptables -t mangle -A OUTPUT --protocol tcp --out-interface enp0s25 --sport 4443 --jump SSLH iptables -t mangle -A OUTPUT --protocol tcp --out-interface enp0s25 --sport 1194 --jump SSLH iptables -t mangle -A SSLH --jump MARK --set-mark 0x1 iptables -t mangle -A SSLH --jump ACCEPT ip rule add fwmark 0x1 lookup 100 ip route add local 0.0.0.0/0 dev lo table 100 ip6tables -t mangle -N SSLH ip6tables -t mangle -A OUTPUT --protocol tcp --out-interface enp0s25 --sport 4443 --jump SSLH ip6tables -t mangle -A OUTPUT --protocol tcp --out-interface enp0s25 --sport 1194 --jump SSLH ip6tables -t mangle -A SSLH --jump MARK --set-mark 0x1 ip6tables -t mangle -A SSLH --jump ACCEPT ip -6 rule add fwmark 0x1 lookup 100 ip -6 route add local ::/0 dev lo table 100
NOTE: you'll need to replace
enp0s25 with the main network interface of your server.
Make it executable:
sudo chmod +x /usr/local/sbin/sslh-transparent
You should now be able to set the iptables by executing our created script.
Making the iptable settings needed for SSLH persistent
The iptables set from our script won't survive a reboot. Let's make it persistent (note I assume a
systemd enabled distro here):
Create a simple systemd service which will execute our script on boot (after our network interfaces are online):
sudo vim /etc/systemd/system/sslh-transparent.service
and copy/paste the following:
[Unit] Description=sslh transparent (see /usr/local/sbin/ssl-transparent) Wants=network-online.target After=network-online.target [Service] Type=simple ExecStart=/usr/local/sbin/sslh-transparent [Install] WantedBy=multi-user.target
Once saved, enable SSLH persistence on our system:
sudo systemctl daemon-reload sudo systemctl start sslh-transparent sudo systemctl enable sslh-transparent
Now these rules should have been applied to our system and will also be applied on system restart.
Restart Apache, start sslh, and test...
Right, it's time to test the setup. To do so we need to restart Apache, start SSLH:
sudo systemctl restart apache2 sudo systemctl start sslh
If all went well you should be able to still access your webserver AND connect to OpenVPN on port 443.
We'll finalise the configuration (once you've tested it) by enabling sslh (so it starts on boot) and by making the iptable rules (above) persistent.
To make SSLH start on boot:
sudo systemctl enable sslh