Using Apache as an SSL Gateway to x11vnc servers inside a firewall (holy grail: 443 only):

Please see the main notes on the Apache SSL VNC Portal for background and details.

This page contains notes on using a helper script connect_switch to redirect incoming port 443 (the default https:// port) connections to either apache listening on localhost:443 for normal HTTPS tasks or to redirect VNC CONNECT requests directly to the workstations running x11vnc (or other VNC server.) It can also redirect to other services besides VNC, for example SSH.

The idea is you just want to open a single, https (i.e. SSL encrypted) port to the internet and you want it to serve as both a regular https server and also a VNC SSL tunnel (or for any other service, SSH, etc.) Users often want that port to be 443, since sometimes that (and 80) is the only external port their company firewall lets them connect to. But you could choose any port if you desired some obscurity, etc.

It doesn't seem possible to do this entirely inside the apache mod_ssl framework. Please show us how if you know! (It is, however, possible without SSL/mod_ssl: just use the ProxyRequests and AllowCONNECT parameters; see also this apache patch.)

Although inelegant, one can have a helper program listening in front of apache to redirect the two different types of requests.

                                                                            --> localhost:443/apache-mod_ssl
                                                                          /
web-or-vnc-or-ssh-client ==>  internet ==> your-ip-addr:443/connect_switch  
                                                                          \
                                                                            --> vnchost1:5915/x11vnc
                                                                           |
                                                                            --> vnchost2:5915/x11vnc
                                                                           |
                                                                            --> ...
                                                                           |
                                                                            --> ssh-host1:22/sshd
                                                                           |
                                                                            --> ...
So basically you run connect_switch listening on port 443 of your IP address interface. Then you configure apache mod_ssl to listen only on localhost:443 by putting this in ssl.conf:
   Listen 127.0.0.1:443
(or run apache/mod_ssl on a different port.) Incoming connections to port 443 first get intercepted by connect_switch. If it notices the "CONNECT host:port" request, it checks if host:port is in its allowed list, and if so makes a direct connection to the workstation and forwards data to and from the client, by-passing apache completely. If it is not in the allowed list, the connection is immediately dropped.

If it does not detect "CONNECT" it instead forwards the connection to apache listening on localhost:443 (or where ever you have the apache+mod_ssl running/listening) for normal WWW processing. Note that this default redirection need not be to HTTP/HTTPS, it could be to any service you want.


connect_switch configuration:

If you look at the top portion of connect_switch you will see how to configure it for different hosts, IP addresses, and VNC servers. There are also some CONNECT_SWITCH* environment variables you can set to avoid editing the script.

####################################################################
# Set CONNECT_SWITCH_LOOP=1 to have this script create an outer loop
# restarting itself if it ever exits.  Set CONNECT_SWITCH_LOOP=BG to
# do this in the background as a daemon.

...

############################################################################
# The defaults for hosts and ports (you can override them below if needed):
#
# Look below for these environment variables that let you set the various
# parameters without needing to edit this script:
#
#       CONNECT_SWITCH_LISTEN
#       CONNECT_SWITCH_HTTPD
#       CONNECT_SWITCH_ALLOWED
#       CONNECT_SWITCH_ALLOW_FILE
#       CONNECT_SWITCH_VERBOSE
#       CONNECT_SWITCH_APPLY_VNC_OFFSET
#       CONNECT_SWITCH_VNC_OFFSET
#       CONNECT_SWITCH_LISTEN_IPV6
#       CONNECT_SWITCH_BUFSIZE
#       CONNECT_SWITCH_LOGFILE
#       CONNECT_SWITCH_PIDFILE
#
# You can also set these on the cmdline:
#      connect_switch CONNECT_SWITCH_LISTEN=X CONNECT_SWITCH_ALLOW_FILE=Y ...
#

# By default we will use hostname and assume it resolves:
#
my $hostname = `hostname`;
chomp $hostname;

my $listen_host = $hostname;
my $listen_port = 443;

# Let user override listening situation, e.g. multihomed:
#
if (exists $ENV{CONNECT_SWITCH_LISTEN}) {
        #
        # E.g. CONNECT_SWITCH_LISTEN=192.168.0.32:443
        #
        ($listen_host, $listen_port) = split(/:/, $ENV{CONNECT_SWITCH_LISTEN});
}

my $httpd_host = 'localhost';
my $httpd_port = 443;

if (exists $ENV{CONNECT_SWITCH_HTTPD}) {
        #
        # E.g. CONNECT_SWITCH_HTTPD=127.0.0.1:443
        #
        ($httpd_host, $httpd_port) = split(/:/, $ENV{CONNECT_SWITCH_HTTPD});
}

my $bufsize = 8192;
if (exists $ENV{CONNECT_SWITCH_BUFSIZE}) {
        #
        # E.g. CONNECT_SWITCH_BUFSIZE=32768
        #
        $bufsize = $ENV{CONNECT_SWITCH_BUFSIZE};
}


############################################################################
# You can/should override the host/port settings here:
#
#$listen_host = '23.45.67.89';          # set to your interface IP number.
#$listen_port = 555;                    # and/or nonstandard port.
#$httpd_host  = 'somehost';             # maybe you redir https to another machine.
#$httpd_port  = 666;                    # and/or nonstandard port.

# You must set the allowed host:port CONNECT redirection list.
# Only these host:port pairs will be redirected to.
# Port ranges are allowed too:  host:5900-5930.
# If there is one entry named ALL all connections are allow.
# You must supply something, default is deny.
#
my @allowed = qw(
        machine1:5915
        machine2:5900
);

if (exists $ENV{CONNECT_SWITCH_ALLOWED}) {
        #
        # E.g. CONNECT_SWITCH_ALLOWED=machine1:5915,machine2:5900
        #
        @allowed = split(/,/, $ENV{CONNECT_SWITCH_ALLOWED});
}

# Or you could also use an external "allow file".
# They get added to the @allowed list.
# The file is re-read for each new connection.
#
# Format of $allow_file:
#
#     host1 vncdisp
#     host2 vncdisp
#
# where, e.g. vncdisp = 15 => port 5915, say
#
#     joesbox  15 
#     fredsbox 15 
#     rupert    1 

# For examply, mine is:
#
my $allow_file = '/dist/apache/2.0/conf/vnc.hosts';
$allow_file = '';

if (exists $ENV{CONNECT_SWITCH_ALLOW_FILE}) {
        # E.g. CONNECT_SWITCH_ALLOW_FILE=/usr/local/etc/allow.txt
        $allow_file = $ENV{CONNECT_SWITCH_ALLOW_FILE};
}

# Set to 1 to re-map to vnc port, e.g. 'hostname 15' to 'hostname 5915'
# i.e. assume a port 0 <= port < 200 is actually a VNC display
# and add 5900 to it.  Set to 0 to not do the mapping.
# Note that negative ports, e.g. 'joesbox -22' go directly to -port.
#
my $apply_vnc_offset = 1;
my $vnc_offset = 5900;

if (exists $ENV{CONNECT_SWITCH_APPLY_VNC_OFFSET}) {
        #
        # E.g. CONNECT_SWITCH_APPLY_VNC_OFFSET=0
        #
        $apply_vnc_offset = $ENV{CONNECT_SWITCH_APPLY_VNC_OFFSET};
}
if (exists $ENV{CONNECT_SWITCH_VNC_OFFSET}) {
        #
        # E.g. CONNECT_SWITCH_VNC_OFFSET=6000
        #
        $vnc_offset = $ENV{CONNECT_SWITCH_VNC_OFFSET};
}

# Set to 1 or higher for more info output:
#
my $verbose = 0;

if (exists $ENV{CONNECT_SWITCH_VERBOSE}) {
        #
        # E.g. CONNECT_SWITCH_VERBOSE=1
        #
        $verbose = $ENV{CONNECT_SWITCH_VERBOSE};
}


...

This tool possibly has other applications outside of VNC SSL tunnelling for which it was created. For example, one user uses it to access both his SSH server and Apache SSL server from inside a company firewall using a web proxy.

To run it, download it and then type "chmod 755 ./connect_switch" Edit the line in Apache file ssl.conf to be Listen 127.0.0.1:443

If you have apache listen internally on a port other than 443 you don't need to specify the 127.0.0.1 interface in ssl.conf; simply redirect to where ever it is.

If the initial access to the redirected service is through a web URL (e.g. you are using the Java VNC Viewer applet), you also need to put in the RewriteRules for ssl.conf in the normal SSL VNC portal page. You do not need to change httpd.conf since this is pure SSL/https. Note that the RewriteRules for /vnc443 are the only ones we need. Actually, you don't need to do this if you put all of the parameters CONNECT= PORT= on the URL line in the browser instead. You also do not need to do this if you access the service directly (e.g. via SSVNC/ss_vncviewer to VNC server or SSH client to SSH server; see the examples below.)

Then restart apache, often it is:

  apachectl stop
  apachectl startssl
To have it listen on port 443 you need to run it as root. Run it like this:
  ./connect_switch
Or here is a script that sets the env. vars. instead of requiring editing the script:
  #!/bin/sh
  export CONNECT_SWITCH_LISTEN=192.168.0.25:443
  export CONNECT_SWITCH_HTTPD=127.0.0.1:443
  export CONNECT_SWITCH_ALLOWED=rupert:5901,ottoline:5915
  ./connect_switch
One can also put the VAR=VAL env.vars on the cmdline if desired.

To run connect_switch as a daemon running in the background and restarting itself if necessary, the env. vars. "CONNECT_SWITCH_LOOP=BG", "CONNECT_SWITCH_LOGFILE=...", and "CONNECT_SWITCH_PIDFILE=..." may come in handy. Read the top part of the connect_switch script for more information about configuration.

Then on a remote host (outside your firewall probably) enter a URL like this:

   https://www.gateway.east/vnc443/rupert
(with the names changed to your situation of course). You can rename the prefix "/vnc443" to something shorter, easier to remember in the config file if you like.

To access it directly (no web browser URL) with a VNC viewer:

  ss_vncviewer -proxy www.gateway.east:443 ottoline:15
or use SSVNC and set the proxy to "www.gateway.east:443".


Single port SSH gateway:

To use it as an SSH gateway (set CONNECT_SWITCH_APPLY_VNC_OFFSET=0 and set CONNECT_SWITCH_ALLOWED to the lists of desired ssh hosts and port 22, e.g. CONNECT_SWITCH_ALLOWED=rupert:22,ottoline:22) and then run this ssh command to access the internal SSH server:

  ssh -o ProxyCommand='/usr/bin/nc -X connect -x www.gateway.east:443 %h %p' wally@rupert
To do both VNC and SSH redirections at the same time use the above SSH example (CONNECT_SWITCH_APPLY_VNC_OFFSET=0) and specify allowed VNC hosts with the full port, i.e. "machine:5915" and not "machine:15".

To terminate connect_switch type Ctrl-C in the shell you started it in (or use kill(1) if you have it running in the background.) Be sure to change the apache parameter back to Listen 443 if you do not want to use it anymore. For a more robust setup you can have a cron job check if it is still running and restart it if it isn't; or have a wrapper script do this, etc. Note that the "CONNECT_SWITCH_LOOP" mode is pretty robust in keeping the service going for long periods of time.