James Thornton logo
James Thornton
Google
Web jamesthornton.com
Internet Business Consultant
Home Blog Bio Projects Contact
JamesThornton.com -\> Writing -\> OpenACS/Pound Configuration

Enabling OpenACS Subsites to Use SSL Through a Pound Proxy: HOWTO

Summary: Enable SSL for OpenACS 5.x subsites via a Pound proxy.

OpenACS Subsites

OpenACS enables you to create subsites under the main site so that you can run multiple websites from the same code and database. For example:

  • Main Site: http://www.mainsite.com/
  • Subsite: http://www.mainsite.com/my-subsite/

With the OpenACS host-node-map utility, you can map any hostname to a subsite, hiding its relation to the main site. For example, you could map http://www.my-subsite.com/ to http://www.mainsite.com/my-subsite/, where www.mainsite.com and www.my-subsite.com point to the same IP.

One SSL Key Per Server Process

However, if you need SSL encryption for mapped subsites, you will encounter a problem since each subsite will need its own certificate, and you can only have one SSL key per server instance. Scott Goodwin, author of nsopenssl, explains:

When a client connects, the first thing that happens is the SSL handshake. Your server doesn't even know what URL, and hence, which subsite the connection is destined for until after the SSL handshake is done.

The only way to do what you want is to add multiple IP addresses to your ethernet card and assign each address to a different subsite. This way you can attach a cert on a subsite basis. nsd listens on a different address for each subsite and so knows which cert to use.

Pound Proxy Server

If you don't want the overhead of running multiple AOLserver processes, you can use a Pound proxy server to handle the https handshake and forward requests to a single AOLserver process. Configure the hostnames for each subsite to point its respective IP address that Pound is running on, and configure Pound to forward requests to AOLserver.

Sample Pound Configuration File

# Global Directives

# The IPs Pound is listening on (one IP per subsite)
ListenHTTP      1.2.3.4,80
ListenHTTPS     1.2.3.4,443 /web/mainsite/etc/certs/subsite1.pem

ListenHTTP      1.2.3.5,80
ListenHTTPS     1.2.3.5,443 /web/mainsite/etc/certs/subsite2.pem

ListenHTTP      1.2.3.6,80
ListenHTTPS     1.2.3.6,443 /web/mainsite/etc/certs/subsite3.pem

# Remove the X-SSL-Request header from incoming connections
# to prevent hackers from spoofing it
HeadRemove "X-SSL-Request"

# Add an extra header to tell AOLserver that 
#the external connection is secure
HTTPSHeaders 0 "X-SSL-Request: 1"

#CAlist /web/james/etc/certs/test-keyfile.pem
User 		nsadmin
Group 		web
Alive		30
Server		0
Client		10
RewriteRedirect	1
CheckURL	0
LogLevel        2


# Group Directives
# Communication between Pound and AOLserver is over HTTP, not HTTPS

UrlGroup ".*"
HeadRequire Host ".*subsite1.com.*"
# The IP AOLserver is running on
BackEnd 	1.2.3.7,80,1
EndGroup

UrlGroup ".*"
HeadRequire Host ".*subsite2.com.*"
# The IP AOLserver is running on
BackEnd 	1.2.3.7,80,1
EndGroup

UrlGroup ".*"
HeadRequire Host ".*subsite3.com.*"
# The IP AOLserver is running on
BackEnd 	1.2.3.7,80,1
EndGroup


OpenACS Modifications

The communication between Pound and AOLserver is over HTTP, even if the connection between the client and Pound is over HTTPS, so you will need to modify the OpenACS request processor to make subsites play nicely with a Pound proxy server handling the SSL connections. There are three modifications that I know of:

  1. Modify security::secure_conn_p: In the above sample Pound configuration file, it tells Pound to add an extra X-SSL-Request header with a value of 1 if the external connection is secure so we need to tell OpenACS to check for this header to determine if the external connection is secure.

    Change...

    return [string match "https:*" [util_current_location]]
    ...to...
    if {[string equal [ns_set get [ns_conn headers] "X-SSL-Request"] 1]} {
        return 1
    } else {
        return [string match "https:*" [util_current_location]]
    }
    

  2. Modify get_secure_location: Since normally subsites cannot handle secure connections due to the limitations with SSL discussed earlier, OpenACS redirects all secure connections to the main site so we need to modify OpenACS so that it doesn't automatically redirect to https://mainsite.com/ for secure connections.

    Change...

    set secure_location [ad_conn location]
    ...to...
    set secure_location $current_location

  3. Modify util_current_location: Pound passes the Host header exactly as it is sent by the client browser. The Host header contains the hostname and the port. If Pound is listening on the default port for HTTPS and the external connection is secure, the port in the Host header will be 443. But, since all communication between Pound and OpenACS is over HTTP, the AOLserver port will normally be 80. We need to tell OpenACS to adjust the port number it uses for secure connections handled by Pound.

    Change....

    if { [empty_string_p $Host] } {
        # No Host header, return protocol from driver, hostname from [ad_conn location], and port from driver
        set hostname $location_hostname
    } else {
        set hostname $Host_hostname
        if { ![empty_string_p $Host_port] } {
            set port $Host_port
        }
    }
    
    ...to...
    if { [empty_string_p $Host] } {
        # No Host header, return protocol from driver, hostname from [ad_conn location], and port from driver
        set hostname $location_hostname
    } else {
        set hostname $Host_hostname
        if { ![empty_string_p $Host_port] } {
            if {!([string equal [ns_set get [ns_conn headers] "X-SSL-Request"] 1] && 
                  [string equal $Host_port $default_port(https)])} {
    	    set port $Host_port
            }
       }
    }
    


Follow espeed on Twitter