Websockets, CentOS 6, and Apache 2.4

Problem: Apache 2.2 does not support websockets. This precludes using it as reverse proxy for NoVNC, and also for RShiny apps. This is a problem for us because we require access to Shiny apps over our standard Apache proxy. Read on for our solution!

Approach: Solve the problem using standard CentOS image with Apache 2.4 (which supports websockets). Prove we have a solution on a standalone VM, then we’ll migrate our existing Apache proxy.

Procedure:

  1. Create / basic configure the Guest VM within your virtualization environment (we use OpenStack). Launch a new instance based on vanilla CentOS VM instance, reboot at first login to force hostname to set completely, perform a yum update).
  2. Setup iptables:
    iptables -I INPUT 2 -p tcp -m state --state NEW -m tcp \
      -m multiport --dports 80,443 -m comment --comment "HTTP/HTTPS" -j ACCEPT

    Be sure to add the HTTP/HTTPS ports for your VM Security Group if running virtually. Then reload the firewall:

    service iptables reload
  3. Install Apache 2.4 for CentOS (no base support in CentOS yum repository):
    cd /etc/yum.repos.d
    wget http://repos.fedorapeople.org/repos/jkaluza/httpd24/epel-httpd24.repo

    Install the software and verify the version (note the explicit package names and non-standard location for installed binary):

    yum install httpd24.x86_64
    /opt/rh/httpd24/root/usr/sbin/httpd -version

    Set software to start automatically (note service name):

    chkconfig httpd24-httpd on
    service httpd24-httpd start
  4. Setup SSL. We’ll install the module, then disable the default SSL Web site since we’ll use our own for our test. This directly emulates what we do in production.
    First, install the module:

    yum install httpd24-mod_ssl.x86_64

    Then comment out the default SSL Web site:

    
    # /opt/rh/httpd24/root/etc/httpd/conf.d/ssl.conf
    [...comment out lines from...]
    <VirtualHost _default_:443>
    [...all the way to...]
    </VirtualHost>
  5. Setup system to emulate “standard” Apache file locations (remember that installing the special 2.4 Apache will not create these locations). This allows us to setup our configuration file exactly as we will use it in production:
    mkdir -p /etc/httpd /var/log/httpd
    chmod 700 /var/log/httpd
  6. Create the configuration file:
    cd /opt/rh/httpd24/root/etc/httpd/conf.d

    Set the configuration file contents:

    
    # /opt/rh/httpd24/root/etc/httpd/conf.d/wstunnel-test.conf
    LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
    
    <VirtualHost *:80>
      LogLevel debug
      ServerName shiny-demo.hlsdev.com
      RewriteEngine On
      RewriteRule (.*) https://shiny-demo.hlsdev.com/%{REQUEST_URI}
      CustomLog /var/log/httpd/demo.log combined
      ErrorLog /var/log/httpd/demo_error.log
    </VirtualHost>
    <VirtualHost *:443>
      LogLevel debug
      ServerName shiny-demo.example.com
      SSLEngine ON
      SSLCertificateFile /etc/httpd/example.com.crt
      SSLCertificateKeyFile /etc/httpd/example.com.key
      ProxyRequests Off
      ProxyPreserveHost Off
      <Proxy *>
        Order allow,deny
        Allow from all
      </Proxy>
    
      # websockets?
      ProxyPassMatch ^/(.*/__sockjs__/[0-9]+/.*) ws://mybackend.example.local:3838/$1
    
      ProxyPass / http://mybackend.example.local:3838/ max=1 disablereuse=on keepalive=on
      ProxyPassReverse / http://mybackend.example.local:3838/
      CustomLog /var/log/httpd/demo.log combined
      ErrorLog /var/log/httpd/demo_error.log
    </VirtualHost>

    In the above: the Websockets support is provided by two additional lines. The first line loads the Websockets Tunneling code (which is an add-on to standard ws-proxy module):

    LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so

    The second line performs the check for the “websocketized” application using the ProxyPassMatch command. The regular expression checks for __socksjs__ followed by an all-numeric identifier. If found, then the proxy will send the request to the ws:// destination, which automagically invokes the ws_tunnel code.

  7. Restart your web server:
    service httpd24-httpd restart
  8. Test your websocketized application. Notice that we enabled LogLevel debug above so we can see the Websockets tunnel at work in the error log file:
    
    [Wed Dec 03 12:17:15.558370 2014] [proxy_wstunnel:debug] [pid 2042] mod_proxy_wstunnel.c(331): [client 172.20.128.2:62126] AH02451: serving URL ws://mybackend.example.local:3838/sample-apps/rmd/__sockjs__/510/w2kfd1y0/websocket
    

    In the above snippet, the Websockets tunnel code kicked in, detected the sockets pattern we defined in the ProxyPassMatch and served the file to the Websockets backend server. Kewl!

That is all.

Team-oriented systems mentor with deep knowledge of numerous software methodologies, technologies, languages, and operating systems. Excited about turning emerging technology into working production-ready systems. Focused on moving software teams to a higher level of world-class application development. Specialties:Software analysis and development...Product management through the entire lifecycle...Discrete product integration specialist!

2 Comments on “Websockets, CentOS 6, and Apache 2.4

  1. Hello Andrew Bruce,

    Thank you very much for the post. Did you get a chance to try this solution in a mod_cluster clustered environment ?

Leave a Reply

Your email address will not be published. Required fields are marked *

*